I want to write a tool for finding the number of angles, curves and straight lines within each bounded object in an image.
All input images will be black on white background and all will represent characters.
As illustrated in the image, for each bounded region, each shape occurrence is noted. It would be preferable to be able to have a threshold for how curvy a curve must be to be considered a curve and not an angle etc. And the same for straight lines and angles.
I have used Hough Line Transform for detecting straight lines on other images and it might work in combination with something here I thought.
Am open to other libraries than opencv – this is just what I have some experience with.
Thanks in advance
So based on the answer from Markus, I made a program using the
It produces a somewhat wierd result inputting a ‘k’ where it correctly identifies some points around the angles but then the ‘leg’ (the lower diagonal part) has many many points on it. I am unsure how to go about segmenting this to group into straights, angles and curves.
import numpy as np img = cv2.imread('Helvetica-K.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (3, 3), 0) edges = cv2.Canny(blurred, 50, 150, apertureSize=3) ret, thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY_INV) contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #cv2.drawContours(img, contours, 0, (0,255,0), 1) #Coordinates of each contour for i in range(len(contours)): print(contours[i]) print(contours[i]) cv2.circle(img, (contours[i], contours[i]), 2, (0,0,255), -1) cv2.imshow('img', img) cv2.waitKey(0) cv2.destroyAllWindows()
You can use findContours with option
- A point with an angle less than some threshold is a corner.
- A point with an angle more than some threshold is on a straight line and should be removed.
- Two adjacent points with a distance of more than some threshold are the ends of a straight line.
- Two adjacent points that are identified to be corners are the ends of a straight line.
- All other points belong to some curvy detail.
Here is some code you can start with. It shows how to smoothen the straight lines, how you can merge several corner points into one, and how to calculate distances and angles at each point. There is still some work to be done for you to achieve the required result but I hope it leads in the right direction.
import numpy as np import numpy.linalg as la import cv2 def get_angle(p1, p2, p3): v1 = np.subtract(p2, p1) v2 = np.subtract(p2, p3) cos = np.inner(v1, v2) / la.norm(v1) / la.norm(v2) rad = np.arccos(np.clip(cos, -1.0, 1.0)) return np.rad2deg(rad) def get_angles(p, d): n = len(p) return [(p[i], get_angle(p[(i-d) % n], p[i], p[(i+d) % n])) for i in range(n)] def remove_straight(p): angles = get_angles(p, 2) # approximate angles at points (two steps in path) return [p for (p, a) in angles if a < 170] # remove points with almost straight angles def max_corner(p): angles = get_angles(p, 1) # get angles at points j = 0 while j < len(angles): # for each point k = (j + 1) % len(angles) # and its successor (pj, aj) = angles[j] (pk, ak) = angles[k] if la.norm(np.subtract(pj, pk)) <= 4: # if points are close if aj > ak: # remove point with greater angle angles.pop(j) else: angles.pop(k) else: j += 1 return [p for (p, a) in angles] def main(): img = cv2.imread('abc.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY_INV) contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) for c in contours: # for each contour pts = [v for v in c] # get pts from contour pts = remove_straight(pts) # remove almost straight angles pts = max_corner(pts) # remove nearby points with greater angle angles = get_angles(pts, 1) # get angles at points # draw result for (p, a) in angles: if a < 120: cv2.circle(img, p, 3, (0, 0, 255), -1) else: cv2.circle(img, p, 3, (0, 255, 0), -1) cv2.imwrite('out.png', img) cv2.destroyAllWindows() main()
Answered By – Markus
Answer Checked By – Dawn Plyler (AngularFixing Volunteer)