Подтвердить что ты не робот

Автоматический расчет низких и высоких порогов для операции Canny в opencv

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

cvCanny(input,output,thresh1,thresh2)

В Matlab есть возможность их автоматического вычисления:

edge(input,'canny')

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

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

спасибо

4b9b3361

Ответ 1

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

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


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

  • Вычислить порог Otsu, используя:

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

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

  • Используйте пороговое значение Otsu как более высокий порог и половину того же самого, что и нижний порог для алгоритма Canny.

    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. Объяснение реализации Otsu можно найти здесь.

Ответ 2

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

Ответ 4

Я просмотрел исходный код обнаружения края 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;
}

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

Обратите внимание, что double nonEdgeRate = 0.6 и double thresholdRate = 0.6 настраивается мной в моем конкретном случае использования. Первоначальные значения равны 0,7 и 0,4 отдельно в матрице.

Ответ 5

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

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

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

Ответ 6

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

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

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

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))

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

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

Ответ 7

Как предложил Лука Дель Тонго, вы можете рассчитать пороговые значения от серого изображения, например. в 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);