脚本之家

电脑版
提示:原网页已由神马搜索转码, 内容由www.jb51.net提供.
您的位置:首页软件编程java→ java顶象面积验证码

使用java + OpenCV破解顶象面积验证码的示例

  更新时间:2021年02月03日 09:57:21  作者:香芋味的猫 
这篇文章主要介绍了使用java + OpenCV破解顶象面积验证码的示例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

前言

在这里插入图片描述

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

在这里插入图片描述

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

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

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

一、检测出图中标记的点

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

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

Harris角点检测原理详解图像特征之Harris角点检测

效果如下图

在这里插入图片描述

/**
* 哈里斯角点检测
* @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));

下面是效果图

在这里插入图片描述

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

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

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

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

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

在这里插入图片描述

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

结果展示:

在这里插入图片描述

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

到此这篇关于使用java + OpenCV破解顶象面积验证码的示例的文章就介绍到这了,更多相关java顶象面积验证码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

    • 这篇文章主要介绍了Netty粘包拆包问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
      2020-08-08
    • 这篇文章主要介绍了解决rocketmq-client查询手动发送消息异常问题,具有很好的参考价值,希望对大家大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
      2023-08-08
    • 这篇文章主要介绍了IDEA中如何查找jar包之间的依赖关系并忽略依赖的某个包?本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
      2020-08-08
    • 这篇文章主要介绍了SpringBoot中的@Configuration与@Bean注解,在进行项目编写前,我们还需要知道一个东西,就是SpringBoot对我们的SpringMVC还做了哪些配置,包括如何扩展,如何定制,只有把这些都搞清楚了,我们在之后使用才会更加得心应手
      2022-10-10
    • 这篇文章主要介绍了Java数组的基本学习教程,是Java入门学习中的基础知识,需要的朋友可以参考下
      2015-10-10
    • 注解(Annotation)是一种在 Java 程序中以元数据的形式对代码进行标记和说明的机制,它可以被添加到类、方法、字段、参数等程序元素上,用于提供额外的信息和指示,本文给大家介绍springIoc及注解的使用,感兴趣的朋友一起看看吧
      2024-02-02
    • 这篇文章主要为大家介绍了RocketMQ普通消息实战演练详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
      2022-08-08
    • 在现代的Web应用程序中,单点登录(Single Sign-On)已经变得越来越流行,在本文中,我们将使用Spring Boot构建一个基本的单点登录系统,需要的可以参考一下
      2023-05-05
    • 这篇文章主要带领大家深入理解Spring事务原理,Spring事务的传播属性
      2016-07-07
    • 这篇文章主要介绍了SpringBoot使用OpenCV示例总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
      2020-08-08

    最新评论