这还不完整;您必须花时间才能达到最终结果。但这个想法可能会对您有所帮助。
预处理器:
import os
import cv2
import numpy as np
主要代码:
# Read original image
dir = os.path.abspath(os.path.dirname(__file__))
im = cv2.imread(dir+'/'+'im.jpg')
h, w = im.shape[:2]
print(w, h)
# Convert image to Grayscale
imGray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imwrite(dir+'/im_1_grayscale.jpg', imGray)
# Eliminate noise and display laser light better
imHLine = imGray.copy()
imHLine = cv2.GaussianBlur(imHLine, (0, 9), 21) # 5, 51
cv2.imwrite(dir+'/im_2_h_line.jpg', imHLine)
# Make a BW mask to find the ROI of laser array
imHLineBW = cv2.threshold(imHLine, 22, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite(dir+'/im_3_h_line_bw.jpg', imHLineBW)
# Remove noise with mask and extract just needed area
imHLineROI = imGray.copy()
imHLineROI[np.where(imHLineBW == 0)] = 0
imHLineROI = cv2.GaussianBlur(imHLineROI, (0, 3), 6)
imHLineROI = cv2.threshold(imHLineROI, 25, 255, cv2.THRESH_BINARY)[1] # 22
cv2.imwrite(dir+'/im_4_ROI.jpg', imHLineROI)
# Found laser array and draw box around it
cnts, _ = cv2.findContours(
imHLineROI, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts.sort(key=lambda x: cv2.boundingRect(x)[0])
pts = []
for cnt in cnts:
x2, y2, w2, h2 = cv2.boundingRect(cnt)
if h2 < h/10:
cv2.rectangle(im, (x2, y2), (x2+w2, y2+h2), (0, 255, 0), 1)
pts.append({'x': x2, 'y': y2, 'w': w2, 'h': h2})
circle = {
'left': (pts[0]['x']+pts[0]['w'], pts[0]['y']+pts[0]['h']/2),
'right': (pts[1]['x'], pts[1]['y']+pts[1]['h']/2),
}
circle['center'] = calculateMiddlePint(circle['left'], circle['right'])
circle['radius'] = (circle['right'][0]-circle['left'][0])//2
# Draw line and Circle inside it
im = drawLine(im, circle['left'], circle['right'], color=(27, 50, 120))
im = cv2.circle(im, circle['center'], circle['radius'], (255, 25, 25), 3)
# Remove pepper/salt noise to find metal edge
imVLine = imGray.copy()
imVLine = cv2.medianBlur(imVLine, 17)
cv2.imwrite(dir+'/im_6_v_line.jpg', imVLine)
# Remove remove the shadows to find metal edge
imVLineBW = cv2.threshold(imVLine, 50, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite(dir+'/im_7_v_bw.jpg', imVLineBW)
# Finding the right vertical edge of metal
y1, y2 = h/5, h-h/5
x1 = horizantalDistance(imVLineBW, y1)
x2 = horizantalDistance(imVLineBW, y2)
pt1, pt2 = (x1, y1), (x2, y2)
imVLineBW = drawLine(imVLineBW, pt1, pt2)
cv2.imwrite(dir+'/im_8_v_bw.jpg', imVLineBW)
# Draw lines
im = drawLine(im, pt1, pt2)
im = drawLine(im, calculateMiddlePint(pt1, pt2), circle['center'])
# Draw final image
cv2.imwrite(dir+'/im_8_output.jpg', im)
额外功能:
查找一行图片中的第一个白色像素:
# This function only processes on a horizontal line of the image
# Its job is to examine the pixels one by one from the right and
# report the distance of the first white pixel from the right of
# the image.
def horizantalDistance(im, y):
y = int(y)
h, w = im.shape[:2]
for i in range(0, w):
x = w-i-1
if im[y][x] == 255:
return x
return -1
在opencv中画一条线:
def drawLine(im, pt1, pt2, color=(128, 0, 200), thickness=2):
return cv2.line(
im,
pt1=(int(pt1[0]), int(pt1[1])),
pt2=(int(pt2[0]), int(pt2[1])),
color=color,
thickness=thickness,
lineType=cv2.LINE_AA # Anti-Aliased
)
计算两个二维点的中点:
def calculateMiddlePint(p1, p2):
return (int((p1[0]+p2[0])/2), int((p1[1]+p2[1])/2))
输出:
原图:
消除噪音和处理以更好地查看激光阵列:
找到激光区域提取孔:
处理另一张图片以找到金属物体的右侧:
移除阴影以更好地查看右边缘:
最终输出:
我首先定义了一个 ROI 区域。我后来更改了代码,但没有更改变量的名称。如果有人问你。