IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    java识别简单的验证码 - 小小已然

    小小已然发表于 2015-09-12 15:43:00
    love 0

    1.老规矩,先上图

    要破解类似这样的验证码:

     

    拆分后结果:

    然后去匹配,得到结果。

    2.拆分图片

    拿到图片后,首先把图片中我们需要的部分截取出来。

    具体的做法是,创建一个的和图片像素相同的一个代表权重的二维数组,遍历图片的每个像素点,如果接近白色,就标记为1,否则标记为0;

    然后遍历这个二维数据,如果一个竖排都1,说明是空白列,直到第一次遇到不全为1一列,记住列的下标作为起始值,再次遇到全为1的,记住下标作为结束值,然后从起始列到结束列截取图片,依次类推。

    1   //分割图片
    2 private java.util.List<BufferedImage> splitImage(BufferedImage originImg)
    3 throws Exception {
    4 java.util.List<BufferedImage> subImgList = new ArrayList<>();
    5 int height = originImg.getHeight();
    6 int[][] weight = getImgWeight(originImg);
    7 int start = 0;
    8 int end = 0;
    9 boolean isStartReady = false;
    10 boolean isEndReady = false;
    11 for (int i = 0; i < weight.length; i++) {
    12 boolean isBlank = isBlankArr(weight[i]);
    13 if (isBlank) {
    14 if (isStartReady && !isEndReady) {
    15 end = i;
    16 isEndReady = true;
    17 }
    18 } else {
    19 if (!isStartReady) {
    20 start = i;
    21 isStartReady = true;
    22 }
    23 }
    24 if (isStartReady && isEndReady) {
    25 subImgList.add(originImg.getSubimage(start, 0, end - start, height));
    26 isStartReady = false;
    27 isEndReady = false;
    28 }
    29 }
    30 return subImgList;
    31 }
    32
    33 //颜色是否为空白
    34 private boolean isBlank(int colorInt) {
    35 Color color = new Color(colorInt);
    36 return color.getRed() + color.getGreen() + color.getBlue() > 600;
    37 }
    38
    39 //数组是不是全空白
    40 private boolean isBlankArr(int[] arr) {
    41 boolean isBlank = true;
    42 for (int value : arr) {
    43 if (value == 0) {
    44 isBlank = false;
    45 break;
    46 }
    47 }
    48 return isBlank;
    49 }
    50
    51 //获取图片权重数据
    52 private int[][] getImgWeight(BufferedImage img) {
    53 int width = img.getWidth();
    54 int height = img.getHeight();
    55 int[][] weight = new int[width][height];
    56 for (int x = 0; x < width; ++x) {
    57 for (int y = 0; y < height; ++y) {
    58 if (isBlank(img.getRGB(x, y))) {
    59 weight[x][y] = 1;
    60 }
    61 }
    62 }
    63 return weight;
    64 }

     

     

    3.与拆分好的图片进行比较

    拆分好的图片后,把拆分好的图片再次计算它的权重二维数据,加载之前准备好的"已知值的图片",也计算权重数组。

    然后对比两个二维数组,如果大部分都匹配,就确定了值。

    如果没有找到匹配的,就把图片保存下来,人工识别后放入已知值的图片组。

    1   //分析识别
    2 private String realize(java.util.List<BufferedImage> imgList) {
    3 String resultStr = "";
    4 for (BufferedImage img : imgList) {
    5 String key = getKey(Global.trainedMap, img);
    6 if (key == null) {
    7 String noTrainedKey = getKey(Global.noTrainedMap, img);
    8 if(noTrainedKey == null){
    9 try {
    10 ImageIO.write(img, "JPG", new File(Global.LIB_NO + File.separator + UUID.randomUUID() + ".jpg"));
    11 } catch (IOException e) {
    12 e.printStackTrace();
    13 }
    14 }
    15 } else {
    16 resultStr += key;
    17 }
    18 }
    19 return resultStr;
    20 }
    21
    22 //获取已知值
    23 private String getKey(Map<String, BufferedImage> map, BufferedImage img){
    24 String resultStr = null;
    25 Set<Map.Entry<String, BufferedImage>> entrySet = map.entrySet();
    26 for (Map.Entry<String, BufferedImage> one : entrySet) {
    27 if (isSimilarity(img, one.getValue())) {
    28 resultStr = one.getKey();
    29 break;
    30 }
    31 }
    32 return resultStr;
    33 }
    34
    35 //是否相似
    36 private boolean isSimilarity(BufferedImage imageA, BufferedImage imageB) {
    37 int widthA = imageA.getWidth();
    38 int widthB = imageB.getWidth();
    39 int heightA = imageA.getHeight();
    40 int heightB = imageB.getHeight();
    41 if (widthA != widthB || heightA != heightB) {
    42 return false;
    43 } else {
    44 int[][] weightA = getImgWeight(imageA);
    45 int[][] weightB = getImgWeight(imageB);
    46 int count = 0;
    47 for (int i = 0; i < widthA; i++) {
    48 for (int j = 0; j < heightB; j++) {
    49 if (weightA[i][j] != weightB[i][j]) {
    50 count++;
    51 }
    52 }
    53 }
    54 if ((double) count / (widthA * widthB) > (1 - Global.SIMILARITY)) {
    55 return false;
    56 } else {
    57 return true;
    58 }
    59 }
    60 }

     

    4.完整代码

    1 import javax.imageio.ImageIO;
    2 import java.awt.image.BufferedImage;
    3 import java.io.File;
    4 import java.io.IOException;
    5 import java.util.HashMap;
    6 import java.util.Map;
    7
    8 public class Global {
    9 public static final String LIB_PATH = "C:/lib";
    10 public static final String LIB_NO = "C:/no";
    11 public static final double SIMILARITY = 0.9;
    12 public static Map<String, BufferedImage> trainedMap;
    13 public static Map<String, BufferedImage> noTrainedMap = new HashMap<>();
    14
    15 static {
    16 trainedMap = getMap(LIB_PATH);
    17 noTrainedMap = getMap(LIB_NO);
    18 }
    19
    20 private static Map<String, BufferedImage> getMap(String path) {
    21 Map<String, BufferedImage> map = new HashMap<>();
    22 File parentFile = new File(path);
    23 for (String filePath : parentFile.list()) {
    24 File file = new File(path + File.separator + filePath);
    25 String fileName = file.getName();
    26 String key = fileName.substring(0,fileName.indexOf(".")).trim();
    27 try {
    28 map.put(key, ImageIO.read(file));
    29 } catch (IOException e) {
    30 e.printStackTrace();
    31 }
    32 }
    33 return map;
    34 }
    35 }
    36 import javax.imageio.ImageIO;
    37 import java.awt.*;
    38 import java.awt.image.BufferedImage;
    39 import java.io.File;
    40 import java.io.IOException;
    41 import java.util.*;
    42
    43 /**
    44 * 识别验证码
    45 */
    46 public class ImageProcess {
    47 private String imgPath;
    48
    49 public ImageProcess(String imgPath) {
    50 this.imgPath = imgPath;
    51 }
    52
    53 public String getResult() {
    54 java.util.List<BufferedImage> imgList = null;
    55 try {
    56 BufferedImage img = ImageIO.read(new File(imgPath));
    57 imgList = splitImage(img);
    58 } catch (IOException e) {
    59 e.printStackTrace();
    60 } catch (Exception e) {
    61 e.printStackTrace();
    62 }
    63 return realize(imgList);
    64 }
    65
    66 //分析识别
    67 private String realize(java.util.List<BufferedImage> imgList) {
    68 String resultStr = "";
    69 for (BufferedImage img : imgList) {
    70 String key = getKey(Global.trainedMap, img);
    71 if (key == null) {
    72 String noTrainedKey = getKey(Global.noTrainedMap, img);
    73 if(noTrainedKey == null){
    74 try {
    75 ImageIO.write(img, "JPG", new File(Global.LIB_NO + File.separator + UUID.randomUUID() + ".jpg"));
    76 } catch (IOException e) {
    77 e.printStackTrace();
    78 }
    79 }
    80 } else {
    81 resultStr += key;
    82 }
    83 }
    84 return resultStr;
    85 }
    86
    87 //获取已知值
    88 private String getKey(Map<String, BufferedImage> map, BufferedImage img){
    89 String resultStr = null;
    90 Set<Map.Entry<String, BufferedImage>> entrySet = map.entrySet();
    91 for (Map.Entry<String, BufferedImage> one : entrySet) {
    92 if (isSimilarity(img, one.getValue())) {
    93 resultStr = one.getKey();
    94 break;
    95 }
    96 }
    97 return resultStr;
    98 }
    99
    100 //是否相似
    101 private boolean isSimilarity(BufferedImage imageA, BufferedImage imageB) {
    102 int widthA = imageA.getWidth();
    103 int widthB = imageB.getWidth();
    104 int heightA = imageA.getHeight();
    105 int heightB = imageB.getHeight();
    106 if (widthA != widthB || heightA != heightB) {
    107 return false;
    108 } else {
    109 int[][] weightA = getImgWeight(imageA);
    110 int[][] weightB = getImgWeight(imageB);
    111 int count = 0;
    112 for (int i = 0; i < widthA; i++) {
    113 for (int j = 0; j < heightB; j++) {
    114 if (weightA[i][j] != weightB[i][j]) {
    115 count++;
    116 }
    117 }
    118 }
    119 if ((double) count / (widthA * widthB) > (1 - Global.SIMILARITY)) {
    120 return false;
    121 } else {
    122 return true;
    123 }
    124 }
    125 }
    126
    127 //分割图片
    128 private java.util.List<BufferedImage> splitImage(BufferedImage originImg)
    129 throws Exception {
    130 java.util.List<BufferedImage> subImgList = new ArrayList<>();
    131 int height = originImg.getHeight();
    132 int[][] weight = getImgWeight(originImg);
    133 int start = 0;
    134 int end = 0;
    135 boolean isStartReady = false;
    136 boolean isEndReady = false;
    137 for (int i = 0; i < weight.length; i++) {
    138 boolean isBlank = isBlankArr(weight[i]);
    139 if (isBlank) {
    140 if (isStartReady && !isEndReady) {
    141 end = i;
    142 isEndReady = true;
    143 }
    144 } else {
    145 if (!isStartReady) {
    146 start = i;
    147 isStartReady = true;
    148 }
    149 }
    150 if (isStartReady && isEndReady) {
    151 subImgList.add(originImg.getSubimage(start, 0, end - start, height));
    152 isStartReady = false;
    153 isEndReady = false;
    154 }
    155 }
    156 return subImgList;
    157 }
    158
    159 //颜色是否为空白
    160 private boolean isBlank(int colorInt) {
    161 Color color = new Color(colorInt);
    162 return color.getRed() + color.getGreen() + color.getBlue() > 600;
    163 }
    164
    165 //数组是不是全空白
    166 private boolean isBlankArr(int[] arr) {
    167 boolean isBlank = true;
    168 for (int value : arr) {
    169 if (value == 0) {
    170 isBlank = false;
    171 break;
    172 }
    173 }
    174 return isBlank;
    175 }
    176
    177 //获取图片权重数据
    178 private int[][] getImgWeight(BufferedImage img) {
    179 int width = img.getWidth();
    180 int height = img.getHeight();
    181 int[][] weight = new int[width][height];
    182 for (int x = 0; x < width; ++x) {
    183 for (int y = 0; y < height; ++y) {
    184 if (isBlank(img.getRGB(x, y))) {
    185 weight[x][y] = 1;
    186 }
    187 }
    188 }
    189 return weight;
    190 }
    191
    192
    193 public static void main(String[] args) throws Exception {
    194 String result = new ImageProcess("C:/login.jpg").getResult();
    195 System.out.println(result);
    196
    197 }
    198 }

     


    本文链接:java识别简单的验证码,转载请注明。



沪ICP备19023445号-2号
友情链接