Как вычислить тензор структуры изображения с помощью OpenCV

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

Я хотел бы взять изображение, разделить его на сетку подизображений, например, сетку 4х4 (всего 16 подизображений), а затем найти направление ведущего градиента каждой ячейки. Чтобы найти ведущее направление градиента, я хочу посмотреть, может ли вычисление тензора структуры для каждой ячейки дать хорошее представление о градиенте изображения и привести к улучшению сопоставления изображения. Это хорошая идея или плохая идея? Идея заключалась в том, чтобы получить вектор признаков, аналогичный идее в разделе 3.2 этой статьи. http://cybertron.cg.tu-berlin.de/eitz/pdf/2009_sbim.pdf

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

Mat dx, dy;
Sobel(im, dx, CV_32F, 1, 0, 3, 1, 0, BORDER_DEFAULT);
Sobel(im, dy, CV_32F, 0, 1, 3, 1, 0, BORDER_DEFAULT);

Вычисление dx ^ 2, dy ^ 2 и dxy не должно быть проблемой, но я не уверен, как я могу вычислить матрицу тензора структуры и использовать матрицу тензора, чтобы найти основное направление градиента для изображения или подизображения. Как я могу реализовать это с OpenCV?

РЕДАКТИРОВАТЬ
Хорошо, это то, что я сделал.

    Mat _im; // Image to compute main gradient direction for.
cvtColor(im, _im, CV_BGR2GRAY);
GaussianBlur(_im, _im, Size(3, 3), 0, 0, BORDER_DEFAULT); //Blur the image to remove unnecessary details.
GaussianBlur(_im, _im, Size(5, 5), 0, 0, BORDER_DEFAULT);
GaussianBlur(_im, _im, Size(7, 7), 0, 0, BORDER_DEFAULT);

// Calculate image derivatives
Mat dx2, dy2, dxy;
Sobel(_im, dx2, CV_32F, 2, 0, 3, 1, 0, BORDER_DEFAULT);
Sobel(_im, dy2, CV_32F, 0, 2, 3, 1, 0, BORDER_DEFAULT);
Sobel(_im, dxy, CV_32F, 1, 1, 3, 1, 0, BORDER_DEFAULT);

Mat t(2, 2, CV_32F); // tensor matrix

// Insert values to the tensor matrix.
t.at<float>(0, 0) = sum(dx2)[0];
t.at<float>(0, 1) = sum(dxy)[0];
t.at<float>(1, 0) = sum(dxy)[0];
t.at<float>(1, 1) = sum(dy2)[0];

// eigen decomposition to get the main gradient direction.
Mat eigVal, eigVec;
eigen(t, eigVal, eigVec);

// This should compute the angle of the gradient direction based on the first eigenvector.
float* eVec1 = eigVec.ptr<float>(0);
float* eVec2 = eigVec.ptr<float>(1);
cout << fastAtan2(eVec1[0], eVec1[1]) << endl;
cout << fastAtan2(eVec2[0], eVec2[1]) << endl;

Правильный ли этот подход?


Используя это изображение, приложение выводит 44.9905, 135.01.

Это дает 0, 90.



Когда я использую часть реального изображения, я получаю 342,743, 72,7425, что я нахожу странным. Я ожидал получить угол по изменению цвета (90 градусов).

После тестирования я не уверен, что моя реализация верна, поэтому любые отзывы или комментарии по этому поводу приветствуются.

1

Решение

Я считаю, что ваша проблема в том, что вы вычисляете производные второго порядка вместо того, чтобы возводить в квадрат производные первого порядка. Вместо этого должно быть что-то вроде этого:

// Calculate image derivatives
Mat dx, dy;
Mat dx2, dy2, dxy;
Sobel(_im, dx, CV_32F, 1, 0);
Sobel(_im, dy, CV_32F, 0, 1);
multiply(dx, dx, dx2);
multiply(dy, dy, dy2);
multiply(dx, dy, dxy);

Постскриптум
О, кстати, нет необходимости делать размытие по Гауссу снова и снова. Просто используйте более крупное ядро ​​и размывайте один раз.
Д.С.

1

Другие решения


По вопросам рекламы [email protected]