天天看點

java opencv 檢測缺口圖檔是否向左凸出來的

java opencv 檢測缺口圖檔是否向左凸出來的
java opencv 檢測缺口圖檔是否向左凸出來的
java opencv 檢測缺口圖檔是否向左凸出來的
java opencv 檢測缺口圖檔是否向左凸出來的

如上4張圖檔,其中 2 3 是向左凸出來的。

圖檔處理,以上圖2為例,  圖檔 -> 高斯模糊       

java opencv 檢測缺口圖檔是否向左凸出來的

           -> 圖檔灰階化處理     

java opencv 檢測缺口圖檔是否向左凸出來的

       ->  邊緣檢測   

java opencv 檢測缺口圖檔是否向左凸出來的

 ,沒有二值化處理。

 最後的圖檔,在python下,顯示的像素點

java opencv 檢測缺口圖檔是否向左凸出來的

思路,統計每個 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;
    }