2012-06-21 15 views
5

Ich entwickle ein Projekt zur Identifizierung von Komponenten mit dem Javacv-Paket (Opencv). Ich eine Methode verwendet, um Rückkehr der Rechtecke auf dem Bild gesetzt als „CvSeq“ Was ich wissen muss, ist, wie folgende Dinge zu tunWie extrahiert man Breite und Höhe der Kontur in javacv?

  • Wie kann ich jedes Rechteck von Methoden Ausgabe zu erhalten (von CvSeq)?
  • Wie auf die Längen und die Breite des Rechtecks ​​zugreifen?

Dies ist die Methode, die die Rechtecke

public static CvSeq findSquares(final IplImage src, CvMemStorage storage) 
{ 

CvSeq squares = new CvContour(); 
squares = cvCreateSeq(0, sizeof(CvContour.class), sizeof(CvSeq.class), storage); 

IplImage pyr = null, timg = null, gray = null, tgray; 
timg = cvCloneImage(src); 

CvSize sz = cvSize(src.width() & -2, src.height() & -2); 
tgray = cvCreateImage(sz, src.depth(), 1); 
gray = cvCreateImage(sz, src.depth(), 1); 
pyr = cvCreateImage(cvSize(sz.width()/2, sz.height()/2), src.depth(), src.nChannels()); 

// down-scale and upscale the image to filter out the noise 
cvPyrDown(timg, pyr, CV_GAUSSIAN_5x5); 
cvPyrUp(pyr, timg, CV_GAUSSIAN_5x5); 
cvSaveImage("ha.jpg", timg); 
CvSeq contours = new CvContour(); 
// request closing of the application when the image window is closed 
// show image on window 
// find squares in every color plane of the image 
for(int c = 0; c < 3; c++) 
{ 
    IplImage channels[] = {cvCreateImage(sz, 8, 1), cvCreateImage(sz, 8, 1), cvCreateImage(sz, 8, 1)}; 
    channels[c] = cvCreateImage(sz, 8, 1); 
    if(src.nChannels() > 1){ 
     cvSplit(timg, channels[0], channels[1], channels[2], null); 
    }else{ 
     tgray = cvCloneImage(timg); 
    } 
    tgray = channels[c]; // try several threshold levels 
    for(int l = 0; l < N; l++) 
    { 
    //    hack: use Canny instead of zero threshold level. 
    //    Canny helps to catch squares with gradient shading 
        if(l == 0) 
       { 
    //    apply Canny. Take the upper threshold from slider 
    //    and set the lower to 0 (which forces edges merging) 
         cvCanny(tgray, gray, 0, thresh, 5); 
    //     dilate canny output to remove potential 
    //    // holes between edge segments 
         cvDilate(gray, gray, null, 1); 
       } 
       else 
       { 
    //    apply threshold if l!=0: 
         cvThreshold(tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY); 
       } 
    //   find contours and store them all as a list 
       cvFindContours(gray, storage, contours, sizeof(CvContour.class), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); 

       CvSeq approx; 

    //   test each contour 
       while (contours != null && !contours.isNull()) { 
         if (contours.elem_size() > 0) { 
          approx = cvApproxPoly(contours, Loader.sizeof(CvContour.class),storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0); 
        if(approx.total() == 4 
          && 
          Math.abs(cvContourArea(approx, CV_WHOLE_SEQ, 0)) > 1000 && 
         cvCheckContourConvexity(approx) != 0 
         ){ 
         double maxCosine = 0; 
         // 
         for(int j = 2; j < 5; j++) 
         { 
      //   find the maximum cosine of the angle between joint edges 
         double cosine = Math.abs(angle(new CvPoint(cvGetSeqElem(approx, j%4)), new CvPoint(cvGetSeqElem(approx, j-2)), new CvPoint(cvGetSeqElem(approx, j-1)))); 
         maxCosine = Math.max(maxCosine, cosine); 
         } 
         if(maxCosine < 0.2){ 
          cvSeqPush(squares, approx); 
         } 
        } 
       } 
       contours = contours.h_next(); 
      } 
     contours = new CvContour(); 
    } 
} 
return squares; 
} 

Dies ist die Probe Originalbild zurückgibt, die ich

enter image description here

verwendet Und das ist das Bild, das ich nach dem Zeichnen von Linien bekam um die passenden Rechtecke

enter image description here

Eigentlich bin ich in den obigen Bildern gebunden, um diese großen Rechtecke zu entfernen und nur andere Rechtecke zu identifizieren, also brauche ich ein Codebeispiel, um zu verstehen, wie man obige Ziele archiviert. Bitte sei so freundlich, deine Erfahrungen mit mir zu teilen. Vielen Dank !

Antwort

4

OpenCV findet Konturen der weißen Objekte in schwarzem Hintergrund. In Ihrem Fall ist es umgekehrt, Objekte sind schwarz. Und so ist auch die Bildgrenze ein Objekt. Um dies zu vermeiden, kehren Sie das Bild einfach so um, dass der Hintergrund schwarz ist.

Below I gezeigt haben (unter Verwendung von OpenCV-Python):

import numpy as np 
import cv2 

im = cv2.imread('sofsqr.png') 
img = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) 

ret,thresh = cv2.threshold(img,127,255,1) 

bleiben, anstelle von zum Invertieren seperate Funktion verwendete ich es in Schwelle. Konvertieren Sie den Schwellenwerttyp einfach in BINARY_INV (dh '1').

Jetzt haben Sie ein Bild wie folgt:

enter image description here

Nun wir die Konturen finden. Dann approximieren wir es für jede Kontur und prüfen, ob es ein Rechteck ist, indem wir die Länge der angenäherten Kontur betrachten, die für ein Rechteck vier sein sollte.

Wenn gezogen, erhalten Sie wie folgt aus:

enter image description here

Und zugleich haben wir auch die begrenzende rect jeder Kontur finden. Das umgebende Rect hat eine Form wie folgt: [Anfangspunkt x, Anfangspunkt y, Breite des Rect, Höhe des Rect]

So erhalten Sie die Breite und Höhe.

Unten ist der Code:

contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) 

for cnt in contours: 
    approx = cv2.approxPolyDP(cnt,cv2.arcLength(cnt,True)*0.02,True) 
    if len(approx)==4: 
     cv2.drawContours(im,[approx],0,(0,0,255),2) 
     x,y,w,h = cv2.boundingRect(cnt) 

EDIT:

Nach einigen Kommentaren, ich verstand, dass das eigentliche Ziel der Frage große Rechtecke zu vermeiden ist und nur kleinere wählen.

Es kann getan werden, indem wir rect-Werte verwenden, die wir erhalten haben. dh Wählen Sie nur die Rechtecke aus, deren Länge kleiner als ein Schwellenwert oder Breite oder Fläche ist. Als ein Beispiel, in diesem Bild, sollte ich Bereich sollte weniger als 10000 sein. (Eine grobe Schätzung). Wenn es kleiner als 10000 ist, sollte es ausgewählt werden und wir bezeichnen es in roter Farbe, ansonsten als falschen Kandidaten, dargestellt in blauer Farbe (nur zur Visualisierung).

for cnt in contours: 
    approx = cv2.approxPolyDP(cnt,cv2.arcLength(cnt,True)*0.02,True) 
    if len(approx)==4: 
     x,y,w,h = cv2.boundingRect(approx) 
     if w*h < 10000: 
      cv2.drawContours(im,[approx],0,(0,0,255),-1) 
     else: 
      cv2.drawContours(im,[approx],0,(255,0,0),-1) 

Unten ist der Ausgang i bekam:

enter image description here

Wie diesen Schwellenwert bekommen? :

Es hängt vollständig von Ihnen und Ihrer Anwendung ab. Oder Sie können es durch Versuch und Irrtum Methoden finden. (Ich habe es so gemacht).

Hoffnung, die Ihr Problem löst. Alle Funktionen sind Standard opencv Funktionen. Also ich denke, Sie werden kein Problem finden, um JavaCV zu konvertieren.

+0

Eigentlich brauche ich zwei große Rechtecke in Seite zu entfernen, sollte das Bild und andere kleine Rechtecke identifiziert werden. Bitte erklären Sie, wie man das mit javacv macht. –

+0

Es tut mir leid, ich habe es nicht verstanden. Vielleicht kannst du malen, welches Quadrat du in grüner Farbe benötigst und irgendwo hochladen und hier einen Link geben. –

+2

K, ich habe es .. du brauchst nur kleine Rechtecke und meide große Rechtecke, oder? Sie können sie vermeiden, wenn ihre Länge oder Breite größer als ein Schwellenwert ist. –

2

habe gerade bemerkt, dass es einen Fehler in der in der Frage bereitgestellten Code ist:

IplImage channels[] = {cvCreateImage(sz, 8, 1), cvCreateImage(sz, 8, 1), cvCreateImage(sz, 8, 1)}; 
channels[c] = cvCreateImage(sz, 8, 1); 
if(src.nChannels() > 1){ 
    cvSplit(timg, channels[0], channels[1], channels[2], null); 
}else{ 
    tgray = cvCloneImage(timg); 
} 
tgray = channels[c]; 

Das bedeutet, wenn ein einzelner Kanal ist, wird tgray ein leeres Bild sein. Es sollte lauten:

IplImage channels[] = {cvCreateImage(sz, 8, 1), cvCreateImage(sz, 8, 1), cvCreateImage(sz, 8, 1)}; 
channels[c] = cvCreateImage(sz, 8, 1); 
if(src.nChannels() > 1){ 
    cvSplit(timg, channels[0], channels[1], channels[2], null); 
    tgray = channels[c]; 
}else{ 
    tgray = cvCloneImage(timg); 
}