problem in python findContours() with connected and disconnected shapes [closed]

asked 2014-01-15 04:53:31 -0500

Francesco Sgaramella gravatar image

updated 2017-11-12 06:21:34 -0500

Hello everybody, I am running a project in python involving recognition of shapes in images and creation of a graph out of the recognition. The script should be as more general as possible in order to create a graph out of any image given in input. The approach I used is to find the contours of the shapes and re-draw them into a new image. However I am having some troubles when for example the image contains a circle connected to a line: in this case the line is lost and not drawn in the graph. I show you what I mean:

this is the input picture (please don't laught about it):

input image

After the processing, the graph created is this:

output graph

It is noticeable that the line of the left "arm" is missing and after a all afternoon of trial, I didn't get to anything. Moreover, Also the "smile" is recognized as pentagon even if the shape is disconnected.

The code written in python is a little ugly because I am not such an expert in python programming, so please excuse me for that:

import numpy as np
import cv2
import Image, ImageDraw
import math

#Function to find a cosine of angle between vectors
#from pt0->pt1 and pt0->pt2
def angle_cos(p1, p2, p0):
    dx1 = (p1[0]-p0[0]).astype('double')
    dy1 = (p1[1]-p0[1]).astype('double')
    dx2 = (p2[0]-p0[0]).astype('double')
    dy2 = (p2[1]-p0[1]).astype('double')
    return (dx1*dx2 + dy1*dy2) / np.sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10)

#function to create the final graph
def create_graph(vertex, color):
    for g in range(0, len(vertex)-1):
        for y in range(0, len(vertex[0][0])-1):
            cv2.circle(newimg, (vertex[g][0][y], vertex[g][0][y+1]), 3, (255,255,255), -1)
            cv2.line(newimg, (vertex[g][0][y], vertex[g][0][y+1]), (vertex[g+1][0][y], vertex[g+1][0][y+1]), color, 2)
    cv2.line(newimg, (vertex[len(vertex)-1][0][0], vertex[len(vertex)-1][0][1]), (vertex[0][0][0], vertex[0][0][1]), color, 2)

#Routine
img = cv2.imread('draw.jpg')
cv2.imshow('starting picture', img)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#Remove of noise, if any
blur = cv2.GaussianBlur(gray, (5,5), 0)

#Create a new image of the same size of the starting image
height, width = gray.shape
newimg = np.zeros((height, width, 3), np.uint8)

#Edge detector
thresh = 175
edges = cv2.Canny(blur, thresh, thresh*2)

#Find contours
contours,hierarchy = cv2.findContours(edges, cv2.cv.CV_RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
for b,cnt in enumerate(contours):
    if hierarchy[0,b,3] == -1: #Avoid inner contours
        approx = cv2.approxPolyDP(cnt,0.025*cv2.arcLength(cnt,True), True)
        if len(approx)==5:
            if cv2.isContourConvex(approx):
                print "pentagon" + " with area = " +str(cv2.contourArea(cnt))
                clr = (255, 0, 0)
                cv2.drawContours(img,[cnt],-1, clr,-1)
                #draw the pentagon in the new image
                create_graph(approx, clr)
            else:
                print ...
(more)
edit retag flag offensive reopen merge delete

Closed for the following reason question is not relevant or outdated by sturkmen
close date 2020-10-10 13:59:15.579180