Automatic calculation of low and high thresholds for the Canny operation in opencv

后端 未结 7 897
孤独总比滥情好
孤独总比滥情好 2020-11-28 03:15

In openCV, the low and high thresholds for the canny operator are mandatory:

cvCanny(input,output,thresh1,thresh2)

In Matlab, there\'s an o

7条回答
  •  春和景丽
    2020-11-28 03:31

    I have looked through the source code of Matlab Canny edge detection and I managed to write it in Java with OpenCV 3.

    private static Mat getpartialedge(Mat image){
        double nonEdgeRate = 0.6;
        double thresholdRate = 0.6;
        double w = image.cols();
        double h = image.rows();
        int bins = 256;
        Mat sobel = new Mat();
        Mat sobelx = new Mat();
        Mat sobely = new Mat();
        Mat sobelxabs = new Mat();
        Mat sobelyabs = new Mat(); 
        Size gsz = new Size(5, 5);
        if(false) {
            Imgproc.Canny(image, sobel, 41, 71);
        }else {
    
            //Imgproc.GaussianBlur(graycopy,graycopy, gsz, 2);
            //Imgproc.dilate(image, image, kernel8);
            Imgproc.GaussianBlur(image, image, gsz, 2);
    
    
            int apertureSize = 3;
            Imgproc.Sobel(image, sobelx, CvType.CV_16S, 1, 0, apertureSize, 1, 0);
            Core.convertScaleAbs(sobelx, sobelxabs);
            Imgproc.Sobel(image, sobely, CvType.CV_16S, 0, 1, apertureSize, 1, 0);
            Core.convertScaleAbs(sobely, sobelyabs);
            Core.addWeighted(sobelxabs, 1, sobelyabs, 1, 0, sobel);
            sobel.convertTo(sobel, CvType.CV_8U);
    
    
            Mat equalized = new Mat();
            Imgproc.equalizeHist(sobel, equalized);
            Imgcodecs.imwrite(filePath + "aftersobel(eq).png", equalized);
            Imgcodecs.imwrite(filePath + "aftersobel.png", sobel);
    
    
            Mat hist = new Mat();
            List matList = new ArrayList();
            matList.add(sobel);
            Imgproc.calcHist(matList, new MatOfInt(0), new Mat(), hist, new MatOfInt(bins), new MatOfFloat(0f, 256f));
            float accu = 0;
            float t = (float) (nonEdgeRate * w * h);
            float bon = 0;
            float[] accutemp = new float[bins];
            for (int i = 0; i < bins; i++) {
                float tf[] = new float[1];
                hist.get(i, 0, tf);
                accu = accu + tf[0];
                accutemp[i] = accu;
                if (accu > t) {
                    bon = (float) i;
                    break;
                }
            }
            Imgproc.threshold(sobel, sobel, bon, 255, Imgproc.THRESH_BINARY);
            double ut = bon;
            double lt = thresholdRate * bon;
    
    
            Imgproc.Canny(image, sobel, lt, ut);
            //Imgproc.dilate(sobel, sobel, kernel2);
        }
        return sobel;
    }
    

    The filepath is the place to hold the output images. And the input image should be a gray-scale image with U8 data type. The basic principle is to rule out nonEdgeRate(60%) pixel as non-edge pixel by the brightness. A histogram is used to sort the brightness and the upper threshold will be set so that there are 60% pixels below it. The lower threshold is set by multiplying the upper threshold by the thresholdRate(0.6).

    Note that the double nonEdgeRate = 0.6 and double thresholdRate = 0.6 is tuned by myself in my specific use case. Th original values are 0.7 and 0.4 separately in matlab.

提交回复
热议问题