Wie erkennt man Farbverläufe und Kanten in Bildern?

17

Ich möchte in der Lage sein, Punkte in Bildern zu finden, die der Mittelpunkt eines radialen Verlaufs sind, wie im linken Bild unten gezeigt. Irgendwelche Ideen, wie ich eine Hough-Transformation oder eine andere Computer-Vision-Methode verwenden könnte?

Vielen Dank

Bildbeschreibung hier eingeben

Beispiel für ein Suchbild:

Bildbeschreibung hier eingeben

Waspinator
quelle
Gute Frage!
Spacey
Schauen Sie sich auch Roberts 'Cross an: ( en.wikipedia.org/wiki/Roberts_Cross ) als Beispiel für die Schätzung von Verläufen.
Spacey
sieht aus wie ein kleinerer Sobel-Operator. Ich bin mir nicht sicher, wie ich das verwenden soll, um einen radialen Gradienten zu finden
waspinator
@waspinator: na hast du einen sobel operator auf deinem image ausgeführt und die ausgabe angeschaut? Es ist wie das 2D-Äquivalent der Ableitung einer 1D-Funktion, also sollte es bei den lokalen Minima oder Maxima 0 kreuzen?
Endolith
1
Für einen einfachen Hough-ähnlichen Ansatz, der wahrscheinlich funktionieren würde, könnten Sie Folgendes versuchen: Berechnen Sie für jedes Pixel des Bildes die Verlaufsrichtung und rendern Sie ein kurzes Liniensegment in Richtung des Verlaufs, das bei diesem Pixel beginnt, in einen Akkumulator. Die Mittelpunkte, die Sie suchen, sollten die höchsten Peaks im Akkumulator sein (mit großem Abstand).
Koletenbert

Antworten:

7

Ich habe in opencv gearbeitet und versucht, die Spitze eines Gradienten zu finden, der durch Distanztransformation erzeugt wurde. Ich erkannte, dass morphologische Operationen (Erosion / Dilatation) in Graustufenbildern in diesem Fall sehr nützlich waren. Wenn Sie ein Graustufenbild aushöhlen, nimmt jedes Pixel den Wert des unteren / höchsten Nachbarn an. Sie können daher Intensitätspeaks in Verläufen finden, indem Sie das Graustufenbild von demselben erweiterten / erodierten Bild subtrahieren. Hier ist mein Ergebnis: Bildbeschreibung hier eingeben

Und eine Möglichkeit, dies in OpenCV / Cpp zu tun:

#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
quelle
5

Folgendes habe ich bisher. Die Art und Weise, wie ich meinen Hough-Raum bevölkere, ist alles andere als optimal. Ich bin mir ziemlich sicher, dass ich etwas Vektorisierung tun kann, um es schneller zu machen. Ich benutze Matlab R2011a. Original Bild

Vorschläge werden geschätzt, danke.

Bildbeschreibung hier eingeben

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)

Ich habe eine Zeichnungslinienfunktion, die ich in matlab central gefunden habe, geändert, um sie um einen Wert um ein Pixel zu erhöhen, anstatt ein Pixel auf einen Wert zu setzen

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
quelle
Ich denke, ich werde das Kopfgeld Ihrer Antwort zuschreiben, da sich sonst niemand die Mühe gemacht hat, einen Beitrag zu leisten. Es ist nicht genau das, was ich will, aber es ist das nächste der 3. Haben Sie diese Methode weiter verbessert?
Cape Code
1

Führen Sie ein Histogramm mit orientierten Verläufen über Bildbereiche aus. Der Peak in jedem dieser Histogramme gibt Ihnen die dominante Richtung dieses Bereichs an (wie die Pfeile, die Sie anzeigen).

Finden Sie heraus, wo sich all diese Pfeile schneiden. Wenn sich dieser Punkt innerhalb des Objekts befindet, kann er der Mittelpunkt eines radialen Verlaufs sein.

Martin Thompson
quelle