2015-12-10 28 views
5

Ich muss die Formen erkennen und das Auftreten jeder Form im Bild zählen.Ich erkannte zunächst die Konturen und genähert sie, und zählte die Scheitelpunkte in jeder der vorhandenen Kontur.Mein Code aussieht wie folgt aus:Erkennen Sternform in opencv-Python

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 

Arbeit Mein Code tut in diesem Bild die Sterne zum Nachweis:

Image with stars and other basic shapes

Welche Änderungen sollte ich im Code machen?

+2

von (dichten oder spärlichen) Kontur, versuchen Sie Matc hShape-Funktion: 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

Sie können _circularity_ verwenden, um Shapes zu erkennen: '(4 * pi * area)/(perimeter^2)'. Sternformen haben eine Kreisform um 0,25, zum Beispiel – Miki

Antwort

3

Was für mich funktionierte, war ein Vergleich zwischen der Quadratwurzel der Fläche über den Umfang der Form. Es ist ungefähr 0,145 für einen Stern (+/- 0,0015, weil einige der Kanten nicht perfekt herausgekommen sind). 0,255 für das Sechseck, 0,21 für die Dreiecke, 0,247 für das Quadrat und 0,250 für das Pentagon.

Circularity funktioniert auch (die hat die Dreiecke bei 0.26 bis .27), und es unterscheidet sich ähnlich (.83 für das Sechseck, .55-.56 für das Dreieck, .77 für das Quadrat, und. 78 für das Fünfeck)

Unten ist der C++ Code für sie (ich habe nicht python auf meinem PC hier, aber die Idee ist die gleiche):

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

} 

beiden Wege - entweder mit Zirkularität oder meinem sqrt (area)/arclength-Methode - Ergebnis in: image with stars highlighted

+1

Vielen Dank! Es hat geholfen :) –