Jak wykryć gradienty i krawędzie na obrazach?

17

Chcę być w stanie znaleźć punkty na obrazach, które są środkiem gradientu radialnego, jak ten pokazany na lewym zdjęciu poniżej. Jakieś pomysły na to, jak mogę zastosować transformację Hougha lub inną metodę wizji komputerowej?

Dzięki

wprowadź opis zdjęcia tutaj

przykładowy obraz wyszukiwania:

wprowadź opis zdjęcia tutaj

waspinator
źródło
Świetne pytanie!
Spacey
Spójrz także na Roberts 'Cross: ( en.wikipedia.org/wiki/Roberts_Cross ) jako przykład sposobu oszacowania gradientów.
Spacey
wygląda jak mniejszy operator sobel. Nie jestem jednak pewien, jak tego użyć, aby znaleźć gradient radialny
waspinator
@waspinator: dobrze, czy użyłeś operatora sobel na swoim zdjęciu i spojrzałeś na wynik? To jest jak ekwiwalent 2D pobierania pochodnej funkcji 1D, więc powinna przekraczać 0 przy lokalnych minimach lub maksimach?
endolith,
1
Aby zastosować proste podejście podobne do Hougha, które prawdopodobnie zadziałałoby, możesz spróbować: dla każdego piksela obrazu obliczyć kierunek gradientu i renderować segment krótkiej linii w kierunku gradientu, zaczynając od tego piksela, do akumulatora. Punkty centralne, których szukasz, powinny być najwyższymi pikami w akumulatorze (z dużym marginesem).
koletenbert

Odpowiedzi:

7

Pracowałem w opencv i próbowałem znaleźć pik gradientu wygenerowany przez transformację odległości. Uświadomiłem sobie, że zastosowanie operacji morfologicznych (erozja / dylatacja) w obrazach w skali szarości było w tym przypadku bardzo przydatne. Jeśli erodujesz, rozszerzasz obraz w skali szarości, każdy piksel przyjmie wartość dolnego / najwyższego sąsiada. Można zatem znaleźć szczyty intensywności w gradientach, odejmując obraz w skali szarości od tego samego obrazu rozszerzonego / zerodowanego. Oto mój wynik: wprowadź opis zdjęcia tutaj

I sposób, aby to zrobić w OpenCV / Cpp:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

int main( int argc, char** argv ){

    cv::Mat objects, img ,peaks,BGR;
    std::vector<std::vector<cv::Point> > contours;
    /* Reads the image*/
    BGR=cv::imread(argv[1]);
    /* Converts it to Grayscale*/
    cv::cvtColor(BGR,img,CV_BGR2GRAY);
    /* Devine where are the objects*/
    cv::threshold(img,objects,0,255,cv::THRESH_BINARY);
    /* In order to find the local maxima, "distance"
     * is subtracted from the result of the dilatation of
     * "distance". All the peaks keep the save value */
    cv::dilate(img,peaks,cv::Mat(),cv::Point(-1,-1),3);
    cv::dilate(objects,objects,cv::Mat(),cv::Point(-1,-1),3);

    /* Now all the peaks should be exactely 0*/
    peaks=peaks-img;

    /* And the non-peaks 255*/
    cv::threshold(peaks,peaks,0,255,cv::THRESH_BINARY);
    peaks.convertTo(peaks,CV_8U);

    /* Only the zero values of "peaks" that are non-zero
     * in "objects" are the real peaks*/
    cv::bitwise_xor(peaks,objects,peaks);

    /* The peaks that are distant from less than
     * 2 pixels are merged by dilatation */
    cv::dilate(peaks,peaks,cv::Mat(),cv::Point(-1,-1),1);

    /* In order to map the peaks, findContours() is used.
     * The results are stored in "contours" */
    cv::findContours(peaks, contours, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
    /* just draw them and save the image */
    cv::drawContours(BGR,contours,-1,cv::Scalar(255,0,0),-1);
    cv::imwrite("result.png",BGR);

    return 1;
}
Quentin Geissmann
źródło
5

Oto co mam do tej pory. Sposób, w jaki zapełniam przestrzeń Hougha, jest daleki od optymalnego. Jestem pewien, że mogę zrobić wektoryzację, aby przyspieszyć. Używam Matlab R2011a. Oryginalny obraz

Sugestie są mile widziane, dziękuję.

wprowadź opis zdjęcia tutaj

clear all; clc; close all;

%% read in image and find gradient information
img = rgb2gray(imread('123.png'));
[rows, columns] = size(img);
[dx, dy] = gradient(double(img));
[x y] = meshgrid(1:columns, 1:rows);
u = dx;
v = dy;
imshow(img);
hold on
quiver(x, y, u, v)


%% create Hough space and populate
hough_space = zeros(size(img));

for i = 1:columns
  for j = 1:rows

    X1 = i;
    Y1 = j;
    X2 = round(i + dx(j,i));
    Y2 = round(j + dy(j,i));
    increment = 1;

    slope = (Y2 - Y1) / (X2 - X1);
    y_intercept = Y1 - slope * X1;

    X3 = X1 + 5;

    if X3 < columns && X3 > 1
      Y3 = slope * X3 + y_intercept;
      if Y3 < rows && Y3 > 1
        hough_space = func_Drawline(hough_space, Y1, X1, floor(Y3), floor(X3), increment);
      end
    end
  end
end

imtool(hough_space)

Zmodyfikowałem funkcję rysowania, którą znalazłem na centralnym programie Matlab, aby zwiększyć wartość o piksel o wartość zamiast ustawiać piksel na wartość

function Img = func_DrawLine(Img, X0, Y0, X1, Y1, nG)
% Connect two pixels in an image with the desired graylevel
%
% Command line
% ------------
% result = func_DrawLine(Img, X1, Y1, X2, Y2)
% input:    Img : the original image.
%           (X1, Y1), (X2, Y2) : points to connect.
%           nG : the gray level of the line.
% output:   result
%
% Note
% ----
%   Img can be anything
%   (X1, Y1), (X2, Y2) should be NOT be OUT of the Img
%
%   The computation cost of this program is around half as Cubas's [1]
%   [1] As for Cubas's code, please refer  
%   http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=4177  
%
% Example
% -------
% result = func_DrawLine(zeros(5, 10), 2, 1, 5, 10, 1)
% result =
%      0     0     0     0     0     0     0     0     0     0
%      1     1     1     0     0     0     0     0     0     0
%      0     0     0     1     1     1     0     0     0     0
%      0     0     0     0     0     0     1     1     1     0
%      0     0     0     0     0     0     0     0     0     1
%
%
% Jing Tian Oct. 31 2000
% [email protected]
% This program is written in Oct.2000 during my postgraduate in 
% GuangZhou, P. R. China.
% Version 1.0

Img(X0, Y0) = Img(X0, Y0) + nG;
Img(X1, Y1) = Img(X1, Y1) + nG;
if abs(X1 - X0) <= abs(Y1 - Y0)
   if Y1 < Y0
      k = X1; X1 = X0; X0 = k;
      k = Y1; Y1 = Y0; Y0 = k;
   end
   if (X1 >= X0) & (Y1 >= Y0)
      dy = Y1-Y0; dx = X1-X0;
      p = 2*dx; n = 2*dy - 2*dx; tn = dy;
      while (Y0 < Y1)
         if tn >= 0
            tn = tn - p;
         else
            tn = tn + n; X0 = X0 + 1;
         end
         Y0 = Y0 + 1; Img(X0, Y0) = Img(X0, Y0) + nG;
      end
   else
      dy = Y1 - Y0; dx = X1 - X0;
      p = -2*dx; n = 2*dy + 2*dx; tn = dy;
      while (Y0 <= Y1)
         if tn >= 0
            tn = tn - p;
         else
            tn = tn + n; X0 = X0 - 1;
         end
         Y0 = Y0 + 1; Img(X0, Y0) = Img(X0, Y0) + nG;
      end
   end
else if X1 < X0
      k = X1; X1 = X0; X0 = k;
      k = Y1; Y1 = Y0; Y0 = k;
   end
   if (X1 >= X0) & (Y1 >= Y0)
      dy = Y1 - Y0; dx = X1 - X0;
      p = 2*dy; n = 2*dx-2*dy; tn = dx;
      while (X0 < X1)
         if tn >= 0
            tn = tn - p;
         else
            tn = tn + n; Y0 = Y0 + 1;
         end
         X0 = X0 + 1; Img(X0, Y0) = Img(X0, Y0) + nG;
      end
   else
      dy = Y1 - Y0; dx = X1 - X0;
      p = -2*dy; n = 2*dy + 2*dx; tn = dx;
      while (X0 < X1)
         if tn >= 0
            tn = tn - p;
         else
            tn = tn + n; Y0 = Y0 - 1;
         end
         X0 = X0 + 1; Img(X0, Y0) = Img(X0, Y0) + nG;
      end
   end
end
waspinator
źródło
Myślę, że przypisuję nagrodę za twoją odpowiedź, ponieważ nikt inny nie zadał sobie trudu, aby wnieść swój wkład. Nie jest to dokładnie to, czego chcę, ale jest najbliższe z 3. Czy ulepszyłeś tę metodę?
Cape Code
1

Przeprowadź histogram zorientowanych gradientów nad łatami obrazu - pik na każdym z tych histogramów da ci dominujący kierunek tej łatki (podobnie jak pokazywane strzałki).

Znajdź, gdzie przecinają się wszystkie strzałki - jeśli ten punkt znajduje się w obiekcie, może to być środek gradientu promieniowego.

Martin Thompson
źródło