import cv2
import numpy as np
### Perform histogram equalization and threshold with OTSU.
img = cv2.imread('lens.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
equ = cv2.equalizeHist(gray)
_, thresh = cv2.threshold(equ,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
### Perform opening (erosion followed by dilation) and search for contours.
kernel = np.ones((2,2),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
_, contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
### Select the biggest one and create a bounding box.
### This will be used to calculate the center of your ROI.
cnt = max(contours, key=cv2.contourArea)
### Calculate x and y of the center.
x,y,w2,h2 = cv2.boundingRect(cnt)
center_x = int(x+(w2/2))
center_y = int(y+(h2/2))
### Create the radius of your inner circle ROI and draw it on a copy of the image.
img2 = img.copy()
radius = int((w2/2)-20)
cv2.circle(img2,(center_x,center_y), radius, (0,0,0), -1)
### Create the radius of your inner circle ROI and draw it on a blank mask.
radius_2 = int(w2/2)
h,w = img.shape[:2]
mask = np.zeros((h, w), np.uint8)
cv2.circle(mask,(center_x,center_y), radius_2, (255,255,255), -1)
### Perform a bitwise operation so that you will get your ROI
res = cv2.bitwise_and(img2, img2, mask=mask)
### Modify the image a bit to eliminate noise with thresholding and closing.
_, thresh = cv2.threshold(res,190,255,cv2.THRESH_BINARY)
kernel = np.ones((3,3),np.uint8)
closing = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,kernel, iterations = 2)
### Search for contours again and select two biggest one.
gray = cv2.cvtColor(closing,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
area = sorted(contours, key=cv2.contourArea, reverse=True)
contour1 = area[0]
contour2 = area[1]
### Iterate through both contours and calculate the minimum distance.
### If it is less than the threshold you provide, draw the lines on the image.
### Forumula is sqrt((x2-x1)^2 + (y2-y2)^2).
for i in contour1:
x = i[0][0]
y = i[0][1]
for j in contour2:
x2 = j[0][0]
y2 = j[0][1]
dist = np.sqrt((x2-x)**2 + (y2-y)**2)
if dist < 12:
xy = (x,y)
x2y2 = (x2,y2)
line = (xy,x2y2)
cv2.line(img2,xy,x2y2,(255,0,0),2)
else:
pass
### Transform the image to HSV colorspace and mask the result.
hsv = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV)
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
mask = cv2.inRange(hsv, lower_blue, upper_blue)
res = cv2.bitwise_and(img2,img2, mask= mask)
### Search fot contours again.
gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
### Fit a line through the contour and draw it on the original image.
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
left = int((-x*vy/vx) + y)
right = int(((w-x)*vy/vx)+y)
cv2.line(img,(w-1,right),(0,left),(0,0,255),2)
### Display the result.
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
所以,首先我要指出,你的形象是非常嘈杂的。这意味着仅仅通过寻找轮廓、边缘或线条,可能会因为噪音而无法工作。这使任务非常困难。如果你正在寻找一种自动化的方法来完成这样的任务,我建议你花点力气去寻找合适的照明(我认为一个经典的顶灯就足够了),因为它会使图像上的噪音更小(反射更少……),因此这样的算法更容易实现。在
我是这么说的。我举了一个例子来说明我将如何努力完成这项任务。请注意,这个解决方案可能不适用于其他图像,但在这个示例中,结果非常好。它可能会给你一个新的观点,如何解决这个问题。在
首先,在用OTSU阈值将图像转换为二进制之前,我将尝试执行直方图均衡化。之后,我将对图像执行打开操作(腐蚀后膨胀):
之后我会在最大的轮廓上做一个包围盒。通过x,y,h,w,我可以计算出边界框的中心,它将作为我要创建的ROI的中心。在图像的副本上画一个半径略小于w/2的圆,在半径等于w/2的新遮罩上画一个圆。然后执行位操作:
现在您有了ROI,必须再次设置阈值,以使边界无噪音并搜索轮廓:
现在可以看到有两个轮廓(内部和外部)。现在你可以提取镜头被切割的区域。可以通过计算内轮廓和外轮廓的每个点之间的距离来完成此操作。两点之间的距离公式是
sqrt((x2-x1)^2 + (y2-y2)^2)
。阈值这个距离,以便如果距离小于某个整数,并在图像上这两个点之间画一条线。我用蓝线画了距离。之后,将图像转换为HSV颜色空间,并再次使用按位操作对其进行遮罩,因此只剩下蓝色线条:再次执行OTSU阈值,然后选择最大的轮廓(那些蓝色的线)并通过轮廓拟合一条线。在原图上画一条线,你就会得到结果:
示例代码:
相关问题 更多 >
编程相关推荐