Come rilevare gradienti e bordi nelle immagini?


17

Voglio essere in grado di trovare punti nelle immagini che sono al centro di un gradiente radiale come quello mostrato nella figura a sinistra in basso. Qualche idea su come potrei usare una trasformazione di Hough o qualche altro metodo di visione artificiale?

Grazie

inserisci qui la descrizione dell'immagine

immagine di ricerca di esempio:

inserisci qui la descrizione dell'immagine


Ottima domanda!
Spacey

Inoltre, dai un'occhiata a Roberts 'Cross: ( en.wikipedia.org/wiki/Roberts_Cross ) come esempio di un modo per stimare i gradienti.
Spacey

sembra un operatore di sobel più piccolo. Non sono sicuro di come usarlo per trovare un gradiente radiale
waspinator

@waspinator: bene hai eseguito un operatore sobel sulla tua immagine e guardato l'output? È come l'equivalente 2D di prendere la derivata di una funzione 1D, quindi dovrebbe incrociare 0 ai minimi o ai massimi locali?
endolith

1
Per un semplice approccio simile a quello di Hough che probabilmente funzionerebbe, potresti provare questo: per ogni pixel dell'immagine, calcola la direzione del gradiente e rendi un segmento di linea corta nella direzione del gradiente a partire da questo pixel in un accumulatore. I punti centrali che stai cercando dovrebbero essere i picchi più alti nell'accumulatore (con un ampio margine).
koletenbert,

Risposte:


7

Lavoravo a cielo aperto e cercavo di trovare il picco di un gradiente generato dalla trasformazione della distanza. Mi sono reso conto che l'uso di operazioni morfologiche (erosione / dilatazione) nelle immagini in grigio scuro è stato molto utile in questo caso. Se si erode dilatate un'immagine in scala di grigi, qualsiasi pixel assumerà il valore del vicino più basso / più alto. È quindi possibile trovare picchi di intensità in gradienti sottraendo l'immagine in scala di grigi dalla stessa immagine dilatata / erosa. Ecco il mio risultato: inserisci qui la descrizione dell'immagine

E un modo per farlo in 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;
}

5

Ecco quello che ho finora. Il modo in cui sto popolando il mio spazio Hough è tutt'altro che ottimale. Sono abbastanza sicuro che ci sia qualche vettorializzazione che posso fare per renderlo più veloce. Sto usando Matlab R2011a. Immagine originale

I suggerimenti sono apprezzati, grazie.

inserisci qui la descrizione dell'immagine

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)

Ho modificato una funzione della linea di disegno che ho trovato su matlab central per incrementare di un pixel di un valore invece di impostare un pixel su un valore

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
% scuteejtian@hotmail.com
% 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

Penso che attribuirò la generosità alla tua risposta, poiché nessun altro si è preso la briga di contribuire. Non è esattamente quello che voglio, ma è il più vicino dei 3. Hai ulteriormente migliorato questo metodo?
Cape Code

1

Esegui un istogramma di gradienti orientati su patch dell'immagine: il picco in ciascuno di quegli istogrammi ti darà la direzione dominante di quel patch (come le frecce che mostri).

Trova dove si incrociano tutte quelle frecce: se quel punto si trova all'interno dell'oggetto, potrebbe essere il centro di un gradiente radiale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.