Issue
I have the following images:
image without staff lines:
I want to detect the circles / ellipse shapes in the images and get an array of the detected shapes.
I want to detect the large circles and the tiny one.
I tried the following and it fails to detect anything:
img = cv2.imread("1.png", 0)
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1.2, 1, param1=50, param2=30, minRadius=0, maxRadius=0)
but circles returns None. thanks.
thank you to fmw42 but his solution doesn't remove all the noise from the following image:
result:
but it can be managed with area check with some pre determined values
Solution
Here is a better variation in Python/OpenCV. In addition to filtering on area, we can filter on how good a match the shape is of the contour to a fitted ellipse.
Input 1:
Input 2:
import cv2
import numpy as np
# read image
img = cv2.imread('notes.png')
#img = cv2.imread('notes2.png')
# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray,128,255,cv2.THRESH_BINARY)[1]
# do morphology remove horizontal lines
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,5))
lines1 = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, kernel, iterations = 1)
# do morphology to remove vertical lines
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,1))
lines2 = cv2.morphologyEx(lines1, cv2.MORPH_CLOSE, kernel, iterations = 1)
lines2 = cv2.threshold(lines2,128,255,cv2.THRESH_BINARY)[1]
# invert lines2
lines2 = 255 - lines2
# get contours
cntrs = cv2.findContours(lines2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
# filter contours on area and draw good ones as black filled on white background
result = np.full_like(img, (255,255,255))
for cntr in cntrs:
area = cv2.contourArea(cntr)
if area > 9 and area < 400:
# get centroid
M = cv2.moments(cntr)
cx = M["m10"] / M["m00"]
cy = M["m01"] / M["m00"]
pt="(" + str(cx) + "," + str(cy) + ")"
# fit ellipse
ellipse = cv2.fitEllipse(cntr)
(x, y), (minor_axis, major_axis), angle = ellipse
poly = cv2.ellipse2Poly((int(x), int(y)), (int(major_axis / 2), int(minor_axis / 2)), int(angle), 0, 360, 1)
similarity = cv2.matchShapes(poly.reshape((poly.shape[0], 1, poly.shape[1])), cntr, cv2.CONTOURS_MATCH_I1, 0)
if similarity < 0.2:
print("area:",area, "center:",pt, "major_axis:",major_axis, "minor_axis:",minor_axis, "similarity:",similarity)
cv2.drawContours(result, [cntr], 0, (0,0,0), -1)
# write result to disk
cv2.imwrite("notes_lines_removed.png", result)
#cv2.imwrite("notes2_lines_removed.png", result)
# display it
cv2.imshow("lines1", lines1)
cv2.imshow("lines2", lines2)
cv2.imshow("result", result)
cv2.waitKey(0)
Result 1:
area: 360.0 center: (12.710648148148147,19.85972222222222) major_axis: 30.517166137695312 minor_axis: 18.602985382080078 similarity: 0.0965383677685383
area: 309.0 center: (64.38619201725997,10.55393743257821) major_axis: 24.558181762695312 minor_axis: 16.582275390625 similarity: 0.026244617612192156
Result 2:
area: 317.0 center: (12.773922187171397,10.570452155625656) major_axis: 25.237092971801758 minor_axis: 16.553726196289062 similarity: 0.008516408232928263
Answered By - fmw42
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.