要破解滑块验证码,最简单直接的思路是:
- 获取滑块到背景缺口的距离
- 通过selenium的操作滑块完成滑动
关键点就在于如何获取滑块到背景缺口图的距离,现在主流的方案都是通过OpenCV(Open Source Computer Vision Library)开源计算机视觉库来处理,OpenCV有非常多的图像处理方法,但是我们java系的程序员当然是想通过java来实现,好在有实现好了的JavaCV,废话不多说,直接上代码
pom.xml
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp-platform</artifactId>
<version>1.5.7</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv-platform</artifactId>
<version>4.5.5-1.5.7</version>
</dependency>
SliderImgTest.java
import org.bytedeco.javacpp.DoublePointer;
import org.bytedeco.javacpp.indexer.UByteRawIndexer;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Point;
import org.bytedeco.opencv.opencv_core.Scalar;
import java.util.Objects;
import static org.bytedeco.opencv.global.opencv_core.CV_8UC1;
import static org.bytedeco.opencv.global.opencv_core.inRange;
import static org.bytedeco.opencv.global.opencv_core.minMaxLoc;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imwrite;
import static org.bytedeco.opencv.global.opencv_imgproc.COLOR_BGR2GRAY;
import static org.bytedeco.opencv.global.opencv_imgproc.COLOR_RGB2GRAY;
import static org.bytedeco.opencv.global.opencv_imgproc.THRESH_BINARY;
import static org.bytedeco.opencv.global.opencv_imgproc.TM_CCOEFF_NORMED;
import static org.bytedeco.opencv.global.opencv_imgproc.cvtColor;
import static org.bytedeco.opencv.global.opencv_imgproc.matchTemplate;
import static org.bytedeco.opencv.global.opencv_imgproc.threshold;
/**
* @author Administrator
* 2022/10/26
*/
public class SliderImgTest {
public static void main(String[] args) {
Mat bigImg = bigImgProcess();
Mat smallImg = smallImgProcess();
Mat result = new Mat();
DoublePointer minVal= new DoublePointer();
DoublePointer maxVal= new DoublePointer();
Point min = new Point();
Point max = new Point();
// 匹配
matchTemplate(bigImg, smallImg, result, TM_CCOEFF_NORMED);
// 获取结果
minMaxLoc(result, minVal, maxVal, min, max, null);
// 打印移动距离
System.out.println(max.x());
if (!Objects.isNull(bigImg)) {
bigImg.release();
}
if (!Objects.isNull(smallImg)) {
smallImg.release();
}
if (!Objects.isNull(result)) {
result.release();
}
}
/**
* 滑块背景的处理
* @return
*/
private static Mat bigImgProcess() {
Mat bigImg = imread("C:\\Users\\Administrator\\Desktop\\big.jpg");
if (bigImg.empty()) {
return null;
}
// 1、灰度化图片
cvtColor(bigImg, bigImg, COLOR_RGB2GRAY);
// 2、二值化转黑白图
// adaptiveThreshold(bigImg, bigImg,255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 3, 20);
threshold(bigImg, bigImg, 140, 255, THRESH_BINARY);
imwrite("big.jpg", bigImg);
return bigImg;
}
/**
* 小滑块的处理
* @return
*/
private static Mat smallImgProcess() {
Mat smallImg = imread("C:\\Users\\Administrator\\Desktop\\small.png");
if (smallImg.empty()) {
return null;
}
// 1、灰度化图片
cvtColor(smallImg, smallImg, COLOR_BGR2GRAY);
int width= smallImg.rows();
int height = smallImg.cols();
// 2、去除周围黑边
UByteRawIndexer smallImgIndexer = smallImg.createIndexer();
for (int row = 0; row < width; row++) {
for (int col = 0; col < height; col++) {
if (smallImgIndexer.get(row, col) == 0) {
smallImgIndexer.put(row, col, 255);
}
}
}
smallImgIndexer.release();
// 3、inRange二值化转黑白图
Mat newMat = new Mat(width,height, CV_8UC1, Scalar.all(255));
inRange(smallImg, newMat, newMat, smallImg);
imwrite("small.png", smallImg);
return smallImg;
}
}
效果展示
bigImg
smallImg