opencv - подсчет ненаправленных ребер от хитрости

Может ли кто-нибудь помочь мне, как подсчитать количество ненаправленных краев с помощью обнаружения opencv cannyedge? У меня есть изображение cannyEdge из opencv, и я хотел бы иметь гистограмму, основанную на направлениях краев, и таким образом я могу подсчитать количество направленных и ненаправленных краев.


person user973743    schedule 21.06.2012    source источник


Ответы (1)


Я думаю, вы путаете обнаружение краев с обнаружением градиента. Canny предоставляет карту краев на основе величины градиента (обычно с помощью оператора Собеля, но может использовать и другие), поскольку Canny возвращает только информацию о пороговой величине градиента, но не может предоставить вам информацию об ориентации.

EDIT: я должен уточнить, что алгоритм Canny использует градиентную ориентацию для немаксимального шага подавления. Однако реализация OpenCV Canny скрывает от вас эту информацию об ориентации и возвращает только карту величины края.

Основной алгоритм получения величины и ориентации градиента выглядит следующим образом:

  1. Вычислите Собеля в направлении X (Sx).
  2. Вычислите Собеля в направлении Y (Sy).
  3. Вычислите величину градиента sqrt(Sx*Sx + Sy*Sy).
  4. Вычислите ориентацию градиента с помощью arctan(Sy / Sx).

Этот алгоритм может быть реализован с использованием следующих функций OpenCV: Собел, величина и фаза.

Ниже приведен пример, который вычисляет величину и фазу градиента, а также показывает грубое цветовое отображение ориентации градиента:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>
#include <vector>

using namespace cv;
using namespace std;

Mat mat2gray(const cv::Mat& src)
{
    Mat dst;
    normalize(src, dst, 0.0, 255.0, cv::NORM_MINMAX, CV_8U);

    return dst;
}

Mat orientationMap(const cv::Mat& mag, const cv::Mat& ori, double thresh = 1.0)
{
    Mat oriMap = Mat::zeros(ori.size(), CV_8UC3);
    Vec3b red(0, 0, 255);
    Vec3b cyan(255, 255, 0);
    Vec3b green(0, 255, 0);
    Vec3b yellow(0, 255, 255);
    for(int i = 0; i < mag.rows*mag.cols; i++)
    {
        float* magPixel = reinterpret_cast<float*>(mag.data + i*sizeof(float));
        if(*magPixel > thresh)
        {
            float* oriPixel = reinterpret_cast<float*>(ori.data + i*sizeof(float));
            Vec3b* mapPixel = reinterpret_cast<Vec3b*>(oriMap.data + i*3*sizeof(char));
            if(*oriPixel < 90.0)
                *mapPixel = red;
            else if(*oriPixel >= 90.0 && *oriPixel < 180.0)
                *mapPixel = cyan;
            else if(*oriPixel >= 180.0 && *oriPixel < 270.0)
                *mapPixel = green;
            else if(*oriPixel >= 270.0 && *oriPixel < 360.0)
                *mapPixel = yellow;
        }
    }

    return oriMap;
}

int main(int argc, char* argv[])
{
    Mat image = Mat::zeros(Size(320, 240), CV_8UC1);
    circle(image, Point(160, 120), 80, Scalar(255, 255, 255), -1, CV_AA);

    imshow("original", image);

    Mat Sx;
    Sobel(image, Sx, CV_32F, 1, 0, 3);

    Mat Sy;
    Sobel(image, Sy, CV_32F, 0, 1, 3);

    Mat mag, ori;
    magnitude(Sx, Sy, mag);
    phase(Sx, Sy, ori, true);

    Mat oriMap = orientationMap(mag, ori, 1.0);

    imshow("magnitude", mat2gray(mag));
    imshow("orientation", mat2gray(ori));
    imshow("orientation map", oriMap);
    waitKey();

    return 0;
}

Использование изображения в виде круга:
введите здесь описание изображения

В результате получаются следующие изображения величины и ориентации:
величинаориентация

Наконец, вот карта ориентации градиента:
map

ОБНОВЛЕНИЕ: Абид на самом деле задал в комментариях отличный вопрос «что здесь подразумевается под ориентацией?», который, как мне показалось, требует дальнейшего обсуждения. Я предполагаю, что функция phase не переключает кадры координат с точки зрения обычной обработки изображения, когда положительная ось y направлена ​​вниз, а положительная ось x - вправо. Учитывая это предположение, которое приводит к следующему изображению, показывающему векторы ориентации градиента вокруг круга:

введите здесь описание изображения

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

Надеюсь, вы нашли это полезным!

person mevatron    schedule 22.06.2012
comment
@AbidRahmanK Эй, Абид! В этом случае вы можете думать об ориентации градиента как об угле вектора нормали к поверхности градиента. Глядя на изображение ориентации, вы можете видеть, что это так, потому что оно увеличивается от 0 градусов до 360 градусов, когда вы двигаетесь по кругу. - person mevatron; 22.06.2012
comment
+1 Отлично. Что делать, если у меня есть набор изображений с вертикальными, горизонтальными и диагональными линиями внутри? - person Mzk; 26.06.2012
comment
@MizukiKai Применяются те же принципы. Ориентация относительно осей пиксельной сетки, как показано выше. Например, вертикальные линии должны отображать 0 градусов или 180 градусов; в зависимости от направления максимального градиента. В качестве упражнения я бы предложил запустить приведенный выше код на идеализированном изображении, содержащем только интересующую вас ориентацию линий, чтобы увидеть, как это работает. - person mevatron; 26.06.2012
comment
Хотел бы сделать это. Спасибо @mevatron. - person Mzk; 26.06.2012
comment
+1 Это отличный ответ на плохо написанный вопрос (я бы снова проголосовал за него, если бы мог). - person karlphillip; 10.09.2012