Aim of my program is find the angle of bending Led.
I got the angle using convexity defects in convex hull but the midpoint is move away from center point of that bend.
original image original
below image is the output of program
black dot is starting point.
red dot is end point.
blue dot is mid point.
Now I want move blue dot to the center of the curve
my code
import cv2
import numpy as np
from math import sqrt
from collections import OrderedDict
def findangle(x1,y1,x2,y2,x3,y3):
ria = np.arctan2(y2 - y1, x2 - x1) - np.arctan2(y3 - y1, x3 - x1)
if ria > 0:
if ria < 3:
webangle = int(np.abs(ria * 180 / np.pi))
elif ria > 3:
webangle = int(np.abs(ria * 90 / np.pi))
elif ria < 0:
if ria < -3:
webangle = int(np.abs(ria * 90 / np.pi))
elif ria > -3:
webangle = int(np.abs(ria * 180 / np.pi))
return webangle
image = cv2.imread("cam/2022-09-27 10:01:57image.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY)
contours,hie= cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
selected_contour = max(contours, key=lambda x: cv2.contourArea(x))
# Draw Contour
approx = cv2.approxPolyDP(selected_contour, 0.0035 * cv2.arcLength(selected_contour, True), True)
for point in approx:
cv2.drawContours(image, [point], 0, (0, 0, 255), 3)
convexHull = cv2.convexHull(selected_contour,returnPoints=False)
cv2.drawContours(image, cv2.convexHull(selected_contour), 0, (0, 255, 0), 3)
convexHull[::-1].sort(axis=0)
convexityDefects = cv2.convexityDefects(selected_contour, convexHull)
start2,distance=[],[]
for i in range(convexityDefects.shape[0]):
s, e, f, d = convexityDefects[i, 0]
start = tuple(selected_contour[s][0])
end = tuple(selected_contour[e][0])
far = tuple(selected_contour[f][0])
start2.append(start)
cv2.circle(image, start, 2, (255, 0, 0), 3)
cv2.line(image,start,end , (0, 255, 0), 3)
distance.append(d)
distance.sort(reverse=True)
for i in range(convexityDefects.shape[0]):
s, e, f, d = convexityDefects[i, 0]
if distance[0]==d:
defect={"s":s,"e":e,"f":f,"d":d}
cv2.circle(image, selected_contour[defect.get("f")][0], 2, (255, 0, 0), 3)
cv2.circle(image, selected_contour[defect.get("s")][0], 2, (0, 0, 0), 3)
cv2.circle(image, selected_contour[defect.get("e")][0], 2, (0, 0, 255), 3)
x1, y1 = selected_contour[defect.get("f")][0]
x2, y2 = selected_contour[defect.get("e")][0]
x3, y3 = selected_contour[defect.get("s")][0]
cv2.line(image,(x1,y1),(x2,y2),(255,200,0),2)
cv2.line(image,(x1,y1),(x3,y3),(255,200,0),2)
cv2.putText(image, "Web Angle : " + str((findangle(x1,y1,x2,y2,x3,y3))), (50, 200), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, 1, (0,0,0),2,cv2.LINE_AA)
cv2.imshow("frame",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
so i want any concept to get exact center of the bend point.
Here is one way to do that in Python/OpenCV. I make no guarantees that it is universal and would work on all such images. I also leave it for others to add trapping for empty arrays/lists and other general best practices.
Input:
import cv2
import numpy as np
import skimage.morphology
img = cv2.imread("wire.png")
# create a binary thresholded image
lower = (255,255,255)
upper = (255,255,255)
thresh = cv2.inRange(img, lower, upper)
thresh = (thresh/255).astype(np.float64)
# apply morphology to connect at top
kernel = np.ones((11,11), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply skeletonization
skeleton = skimage.morphology.skeletonize(thresh)
skeleton = (255*skeleton).clip(0,255).astype(np.uint8)
# get skeleton points
pts = np.where(skeleton != 0)
x = pts[1]
y = pts[0]
num_pts = len(x)
print(num_pts)
# zip x and y
xy1 = zip(x,y)
xy2 = zip(x,y)
# sort on y
xy_sorty = sorted(xy1, key = lambda x: x[1])
#print(xy_sorty[0])
# sort on x
xy_sortx = sorted(xy2, key = lambda x: x[0])
#print(xy_sortx[0])
# unzip x and y for xy_sortedy
xu1, yu1 = zip(*xy_sorty)
# get first line from top
# find miny from y sort, then get point 40% down from miny
miny = np.amin(yu1)
y1 = miny
[xy1] = [(xi, yi) for (xi, yi) in xy_sorty if abs(yi - y1) <= 0.00001]
x1 = xy1[0]
y1 = xy1[1]
#print(x1,y1)
maxy = np.amax(yu1)
dely = maxy - miny
y2 = int(y1+0.4*dely)
[xy2] = [(xi, yi) for (xi, yi) in xy_sorty if abs(yi - y2) <= 0.00001]
x2 = xy2[0]
y2 = xy2[1]
#print(x2,y2)
# unzip x and y for xy_sortedx
xu2, yu2 = zip(*xy_sortx)
# get first line from left
# find minx from x sort, then get point 40% right from minx
minx = np.amin(xu2)
x3 = minx
[xy3] = [(xi, yi) for (xi, yi) in xy_sortx if abs(xi - x3) <= 0.00001]
x3 = xy3[0]
y3 = xy3[1]
#print(x3,y3)
maxx = np.amax(xu2)
delx = maxx - minx
x4 = int(x3+0.4*delx)
[xy4] = [(xi, yi) for (xi, yi) in xy_sortx if abs(xi - x4) <= 0.00001]
x4 = xy4[0]
y4 = xy4[1]
#print(x4,y4)
# draw lines on copy of skeleton
skeleton_lines = skeleton.copy()
skeleton_lines = cv2.merge([skeleton_lines,skeleton_lines,skeleton_lines])
cv2.line(skeleton_lines, (x1,y1), (x2,y2), (0,0,255), 2)
cv2.line(skeleton_lines, (x3,y3), (x4,y4), (0,0,255), 2)
# get intersection between line1 (x1,y1 to x2,y2) and line2 (x3,y3 to x4,y4) and draw circle
# https://en.wikipedia.org/wiki/Line–line_intersection
den = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4)
px = ((x1*y2-y1*x2)*(x3-x4) - (x1-x2)*(x3*y4-y3*x4))/den
py = ((x1*y2-y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4))/den
px = int(px)
py = int(py)
cv2.circle(skeleton_lines, (px,py), 3, (0,255,0), -1)
# compute first derivatives in x and also in y
dx = np.gradient(x, axis=0)
dy = np.gradient(y, axis=0)
# loop over each point
# get the slope of the tangent to the curve
# get the inverse slop of the line from the point to the intersection point (inverse slope is normal direction)
# get difference in slopes and find the point that has the minimum difference
min_diff = 1000000
eps = 0.0000000001
for i in range(num_pts):
slope1 = abs(dy[i]/(dx[i] + eps))
slope2 = abs((px - x[i])/(py - y[i] + eps))
slope_diff = abs(slope1 - slope2)
if slope_diff < min_diff:
min_diff = slope_diff
bend_x = x[i]
bend_y = y[i]
#print(x[i], y[i], min_diff)
bend_x = int(bend_x)
bend_y = int(bend_y)
#print(bend_x, bend_y)
cv2.line(skeleton_lines, (px,py), (bend_x,bend_y), (0,0,255), 2)
cv2.circle(skeleton_lines, (bend_x,bend_y), 3, (0,255,0), -1)
# get end points and bend point and draw on copy of input
result = img.copy()
end1 = (x1,y1)
end2 = (x3,y3)
bend = (bend_x,bend_y)
print("end1:", end1)
print("end2:", end2)
print("bend:", bend)
cv2.circle(result, (end1), 3, (0,0,255), -1)
cv2.circle(result, (end2), 3, (0,0,255), -1)
cv2.circle(result, (bend), 3, (0,0,255), -1)
# save result
cv2.imwrite("wire_skeleton.png", skeleton)
cv2.imwrite("wire_skeleton_lines.png", skeleton_lines)
cv2.imwrite("wire_result.png", result)
# show results
cv2.imshow("thresh", (255*thresh).astype(np.uint8))
cv2.imshow("skeleton", skeleton)
cv2.imshow("skeleton_lines", skeleton_lines)
cv2.imshow("skeleton_result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Skeleton:
Skeleton with lines:
Result showing end points and bend point: