前言
去年年尾曾经搞过某个图片旋转验证,需要把 4 张图片转到正向才能通过验证:
当时的第一反应是只有正向的时候才能检测出人脸,可以拿人脸检测来做,可惜当时并不知道该怎么在项目里接入人脸检测,也不方便使用第三方 API。最后发现这些验证图片是数量并不是很多,于是就把这些图全部爬了下来,人工做了方向标注(可把我累死啦),然后用相似哈希来做匹配。这种粗暴的做法(像不像刷 OJ 打表)有一个致命的缺点,只要对方更新图库,甚至是改成动态出题,就会直接被废掉。
今天突然想起来,其实静态图片检测个人脸,实在也没多大难度。
调包小子请求出战
OpenCV 直接提供了几个人脸检测模型,可以直接拿来用,虽然这几个模型并不是很强,但至少解决这个图片验证是足够了。
直接上代码:
package opencv;
import opencv.match.Face;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import utils.ImageUtils;
import utils.ImageViewer;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import static org.opencv.imgcodecs.Imgcodecs.IMREAD_COLOR;
/**
* @author yuanbug
* date: 2020/5/13
*/
public class Face {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
private static String FACE_DATA_PATH = String.valueOf(Face.class.getClassLoader().getResource("haarcascade_frontalface_alt.xml")).replace("file:/", "");
private static final String[] IMAGE_PATH = {
"D:/test/img1.jpg",
"D:/test/img2.jpg",
"D:/test/img3.jpg",
"D:/test/img4.jpg"
};
public static void main(String[] args) {
CascadeClassifier faceClassifier = new CascadeClassifier(FACE_DATA_PATH);
List<Mat> images = Arrays.stream(IMAGE_PATH)
.map(path -> Imgcodecs.imread(path, IMREAD_COLOR))
.peek(image -> {
MatOfRect faceRect = new MatOfRect();
faceClassifier.detectMultiScale(image, faceRect);
System.out.println("有脸: " + faceRect.empty());
faceRect.toList().forEach(rec -> Imgproc.rectangle(image, new Point(rec.x, rec.y), new Point(rec.x + rec.width, rec.y + rec.height), new Scalar(255, 0, 0)));
})
.collect(Collectors.toList());
new ImageViewer(ImageUtils.horizontalConcat(images), "人脸检测", true);
}
}
运行结果:
实验说明,这个思路是可行的。拿到验证图片后,先切割成 4 张小图,然后看看需要旋转多少次才能检测到人脸,就能得到点击次数了。
书到用时方恨少,多懂一点东西,就可以少干很多苦力活呀!