1.老规矩,先上图
要破解类似这样的验证码:

拆分后结果:

然后去匹配,得到结果。
2.拆分图片
拿到图片后,首先把图片中我们需要的部分截取出来。
具体的做法是,创建一个的和图片像素相同的一个代表权重的二维数组,遍历图片的每个像素点,如果接近白色,就标记为1,否则标记为0;
然后遍历这个二维数据,如果一个竖排都1,说明是空白列,直到第一次遇到不全为1一列,记住列的下标作为起始值,再次遇到全为1的,记住下标作为结束值,然后从起始列到结束列截取图片,依次类推。
?1 //分割图片
?2? ? private java.util.List splitImage(BufferedImage originImg)
?3? ? ? ? ? ? throws Exception {
?4? ? ? ? java.util.List 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 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 map, BufferedImage img){
24? ? ? ? String resultStr = null;
25? ? ? ? Set> entrySet = map.entrySet();
26? ? ? ? for (Map.Entry 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? ? ? ? ? ? ret