2012-06-21 6 views
5

Pracuję nad projektem identyfikacji komponentów za pomocą pakietu javacv (Opencv). Użyłem metody zwraca zbiór prostokątów na obrazek jako „CvSeq” Co muszę wiedzieć, jak to zrobić następujące rzeczyJak wyodrębnić szerokość i wysokość konturu w javacv?

  • Jak mogę uzyskać każdy prostokąt z wyjściem metod (od CvSeq)?
  • Jak uzyskać dostęp do długości i szerokości prostokąta?

Jest to metoda, która zwraca prostokątów

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; 
} 

Jest to obraz próbka oryginalna, że ​​użyłem

enter image description here

I to jest obraz, który mam po rysowanie linii wokół pasujących prostokątów:

enter image description here

W rzeczywistości na powyższych obrazach przywiązuję do usunięcia tych dużych prostokątów i potrzebuję tylko zidentyfikować inne prostokąty, więc potrzebuję przykładu kodu, aby zrozumieć, jak archiwizować powyższe cele. Proszę być na tyle uprzejmy, aby podzielić się swoim doświadczeniem ze mną. Dzięki !

Odpowiedz

4

OpenCV znajduje kontury białych obiektów na czarnym tle. W twoim przypadku jest odwrotnie, obiekty są czarne. I w ten sposób celem jest nawet granica obrazu. Aby tego uniknąć, po prostu odwróć obraz tak, aby tło było czarne.

Poniżej wykazano, to (przy użyciu OpenCV-Pyton)

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) 

Pamiętaj, zamiast stosowania oddzielnego odwracania funkcji, to stosuje się go w progu. Po prostu zmień typ progu na BINARY_INV (np. "1").

Teraz masz obraz jak poniżej:

enter image description here

Teraz znajdujemy kontury. Następnie dla każdego konturu przybliżamy go i sprawdzamy, czy jest to prostokąt, patrząc na długość przybliżonego konturu, który powinien wynosić cztery dla prostokąta.

Jeśli wyciągnąć, masz tak:

enter image description here

I w tym samym czasie, możemy również znaleźć obwiedni rect każdego konturu. Prostokąt ograniczający ma taki kształt: [punkt początkowy x, punkt początkowy y, szerokość prostokąta, wysokość prostokąta]

Otrzymasz szerokość i wysokość.

Poniżej znajduje się kod:

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:

Po kilku komentarzach, zrozumiałem, że prawdziwym celem tej kwestii jest, aby uniknąć dużych prostokątów i wybierać tylko mniejsze.

Można to zrobić, używając wartości granicznych, które uzyskaliśmy. tj. Wybierz tylko te prostokąty, których długość jest mniejsza niż wartość progowa, szerokość lub powierzchnia. Na przykład na tym zdjęciu zrobiłem obszar mniejszy niż 10000. (Zgrubna ocena). Jeśli jest mniejsza niż 10000, powinna być wybrana, a my oznaczamy ją w kolorze czerwonym, w przeciwnym razie fałszywy kandydat, reprezentowany w kolorze niebieskim (tylko do wizualizacji).

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) 

Poniżej jest wyjście mam:

enter image description here

Jak uzyskać tę wartość progową? :

To całkowicie zależy od Ciebie i Twojej aplikacji. Lub możesz go znaleźć metodą prób i błędów. (Zrobiłem tak).

Mam nadzieję, że rozwiążesz problem. Wszystkie funkcje są standardowymi funkcjami opencv. Więc myślę, że nie znajdziesz żadnych problemów z konwersją do JavaCV.

+0

Właściwie muszę usunąć dwa duże prostokąty z boku obrazu i inne małe prostokąty powinny zostać zidentyfikowane. Czy możesz wyjaśnić, jak to zrobić, używając javacv. –

+0

Przykro mi, nie dostałem tego. Możesz narysować, którego kwadratu potrzebujesz w kolorze zielonym za pomocą farby, i gdzieś załaduj i podaj link tutaj. –

+2

K, mam to ... potrzebujesz tylko małych prostokątów i unikaj dużych prostokątów, prawda? możesz ich uniknąć, jeśli ich długość lub szerokość jest większa niż pewna wartość progowa. –

2

Wystarczy zauważyć, że jest to błąd w kodzie zawarte w pytaniu:

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]; 

Oznacza to, że jeśli jest tylko jeden kanał, będzie tgray być pusty obraz. Powinieneś przeczytać:

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); 
} 
Powiązane problemy