2012-06-21 5 views
5

Я разрабатываю проект по идентификации компонентов с использованием пакета javacv (Opencv). Я использовал метод, возвращающий набор прямоугольников на изображении как «CvSeq» Что мне нужно знать, как сделать следующие вещиКак извлечь ширину и высоту контура в javacv?

  • Как я могу получить каждый прямоугольник с выхода методов (от CvSeq)?
  • Как получить длину и ширину прямоугольника?

Это метод, который возвращает прямоугольник

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

Это образец исходного изображения, которые я использовал

enter image description here

И это изображение, которое я получил после того, как рисование линий вокруг соответствующих прямоугольников

enter image description here

На самом деле в изображениях выше, я связываю, чтобы удалить эти большие прямоугольники и просто нужно идентифицировать другие прямоугольники, поэтому мне нужен пример кода, чтобы понять, как архивировать выше цели. Пожалуйста, будьте любезны поделиться своим опытом со мной. Благодаря !

ответ

4

OpenCV находит контуры белых объектов на черном фоне. В вашем случае это наоборот, объекты черные. И таким образом, даже граница изображения также является объектом. Поэтому, чтобы избежать этого, просто измените изображение таким образом, чтобы фон был черным.

Ниже я это показал (с использованием 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) 

Помните, что вместо того, чтобы использовать отдельную функцию для переворачивания, я использовал его в порог. Просто преобразуйте пороговый тип в BINARY_INV (т.е. «1»).

Теперь у вас есть изображение, как показано ниже:

enter image description here

Теперь мы находим контуры. Затем для каждого контура мы приближаем его и проверяем, является ли он прямоугольником, просматривая длину приближенного контура, который должен быть четыре для прямоугольника.

Если нарисован, вы получите как это:

enter image description here

И в то же время, мы также находим ограничивающий прямоугольник каждого контура. Ограничительный прямоугольник имеет такую ​​форму: [начальная точка x, начальная точка y, ширина прямоугольника, высота прямоугольника]

Таким образом, вы получаете ширину и высоту.

Ниже приведен код:

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:

После некоторых замечаний, я понял, что истинная цель этого вопроса, чтобы избежать больших прямоугольников и выбрать только мелкие.

Это можно сделать с использованием граничных значений прямоугольника, которые мы получили. т.е. выберите только те прямоугольники, длина которых меньше порогового значения, или ширины или области. Например, на этом изображении я взял область, которая должна быть меньше 10000. (Грубая оценка). Если оно меньше 10000, оно должно быть выбрано, и мы будем обозначать его красным цветом, в противном случае - ложным кандидатом, представленным синим цветом (только для визуализации).

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) 

Ниже выход я получил:

enter image description here

Как получить, что пороговое значение? :

Это полностью зависит от вас и вашего приложения. Или вы можете найти его методом проб и ошибок. (я сделал это).

Надеюсь, что решает вашу проблему. Все функции являются стандартными opencv-функциями. Так что, я думаю, вы не найдете никаких проблем для преобразования в JavaCV.

+0

На самом деле мне нужно удалить два больших прямоугольников в стороне изображения и другие маленькие прямоугольники должны быть идентифицированы. Пожалуйста, объясните, как это сделать с помощью javacv. –

+0

Прошу прощения, я не понял. Может быть, вы можете нарисовать квадрат, который вам нужен зеленым цветом, используя краску, и загрузить где-нибудь и дать ссылку здесь. –

+2

K, я получил его .. вам нужны только маленькие прямоугольники и избежать больших прямоугольников, не так ли? вы можете избежать их, если их длина или ширина больше некоторого порогового значения. –

2

Просто заметил, что есть ошибка в коде содержится в вопросе:

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

Это означает, что если есть один канал, tgray будет пустым образом. Должно быть:

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

 Смежные вопросы

  • Нет связанных вопросов^_^