2015-12-10 20 views
5

Muszę wykryć kształty i policzyć występowanie każdego kształtu w obrazie. Najpierw wykryłem kontury i je przybliżyłem, a następnie policzyłem wierzchołki w każdym z obecnych konturów. Wygląda mój kod tak:Wykryj kształt gwiazdy w opencv-pythonie

import cv2 
import numpy as np 
import collections 
import sys 

img = cv2.imread(str(sys.argv[1]),0) 
ret,thresh = cv2.threshold(img,127,255,0) 
contours,hierarchy = cv2.findContours(thresh,1,2) 


no_of_vertices = [] 

i = 0 
mask = np.zeros(img.shape,np.uint8) 
for contour in contours: 

cnt = contour 
area = cv2.contourArea(cnt) 
if area>150: 
    epsilon = 0.02*cv2.arcLength(cnt,True) 
    approx = cv2.approxPolyDP(cnt,epsilon,True) 
    no_of_vertices.append(len(approx)) 



counter = collections.Counter(no_of_vertices) 




a,b = counter.keys(),counter.values() 

i=0 
while i<len(counter): 
    print a[i],b[i] 
    i = i + 1 

Mój kod nie robi praca dla wykrywania gwiazdy w tym obrazie:

Image with stars and other basic shapes

Jakie zmiany należy wprowadzić w kodzie?

+2

z (gęsty lub rzadki) kontur, spróbuj matc Funkcja hShape: http://docs.opencv.org/2.4/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#double%20matchShapes%28InputArray%20contour1,%20InputArray%20contour2,%20int%20method,%20double%20parameter%29 – Micka

+1

Możesz użyć _circularity_ do wykrywania kształtów: '(4 * pi * area)/(obwód^2)'. Kształty gwiazd mają okrągłość około 0,25, na przykład – Miki

Odpowiedz

3

To, co zadziałało, było porównaniem pierwiastka kwadratowego z obszaru ponad obwodem kształtu. To około 0,145 dla gwiazdy (+/- .0015, ponieważ niektóre krawędzie nie wypadły idealnie). 0.255 dla sześciokąta, .21 dla trójkątów, .247 dla kwadratu i .250 dla pięciokąta.

Okrągłość działa również (w trójkątach dochodzi od 0,26 do .27), i podobnie się różnicuje (0,83 dla sześciokąta, 0,55-.56 dla trójkąta, 0,77 dla kwadratu, oraz. 78 do pięciokąta)

Poniżej znajduje się kod C++ dla niego (nie mam Pythona na moim komputerze tutaj, ale idea jest ta sama):

#include "stdafx.h" 
#include <opencv/cxcore.h> 
#include <opencv2\core\mat.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#include <iostream> 
#include <opencv/cxcore.h> 
#include <opencv/highgui.h> 
#include <opencv/cv.h> 
#include <opencv2/opencv.hpp> 
#include <opencv2/core/core.hpp> 

using namespace cv; 
using namespace std; 

RNG rngee(12345); 

int main() { 
    Mat im = imread("C:/this/is.a/path/image.png", CV_LOAD_IMAGE_COLOR); 
    Mat imgrey = im.clone(); 
    cvtColor(im, imgrey, CV_RGB2GRAY); 
    vector<vector<Point> > imContours; 
    vector<Vec4i> hierarchy; 

    double divMaxSize = 0.175, divMinSize = 0.125; 

    namedWindow("Image", CV_WINDOW_NORMAL| CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED); 

    threshold(imgrey, imgrey, 100, 255, 0); 

    findContours(imgrey, imContours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); 

    for (int i=0; i < imContours.size(); i++) { 
     Scalar color = Scalar(rngee.uniform(0, 255), rngee.uniform(0,255), rngee.uniform(0,255)); 
     cout << "sqrt(Area)/arcLength = " << sqrt(contourArea(imContours[i]))/arcLength(imContours[i], true) << endl; 
     if(sqrt(contourArea(imContours[i]))/arcLength(imContours[i], true) < divMaxSize && sqrt(contourArea(imContours[i]))/arcLength(imContours[i], true) > divMinSize) 
     { 
      drawContours(im, imContours, i, color, 2, 8, hierarchy, 0, Point()); 
      cout << "I'm a star!" << endl; 
     } 
     imshow("Image", im); 
     waitKey(0); 
    } 
    imshow("Image", im); 
    waitKey(0); 

} 

Oba sposoby - albo za pomocą cykliczność lub mój metoda sqrt (obszar)/arclength - wynik: image with stars highlighted

+1

Wielkie dzięki! Pomogło :) –