So apologies for the length of code here. Basically I have used opencv to analyse an image of 7 shapes and read 4 features from it.
The problem is that the code is only giving me out arrays for 5 shapes and I'm unsure why. I have left out the imports etc at the start to shorten the code.
img = cv2.imread("C:\\Users\\telli\\Desktop\\Shapetest.jpg")
#print(img)
#Converting the image to Grayscale
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(grey,127,255,1)
im2,contours, h = cv2.findContours(thresh, 1, cv2.CHAIN_APPROX_SIMPLE)
contours.sort(key = len)
numberOfSides = []
corners = []
standardDeviationsPerimeter = []
sidesDividedByPerimeter = []
standardDeviationsAngles = []
largestAngles = []
angles = []
perimeters = []
featureVectors = []
#finding all the possible circles in the image (likely many false positives)
circles = cv2.HoughCircles(grey,cv2.HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
#finding sides
count = 0;
#print("New perimeter")
for contour in contours:
#remove double recognitions due to thick lines
if count %2 == 0:
epsilon = 10
x, y, w, h = cv2.boundingRect(contour)
x-= epsilon
y-= epsilon
w+= 2 *epsilon
h+= 2 * epsilon
insideCircle = False
#Removing false positive circles by testing each circle against
#the bounding box of this contour
#if we find a circle that is COMPLETELY inside the bounding box
#we have found a circle
for possibleCircle in range (0, len(circles[0])):
centreX = circles[0][possibleCircle][0]
centreY = circles[0][possibleCircle][1]
radius = circles[0][possibleCircle][2]
ToRight = centreX - radius >= x
ToLeft = centreX + radius <= x + w
ToBottom = centreY - radius >= y
ToTop = centreY + radius <= y + h
insideCircle = insideCircle or ToRight and ToLeft and ToBottom and ToTop
#Finding the perimeter of the shapes
perim = cv2.arcLength(contour, True)
perimeters.append(perim)
#if we found that this contour is a circle then the number of sides is 1
if insideCircle:
numberOfSides.append(1)
#use the number of corners found in the contours to determine how many
#sides it has
else:
corner = cv2.approxPolyDP(contour, 0.01 * perim, True)
corners.append(corner)
numberOfSides.append(len(corner))
#print(numberOfSides)
count = count + 1
#finding angles in shape
for shape in range(0, len(corners)):
angles.append([])
sidesDividedByPerimeter.append([])
for corner in range(0, len(corners[shape])):
# 3 vertices we need to find the angle at vertice b
ax = corners[shape][corner % len(corners[shape])][0][0]
ay = corners[shape][corner % len(corners[shape])][0][1]
bx = corners[shape][(corner + 1) % len(corners[shape])][0][0]
by = corners[shape][(corner + 1) % len(corners[shape])][0][1]
cx = corners[shape][(corner + 2) % len(corners[shape])][0][0]
cy = corners[shape][(corner + 2) % len(corners[shape])][0][1]
#print ("A: ", ax, ", ", ay, "\tB: ", bx, ", ", by, "\tC: ", cx, ", ", cy)
dirBAx = ax - bx
dirBAy = ay - by
dirBCx = cx - bx
dirBCy = cy - by
#do dot product and find angle in degrees
dot = dirBAx * dirBCx + dirBAy * dirBCy
lengthBC = math.sqrt(dirBCx * dirBCx + dirBCy * dirBCy)
lengthBA = math.sqrt(dirBAx * dirBAx + dirBAy * dirBAy)
angle = math.acos(dot / (lengthBC * lengthBA))
angle = angle * 180 / math.pi
angles[shape].append(angle)
sidesDividedByPerimeter[shape].append(lengthBC / perimeters[shape])
#print(lengthBC / perimeters[shape])
#print(angle)
#finding max of all angles in each shape
for shape in range(0, len(angles)):
largestAngles.append(np.amax(angles[shape]))
#print(largestAngles)
#if len(approx) == 16:
# cv2.drawContours(img, [contours[0]], 0, (0,0,255), -1)
#Calculating the standard deviation of the sides divided by the perimeter
#print("Standard Devs")
for shape in range(0, len(sidesDividedByPerimeter)):
standarddevPerim = statistics.stdev(sidesDividedByPerimeter[shape])
#Caluclating the standard deviation of the angles of each shape
standarddevAngle = statistics.stdev(angles[shape])
standardDeviationsPerimeter.append(standarddevPerim)
standardDeviationsAngles.append(standarddevAngle)
for shape in range(0, len(sidesDividedByPerimeter)):
featureVectors.append([])
featureVectors[shape].append(numberOfSides[shape])
featureVectors[shape].append(standardDeviationsPerimeter[shape])
featureVectors[shape].append(standardDeviationsAngles[shape])
featureVectors[shape].append(largestAngles[shape])
print(featureVectors)
And featureVector prints out this:
[[4, 0.001743713493735165, 0.6497055601752815, 90.795723552739275],
[4, 0.0460937435599832, 0.19764217920409227, 90.204147248752378],
[1, 0.001185534503063044, 0.3034913722821194, 60.348908179729023],
[1, 0.015455289770298222, 0.8380914254332884, 109.02120657826231],
[3, 0.0169961646358455, 41.36919146079211, 136.83829993466398]]
However there should be 7 shapes.
What i cant figure out is where to append blank values for the 2nd/3rd/4th feature for a circle and allow the program to continue running. It currently appears to be giving the 2nd/3rd/4th value from the next two shapes to the circles.
Aucun commentaire:
Enregistrer un commentaire