¿Cómo detectar gradientes y bordes en imágenes?

17

Quiero poder encontrar puntos en imágenes que son el centro de un degradado radial como el que se muestra en la imagen de la izquierda a continuación. ¿Alguna idea sobre cómo podría usar una transformación Hough o algún otro método de visión por computadora?

Gracias

ingrese la descripción de la imagen aquí

ejemplo de imagen de búsqueda:

ingrese la descripción de la imagen aquí

Waspinator
fuente
Gran pregunta!
Spacey
Además, eche un vistazo a Roberts 'Cross: ( en.wikipedia.org/wiki/Roberts_Cross ) como un ejemplo de una forma de estimar gradientes.
Spacey
se parece a un operador sobel más pequeño. Sin embargo
waspinator
@waspinator: bueno, ¿has ejecutado un operador sobel en tu imagen y miraste la salida? Es como el equivalente 2D de tomar la derivada de una función 1D, por lo que debería cruzar 0 en los mínimos o máximos locales.
endolito el
1
Para un enfoque simple similar a Hough que probablemente funcionaría, podría intentar esto: para cada píxel de la imagen, calcule la dirección del gradiente y renderice un segmento de línea corta en la dirección del gradiente que comienza en este píxel en un acumulador. Los puntos centrales que está buscando deben ser los picos más altos en el acumulador (por un amplio margen).
koletenbert

Respuestas:

7

Estaba trabajando en opencv y tratando de encontrar el pico de un gradiente generado por la transformación de distancia. Me di cuenta de que el uso de operaciones morfológicas (erosión / dilatación) en imágenes grises-scsale era muy útil en este caso. Si erosiona dilatar una imagen en escala de grises, cualquier píxel tomará el valor del vecino más bajo / más alto. Por lo tanto, puede encontrar picos de intensidad en gradientes restando la imagen en escala de grises de la misma imagen dilatada / erosionada. Aquí está mi resultado: ingrese la descripción de la imagen aquí

Y una forma de hacerlo en 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
fuente
5

Esto es lo que tengo hasta ahora. La forma en que estoy poblando mi espacio Hough está lejos de ser óptima. Estoy bastante seguro de que hay algo de vectorización que puedo hacer para hacerlo más rápido. Estoy usando Matlab R2011a. Imagen original

Se agradecen las sugerencias, gracias.

ingrese la descripción de la imagen aquí

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)

Modifiqué una función de línea de dibujo que encontré en matlab central para aumentar un píxel por un valor en lugar de establecer un píxel en un 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
fuente
Creo que atribuiré la recompensa a tu respuesta, ya que nadie más se molestó en contribuir. No es exactamente lo que quiero, pero es el más cercano de 3. ¿Mejoraste aún más este método?
Código del Cabo
1

Ejecute un histograma de gradientes orientados sobre parches de la imagen: el pico en cada uno de esos histogramas le dará la dirección dominante de ese parche (como las flechas que muestra).

Encuentre dónde se cruzan todas esas flechas: si ese punto está dentro del objeto, podría ser el centro de un degradado radial.

Martin Thompson
fuente