2

I am currently working on a project using opencv and python to measure objects that are usually curved for example the arrow shown below as accurately as possible.

Curved arrow

I thought that one strategy might be to use the scipy Voronoi function to obtain the points along the center spine of the arrow but am having trouble right now. Here is my code:

img = cv2.imread('example_rubystreak_2.PNG')
img.shape
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,190,255,cv2.THRESH_BINARY)
countimage, contours, hierarchy = cv2.findContours(thresh,1,2)
blank = np.zeros((img.shape[0],img.shape[1],1),np.uint8)
#get max length contour
max_contour = 0
contour_idx = None
for ii in range(len(contours)):
    if len(contours[ii]) > max_contour:
        contour_idx = ii
        max_contour = len(contours[ii])
cv2.drawContours(blank,contours,contour_idx,255,cv2.FILLED,8,hierarchy)
apdp = cv2.approxPolyDP(contours[contour_idx],1,True)
ap = [(a[0][0],a[0][1]) for a in apdp]
vor_ap = Voronoi(ap)
spined = []
for ridge in vor_ap.ridge_vertices:
    if cv2.pointPolygonTest(cnt,tuple(vor_ap.vertices[ridge[0]]),True) <= 0.0 or cv2.pointPolygonTest(cnt,tuple(vor_ap.vertices[ridge[1]]),True) <= 0.0:
        continue
    else:
        if tuple(vor_ap.vertices[ridge[0]]) not in spined:
            spined.append([tuple(vor_ap.vertices[ridge[0]].tolist()),cv2.pointPolygonTest(cnt,tuple(vor_ap.vertices[ridge[0]]),True)])
        if tuple(vor_ap.vertices[ridge[1]]) not in spined:
            spined.append([tuple(vor_ap.vertices[ridge[1]].tolist()),cv2.pointPolygonTest(cnt,tuple(vor_ap.vertices[ridge[1]]),True)])
plt.figure(figsize=(12,12))
plt.scatter([s[0][0] for s in spined],[s[0][1] for s in spined])
plt.plot([a[0] for a in ap],[a[1] for a in ap])

Which produces this picture:

Voronoi Arrow

Anyone have ideas as to how I can then measure the length of the arrow using these center points? I've tried using np.polyfit and looked at the page here but can't figure out a way to consistently get the curve traced out by the most central points as the arrows are sometimes curved like an S or have different shaped points. Any help would be really appreciated. Thanks.

Community
  • 1
  • 1
user2587593
  • 1,443
  • 2
  • 11
  • 12

1 Answers1

1

Here's an outline of what I'd try:

1) Find a parameterized representation of your central curve by interpolating the points using cubic B-splines. Use scipy.interpolate.splrep. You may need to remove the outlier points that don't follow the central curve to get a good cubic spline fit.

2) Once you have the cubic spline curve you can find the arc length by using the arc length integral formula from calculus and compute that integral numerically with the limits of integration your curve's endpoints. To do that you'll need to get the X and Y first derivatives of your spline curve, which scipy.interpolate.splev or scipy.interpolate.spalde should be able to give you. Use the scipy numerical integration routines for a function represented by Numpy arrays.

paisanco
  • 4,098
  • 6
  • 27
  • 33
  • thanks for the hint but i'm having trouble with splrep as many of the points along the arrows have multiple y values for single x values and these curves don't always lend themselves to being sorted. Do you have any suggestions for how to deal with this? – user2587593 Aug 07 '15 at 20:36
  • I haven't been able to run your code (what is the variable cnt in the calls to cv2.pointPolygonTest supposed to be? I know contour , but which one at that stage of execution) . Didn't realize some of the X's have multiple Y's but in those cases does taking the mean Y make sense? – paisanco Aug 07 '15 at 22:22