Como detectar gradientes e arestas em imagens?

17

Quero poder encontrar pontos em imagens que são o centro de um gradiente radial, como o mostrado na imagem à esquerda abaixo. Alguma idéia de como eu poderia usar uma transformação de Hough ou algum outro método de visão por computador?

obrigado

insira a descrição da imagem aqui

imagem de pesquisa de exemplo:

insira a descrição da imagem aqui

waspinator
fonte
Ótima pergunta!
Spacey
Além disso, dê uma olhada no Roberts 'Cross: ( en.wikipedia.org/wiki/Roberts_Cross ) como um exemplo de uma maneira de estimar gradientes.
Spacey
parece um operador sobel menor. Eu não tenho certeza de como usá-lo para encontrar um gradiente radial embora
Waspinator
@waspinator: bem, você executou um operador sobel na sua imagem e olhou para a saída? É como o equivalente em 2D de tirar a derivada de uma função 1D, então deve cruzar 0 nos mínimos ou máximos locais?
endolith 1/08/12
1
Para uma abordagem simples do tipo Hough que provavelmente funcionaria, você pode tentar o seguinte: para cada pixel da imagem, calcule a direção do gradiente e processe um segmento de linha curta na direção do gradiente que começa neste pixel em um acumulador. Os pontos centrais que você procura devem ser os picos mais altos no acumulador (por uma grande margem).
koletenbert

Respostas:

7

Eu estava trabalhando no opencv e tentando encontrar o pico de um gradiente gerado pela transformação à distância. Percebi que o uso de operações morfológicas (erosão / dilatação) em imagens em escala de cinza era muito útil nesse caso. Se você corroer uma imagem em escala de cinza dilatada, qualquer pixel assumirá o valor do vizinho mais baixo / mais alto. Portanto, é possível encontrar picos de intensidade em gradientes subtraindo a imagem em escala de cinza da mesma imagem dilatada / corroída. Aqui está o meu resultado: insira a descrição da imagem aqui

E uma maneira de fazer isso no 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
fonte
5

Aqui está o que eu tenho até agora. A maneira como estou preenchendo meu espaço Hough está longe de ser ótima. Tenho certeza de que há alguma vetorização que posso fazer para torná-lo mais rápido. Estou usando o Matlab R2011a. Imagem original

Sugestões são apreciadas, obrigado.

insira a descrição da imagem aqui

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)

Modifiquei uma função de linha de desenho que encontrei no matlab central para aumentar um pixel por um valor em vez de definir um pixel para um valor

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
fonte
Acho que atribuirei a recompensa à sua resposta, pois ninguém mais se deu ao trabalho de contribuir. Não é exatamente o que eu quero, mas é o mais próximo dos 3. Você melhorou ainda mais esse método?
Código do Cabo
1

Execute um histograma de gradientes orientados sobre os trechos da imagem - o pico em cada um desses histogramas fornecerá a direção dominante desse trecho (como as setas que você mostra).

Descubra onde todas essas setas se cruzam - se esse ponto estiver dentro do objeto, poderá ser o centro de um gradiente radial.

Martin Thompson
fonte