前言
我們又來破解驗證碼啦,今天上場的是–頂象面積驗證碼
根據場景來看,我們需要根據圖片中分隔好的區域找到面積最大的一塊來點擊它。
那么我們把它拆分成以下幾個步驟:
檢測出圖中標記的點將檢測出來的點連成線根據線分割出的區域計算各區域面積,并得到最大面積在該區域面積中選取一個坐標點作為結果
一、檢測出圖中標記的點
第一個問題,怎么檢測出圖片中被標記出來的點?
這里使用哈里斯角點檢測,這里采用OpenCV中的cornerHarris()來實現。
參考下面兩篇文章,感興趣的話可以閱讀一下:
Harris角點檢測原理詳解圖像特征之Harris角點檢測
效果如下圖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
/** * 哈里斯角點檢測 * @param img 原圖地址 * @param img2 新圖地址 */ public void getHarris(String img,String img2) { System.load(dllPath); File bFile = new File(img); try { Mat mat = Imgcodecs.imread(bFile.getPath()); // 轉灰度圖像 Mat gray = new Mat(); Imgproc.cvtColor(mat, gray, Imgproc.COLOR_BGR2GRAY); // 角點發現 Mat harris = new Mat(); Imgproc.cornerHarris(gray, harris, 2 , 3 , 0.04 ); // 繪制角點 float [] floats = new float [harris.cols()]; for ( int i = 0 ; i < harris.rows(); i++) { harris.get(i, 0 , floats); for ( int j = 0 ; j < floats.length; j++) { if (floats[j] > 0.0001 ) { // 越接近于角點數值越大 System.out.println(floats[j]); Imgproc.circle(mat, new Point(j, i), 1 , new Scalar( 0 , 255 , 0 )); } } } Imgcodecs.imwrite(img2, mat); } catch (Throwable e) { e.printStackTrace(); } } |
那標記點的檢測完成了。
二、將檢測出來的點連成線
如何連線就比較簡單了,這里我們只需要在繪制角點的時候將浸染范圍設置大一點就好了,這里設置為5即可。
1
|
Imgproc.circle(mat, new Point(j, i), 5 , new Scalar( 0 , 255 , 0 )); |
下面是效果圖
連線做到這樣的效果就可以了。
三、根據線分割出的區域計算各區域面積,并得到最大面積
這里根據深度優先搜索的原理,劃分不同區域最終選出最大的一塊面積;
深度優先搜索大家不會的話就可以參考這篇文章:
基本算法——深度優先搜索(DFS)和廣度優先搜索(BFS)
這里直接搜索了所有區域。將占像素量最多的區域顯示了出來,效果如圖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
/**根據線分割出的區域計算各區域面積,并得到最大面積 * @param oldimg 原圖 * @param newimg 繪制角點后的圖 */ */ public void getMatrix(String oldimg,String newimg) { File ofile = new File(oldimg); File nfile = new File(newimg); try { BufferedImage oimage = ImageIO.read(ofile); BufferedImage nimage = ImageIO.read(nfile); int matrix[][] = new int [nimage.getWidth()][nimage.getHeight()]; int rank = 0 ; int maxRank = 0 ; int count = 0 ; int maxCount = 0 ; //將檢測并高亮部分置1,其余部分置0,得到一個代替圖的二維數組 for ( int w = 0 ; w < nimage.getWidth(); w++) { for ( int h = 0 ; h < nimage.getHeight(); h++) { int [] bgRgb = new int [ 3 ]; bgRgb[ 0 ] = (nimage.getRGB(w, h) & 0xff0000 ) >> 16 ; bgRgb[ 1 ] = (nimage.getRGB(w, h) & 0xff00 ) >> 8 ; bgRgb[ 2 ] = (nimage.getRGB(w, h) & 0xff ); if (!(bgRgb[ 0 ] <= 70 && bgRgb[ 1 ] >= 180 && bgRgb[ 2 ] <= 70 )) { matrix[w][h] = 0 ; } else { matrix[w][h] = - 1 ; } } } //深度優先搜索找出最大區域 while ( true ) { int n = 0 ; for ( int i = 0 ; i < matrix.length; i++) { for ( int j = 0 ; j < matrix[ 0 ].length; j++) { if (matrix[i][j] == 0 ) { n++; rank++; count = dfs(matrix, rank); if (count > maxCount) { maxCount = count; maxRank = rank; } } } } if (n == 0 ) break ; } //改變最大區域顏色 for ( int j = 0 ; j < matrix[ 0 ].length; j++) { for ( int i = 0 ; i < matrix.length; i++) { if (matrix[i][j] == maxRank){ nimage.setRGB(i, j, new Color( 0 , 0 , 255 ).getRGB()); } } } ImageIO.write(image, "png" , new File(img)); } catch (IOException e) { e.printStackTrace(); } } /** * 深度優先搜索 * @param matrix 圖信息數組 * @param n 標記數 * @return */ public int dfs( int matrix[][], int rank) { int count = 0 ; int w = - 1 ; int h = - 1 ; for ( int i = 0 ; i < matrix.length; i++) { for ( int j = 0 ; j < matrix[ 0 ].length; j++) { if (matrix[i][j] == 0 ) { w = i; h = j; break ; } } if (w != - 1 ) { break ; } } Stack<JSONObject> stack = new Stack<JSONObject>(); while (matrix[w][h] == 0 || h == stack.peek().getIntValue( "h" ) && w == stack.peek().getIntValue( "w" )) { JSONObject json = new JSONObject(); json.put( "w" , w); json.put( "h" , h); stack.push(json); matrix[w][h] = rank; count++; if (h + 1 < matrix[ 0 ].length) { if (matrix[w][h + 1 ] == 0 ) { h = h + 1 ; continue ; } } if (w + 1 < matrix.length) { if (matrix[w + 1 ][h] == 0 ) { w = w + 1 ; continue ; } } if (h - 1 >= 0 ) { if (matrix[w][h - 1 ] == 0 ) { h = h - 1 ; continue ; } } if (w - 1 >= 0 ) { if (matrix[w - 1 ][h] == 0 ) { w = w - 1 ; continue ; } } stack.pop(); if (!stack.empty()) { if (h == stack.peek().getIntValue( "h" ) && w == stack.peek().getIntValue( "w" )) { stack.pop(); } } if (!stack.empty()) { w = stack.peek().getIntValue( "w" ); h = stack.peek().getIntValue( "h" ); } else { break ; } } return count; } |
四、 在該區域面積中選取一個坐標點作為結果
這里我們都已經找到面積最大區域了,就隨意取一個點就好了
將上面代碼中的
1
2
3
4
5
6
7
8
|
//改變最大區域顏色 for ( int j = 0 ; j < matrix[ 0 ].length; j++) { for ( int i = 0 ; i < matrix.length; i++) { if (matrix[i][j] == maxRank){ nimage.setRGB(i, j, new Color( 0 , 0 , 255 ).getRGB()); } } } |
改為下面的代碼即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//標記選取到的點 boolean flag = false ; for ( int j = 0 ; j < matrix[ 0 ].length; j++) { for ( int i = 0 ; i < matrix.length; i++) { if (matrix[i][j] == maxRank) { oimage.setRGB(i, j, new Color( 255 , 0 , 0 ).getRGB()); System.out.println( "w=" + i + "|h=" + j); flag = true ; break ; } } if (flag) { break ; } } |
結果展示:
本文思路參考:https://blog.csdn.net/aaronjny/article/details/110245896
到此這篇關于使用java + OpenCV破解頂象面積驗證碼的示例的文章就介紹到這了,更多相關java頂象面積驗證碼內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/weixin_49701447/article/details/110627934