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

Что такое градиентная ориентация и величина градиента

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

4b9b3361

Ответ 1

Как объясняется Dima в ответе , вы должны быть знакомы с математической концепцией gradient, чтобы лучше понять градиент в области обработки изображений.

Мой ответ основан на ответе mevatron на этот question.

Здесь вы найдете простой исходный образ белого диска на черном фоне:

enter image description here

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

На следующих изображениях показан горизонтальный компонент:

enter image description here

показывает, сколько серых уровней в вашем изображении изменяется в горизонтальном направлении (это направление положительного x, сканирование изображения слева направо), это изменение "закодировано" на уровне серого изображения горизонтальный компонент: средний уровень серого означает отсутствие изменений, яркие уровни означают изменение от темного значения до яркого значения, темные уровни означают изменение от яркого значения до темного значения. Итак, в приведенном выше изображении вы видите более яркое значение в левой части круга, потому что в левой части исходного изображения у вас есть переход от черного к белому, который дает вам левый край диска; аналогично, в приведенном выше изображении вы видите более темное значение в правой части круга, потому что в правой части исходного изображения у вас есть переход от белого к черному, который дает вам правый край диска. В приведенном выше изображении внутренняя часть диска и фон находятся на среднем уровне серого, потому что нет изменений внутри диска и фона.

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

enter image description here

Теперь вы можете объединить два компонента, чтобы получить величину градиента и ориентацию градиента.

Следующее изображение представляет собой величину градиента:

enter image description here

Опять же, в приведенном выше изображении изменение начального изображения закодировано на уровне серого: здесь вы видите, что белый означает высокое изменение исходного изображения, в то время как черный означает отсутствие изменений вообще. Итак, когда вы смотрите на изображение величины градиента, вы можете сказать: "Если изображение яркое, это означает большое изменение исходного изображения, если оно темное, это означает отсутствие изменений или очень незначительное изменение".

Следующее изображение представляет собой ориентацию градиента:

enter image description here

В приведенном выше изображении ориентация снова кодируется как уровни серого: вы можете думать о ориентации как угол стрелки, указывающей от темной части изображения на яркую часть изображения; угол ссылается на xy-кадр, где x пробегает слева направо, а y пробегает сверху вниз. В приведенном выше изображении вы видите весь уровень серого от черного (нулевая степень) до белого (360 градусов). Мы можем кодировать информацию с цветом:

enter image description here

в приведенном выше изображении информация кодируется следующим образом:

красный: угол между 0 и 90 градусами

голубой: угол между 90 и 180 градусами

зеленый: угол между 180 и 270 градусами

желтый: угол между 270 и 360 градусами

Здесь это код С++ OpenCV для создания вышеуказанных изображений.

Обратите внимание на то, что для вычисления ориентации я использую функцию cv::phase, которая, как объясняется в doc дает угол 0, когда и вертикальная составляющая, и горизонтальная составляющая градиента равны нулю; что может быть удобно, но с математической точки зрения явно неверно, потому что, когда обе компоненты равны нулю, ориентация не определена, и единственным значимым значением для ориентации, хранящейся в С++-типе с плавающей точкой, является NaN.

Это явно неправильно, потому что ориентация 0 градусов, например, уже связана с горизонтальным ребром, и она не может использоваться для представления чего-то еще, такого как область без краев, и поэтому область, где ориентация бессмысленна.

// original code by https://stackoverflow.com/users/951860/mevatron
// see /questions/170726/opencv-counting-non-directional-edges-from-canny/966378#966378
// https://stackoverflow.com/users/15485/uvts-cvs added the code for saving x and y gradient component 

#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("x", mat2gray(Sx));
    imshow("y", mat2gray(Sy));

    imwrite("hor.png",mat2gray(Sx));
    imwrite("ver.png",mat2gray(Sy));

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

    return 0;
}

Ответ 2

Градиент функции двух переменных x, y является вектором частных производных по направлениям x и y. Поэтому, если ваша функция f (x, y), градиент - это вектор (f_x, f_y). Изображение представляет собой дискретную функцию (x, y), поэтому вы можете также говорить о градиенте изображения.

Градиент изображения имеет две компоненты: x-производную и y-производную. Таким образом, вы можете думать об этом как о векторах (f_x, f_y), определенных на каждом пикселе. Эти векторы имеют направление atan (f_y/fx) и величину sqrt (f_x ^ 2 + f_y ^ 2). Таким образом, вы можете представить градиент изображения как изображения x-производной, так и изображения y-производной, или как изображение направления и изображение величины.