使用java + OpenCV 100%破解顶象面积验证码

前言

本篇文章主要介绍了使用java + OpenCV 100%破解顶象面积验证码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

头部.gif


我们又来破解验证码啦,今天上场的是–顶象面积验证码

5.jpg


根据场景来看,我们需要根据图片中分隔好的区域找到面积最大的一块来点击它。

那么我们把它拆分成以下几个步骤:

检测出图中标记的点
将检测出来的点连成线
根据线分割出的区域计算各区域面积,并得到最大面积
在该区域面积中选取一个坐标点作为结果


一、检测出图中标记的点

第一个问题,怎么检测出图片中被标记出来的点?

这里使用哈里斯角点检测,这里采用OpenCV中的cornerHarris()来实现。
参考下面两篇文章,感兴趣的话可以阅读一下:

效果如下图

4.jpg


/**	 * 哈里斯角点检测	 * @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即可。

Imgproc.circle(mat, new Point(j, i), 5, new Scalar(0, 255, 0));

下面是效果图

3.jpg


连线做到这样的效果就可以了。

三、根据线分割出的区域计算各区域面积,并得到最大面积

这里根据深度优先搜索的原理,划分不同区域最终选出最大的一块面积;

深度优先搜索大家不会的话就可以参考这篇文章:
基本算法——深度优先搜索(DFS)和广度优先搜索(BFS)

这里直接搜索了所有区域。将占像素量最多的区域显示了出来,效果如图:

2.jpg


/**根据线分割出的区域计算各区域面积,并得到最大面积	 * @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;
	}

四、 在该区域面积中选取一个坐标点作为结果

这里我们都已经找到面积最大区域了,就随意取一个点就好了

将上面代码中的

//改变最大区域颜色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());
		}
	}}

改为下面的代码即可

//标记选取到的点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;
	}}

结果展示:


1.jpg


本文思路参考:https://blog.csdn.net/aaronjny/article/details/110245896

末尾.jpg


作者:香芋味的猫丶

到此关于使用java + 使用java + OpenCV 100%破解顶象面积验证码的文章就介绍到这了,更多相关java selenium 滑动验证码内容请关注作者的其他文章,希望大家以后多多支持,谢谢!



猜你喜欢

转载自blog.51cto.com/14284202/2563687