要破解类似这样的验证码:
拆分后结果:
然后去匹配,得到结果。
拿到图片后,首先把图片中我们需要的部分截取出来。
具体的做法是,创建一个的和图片像素相同的一个代表权重的二维数组,遍历图片的每个像素点,如果接近白色,就标记为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 }
拆分好的图片后,把拆分好的图片再次计算它的权重二维数据,加载之前准备好的"已知值的图片",也计算权重数组。
然后对比两个二维数组,如果大部分都匹配,就确定了值。
如果没有找到匹配的,就把图片保存下来,人工识别后放入已知值的图片组。
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 }
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 }