Автоматический расчет нижнего и верхнего порогов для операции Canny в opencv - PullRequest
32 голосов
/ 27 ноября 2010

В openCV нижний и верхний пороги для оператора canny являются обязательными:

cvCanny(input,output,thresh1,thresh2)

В Matlab есть возможность рассчитать их автоматически:

edge(input,'canny')

Я изучил код Matlab для edge, и это не совсем просто для их автоматического вычисления.

Известно ли вам о какой-либо реализации оператора canny наряду с автоматическим вычислением порога для opencv?

спасибо

Ответы [ 7 ]

45 голосов
/ 17 апреля 2013

Я наткнулся на этот ответ, когда искал способ автоматического вычисления пороговых значений Кэнни.

Надеюсь, это поможет любому, кто придет в поисках хорошего метода для определения автоматических пороговых значений для алгоритма Кэнни ...


Если ваше изображение состоит из различного переднего плана и фона, то край объекта переднего плана может использовать извлеченный следующим образом:

  1. Рассчитать порог Оцу, используя:

    double otsu_thresh_val = cv::threshold(
        orig_img, _img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU
    );
    

    Нам не нужен _img.Нас интересует только otsu_thresh_val, но, к сожалению, в настоящее время в OpenCV нет метода, позволяющего вычислять только пороговое значение.

  2. Используйте пороговое значение Оцу в качестве более высокого порога иполовина того же, что и нижний порог для алгоритма Кэнни.

    double high_thresh_val  = otsu_thresh_val,
           lower_thresh_val = otsu_thresh_val * 0.5;
    cv::Canny( orig_img, cannyOP, lower_thresh_val, high_thresh_val );
    

Более подробную информацию, связанную с этим, можно найти в этой статье: Исследование по применению метода Оцу в Canny Operator .Объяснение реализации Оцу можно найти здесь .

16 голосов
/ 11 января 2011

Вы можете использовать среднее значение входного изображения в градациях серого и определить нижний и верхний пороги, используя стандартное отклонение. Вы можете получить более подробное объяснение и код opencv здесь: http://www.kerrywong.com/2009/05/07/canny-edge-detection-auto-thresholding/

7 голосов
/ 13 декабря 2011

Кроме того, есть код, позволяющий сделать это автоматически, поместив его в сборку OpenCV. Я нашел его в списке рассылки OpenCV-пользователей, так что никаких гарантий. :)

Обсуждение: http://opencv -users.1802565.n2.nabble.com / Automatic-thresholding-in-cvCanny-td5871024.html GitHub (код): https://gist.github.com/756833

4 голосов
/ 19 июля 2017

Проверить эту ссылку: http://www.pyimagesearch.com/2015/04/06/zero-parameter-automatic-canny-edge-detection-with-python-and-opencv/

Они реализуют аналогичное решение, используя базовую статистику для определения нижнего и верхнего порога обнаружения канни-края.

def auto_canny(image, sigma=0.33):
     # compute the median of the single channel pixel intensities
     v = np.median(image)

    # apply automatic Canny edge detection using the computed median
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0 + sigma) * v))
    edged = cv2.Canny(image, lower, upper)

    # return the edged image
    return edged
3 голосов
/ 26 марта 2017

Я просмотрел исходный код обнаружения ребер Matlab Canny и мне удалось написать его на Java с 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<Mat> matList = new ArrayList<Mat>();
        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;
}

Filepath - это место для хранения выходных изображений.И входное изображение должно быть серым с типом данных U8.Основной принцип - исключить пиксель nonEdgeRate (60%) как не краевой пиксель по яркости.Гистограмма используется для сортировки яркости, и верхний порог будет установлен так, чтобы под ним было 60% пикселей.Нижний порог устанавливается путем умножения верхнего порога на thresholdRate (0,6).

Обратите внимание, что double nonEdgeRate = 0,6 и double thresholdRate = 0,6 настраивается мной в моем конкретном случае использования.Исходные значения th составляют 0,7 и 0,4 в Matlab.

1 голос
/ 20 февраля 2017

У меня другой подход к той же проблеме.Это решение также включает в себя выбор оптимальных порогов для определения края.

  • Сначала вычислите медиану изображения серой шкалы.
  • Выберите два значения (нижнее и верхнее)пороговые значения) на основе медианного значения изображения в серой шкале.

Следующий псевдокод показывает, как это делается:

v = np.median(gray_img)
sigma = 0.33

#---- apply optimal Canny edge detection using the computed median----
lower_thresh = int(max(0, (1.0 - sigma) * v))
upper_thresh = int(min(255, (1.0 + sigma) * v))

Исправьте эти пороговые значения в качестве параметров в cannyфункция обнаружения ребер.

Иллюстрация : Если вы наблюдаете кривую Гаусса в статистике, в распределении учитываются значения между 0,33 с обеих сторон кривой.Предполагается, что любое значение за пределами этих точек является выбросом.Поскольку изображения считаются данными, здесь также предполагается это понятие.

0 голосов
/ 22 декабря 2016

Как предположил Лука Дель Тонго, вы можете рассчитать пороги по серому изображению, например в Java с использованием OpenCV ...

MatOfDouble mu = new MatOfDouble();
MatOfDouble stddev = new MatOfDouble();
Core.meanStdDev(greyMat, mu, stddev);
threshold1 = mu.get(0, 0)[0];
threshold2 = stddev.get(0, 0)[0];
Imgproc.Canny(greyMat, outputMat, threshold1, threshold2);
...