java opencv 检测缺口图片是否向左凸出来的
如上4张图片,其中 2 3 是向左凸出来的。
图片处理,以上图2为例, 图片 -> 高斯模糊 -> 图片灰度化处理 -> 边缘检测 ,没有二值化处理。
最后的图片,在python下,显示的像素点
思路,统计每个 x 轴(因为我是检测图片是否向左凸出来)上,rgb 等于255的个数。假设图片是像左凸出来的,那么前几个(自定义)坐标上的统计值,一定是小于最大统计值的,这里定义小于 最大值的1/3。
简单代码如下:
import org.opencv.core.*; import org.opencv.imgcodecs.Imgcodecs; import org.springframework.util.CollectionUtils; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.*; import java.util.*; public class CheckLeftOut { public static void main(String[] args) { // 这个必须要写,不写报java.lang.UnsatisfiedLinkError System.load("D:\\java_project\\common\\lib\\opencv_java440_x64.dll"); //绝对路径 String name = "1600853293536"; //1600853293536 1600852044392 判断小滑块是否左凸出来 {11=3, 12=9, 13=6, 14=4, 15=4, 16=4, 17=2, 18=4, 19=2, 20=2} {11=6, 12=6, 13=6, 14=4, 15=4, 16=4, 17=2, 18=4} String small = "C:\\generate_captcha\\" + name + ".png"; System.out.println(imageOut(small)); } public static boolean imageOut(String path) { // 这个必须要写,不写报java.lang.UnsatisfiedLinkError System.load("D:\\java_project\\common\\lib\\opencv_java440_x64.dll"); //绝对路径 Mat src = imread(path); Mat result = Dis3.gaussianBlur(src); //Imgcodecs.imwrite("C:\\generate_captcha\\b1_1.png", result); result = gray(result); //Imgcodecs.imwrite("C:\\generate_captcha\\b1_2.png", result); //可以不需要 //result = binary(result); //Imgcodecs.imwrite("C:\\generate_captcha\\b1_3.jpg", result); result = canny(result); //Imgcodecs.imwrite("C:\\generate_captcha\\b1_4.png", result); //System.out.println(getImageGRB("C:\\generate_captcha\\b1_4.png")); Map<Integer, Integer> map = getImageGRB(mat2InputStream(getExtensionName(path), result)); if(CollectionUtils.isEmpty(map)) { return false; } return imageOut(map); } /** * * @param map, key 是横坐标,value 是横坐标像素点大于0的统计 * 首先算出像素点最大的值,如果图片的缺口是凸出来的,前几个横坐标(前5个,自己定义)的统计值肯定是小于最大值(一般不超过1/3,自己定义) * @return */ public static boolean imageOut(Map<Integer, Integer> map) { List<Integer> xList = new ArrayList<>(); //横坐标 List<Integer> yList = new ArrayList<>(); //横坐标像素点大于0的统计 map.forEach((k, v) -> { xList.add(k); yList.add(v); }); int max = yList.stream().mapToInt(v -> v).max().orElse(0); max = max / 3; int size = xList.size() > 5 ? 5 : xList.size(); for(int i = 0; i < size; i ++) { if(map.get(xList.get(i)) >= max) { return false; } } return true; } /*** * 获取扩展名,不包含 . * @param file * @return */ public static String getExtensionName(String file) { int index = file.lastIndexOf("."); return file.substring(index + ".".length(), file.length()); } /*** * @param extensionName:文件扩展名,不包含 . * @param mat * @return */ public static InputStream mat2InputStream(String extensionName, Mat mat) { MatOfByte mob = new MatOfByte(); Imgcodecs.imencode("." + extensionName, mat, mob); byte[] byteArray = mob.toArray(); return new ByteArrayInputStream(byteArray); } /** * 返回 map, key 是横坐标,value 是横坐标像素点大于0的统计 * @param inputStream * @return */ public static Map<Integer, Integer> getImageGRB(InputStream inputStream) { Map<Integer, Integer> map = new LinkedHashMap<>(); try { BufferedImage bufImg = ImageIO.read(inputStream); int height = bufImg.getHeight(); int width = bufImg.getWidth(); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { //result[i][j] = bufImg.getRGB(i, j) & 0xFFFFFF; //System.out.println(bufImg.getRGB(i, j) ); /*if(bufImg.getRGB(i, j) > 0) { System.out.println(i + "," + j); }*/ int pixel = bufImg.getRGB(i, j); // 下面三行代码将一个数字转换为RGB数字 int a = (pixel & 0xff0000) >> 16; int b = (pixel & 0xff00) >> 8; int c = (pixel & 0xff); if (a == 255 || b == 255 || c == 255) { //System.out.println("i=" + i + ",j=" + j + ":(" + a + "," + b + "," + c + ")"); map.put(i, map.get(i) == null ? 1 : map.get(i) + 1); } } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // System.out.println(map); return map; } public static Map<Integer, Integer> getImageGRB(String filePath) { File file = new File(filePath); if(!file.exists()) { return null; } try { return getImageGRB(new FileInputStream(file)); } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } }
图片过滤方法
/*** * 高斯模糊处理 * @param src * @return */ public static Mat gaussianBlur(Mat src) { Mat dst = new Mat(); //参数 3 会影响图片处理结果 Imgproc.GaussianBlur(src, dst, new Size(3, 3), 0, 0, Core.BORDER_DEFAULT); // Imgcodecs.imwrite("c:\\b1_1.jpg", binary); return dst; } /** * 图片灰度化处理 * @param src * @return */ public static Mat gray(Mat src) { Mat dst = new Mat(); Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGR2GRAY); return dst; } /** * 图片 二值化 * @param src * @return */ public static Mat binary(Mat src) { Mat dst = new Mat(); Imgproc.threshold(src, dst, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU); //一般 return dst; } /** * 边缘检测 * @param src * @return */ public static Mat canny(Mat src) { Mat dst = new Mat(); // 这里 200 300 会影响结果 Imgproc.Canny(src, dst, 200, 300); return dst; }