python opencv提取砂轮轮廓并与设计轮廓对比

本案例通过相机采集砂轮图像,提取轮廓边缘点,并和设计轮廓对比,实现砂轮轮廓图像检测,具体如下:

1、原始图像

import cv2
import numpy as np
import matplotlib.pyplot as plt
​
# 读取图像
image = cv2.imread("C:/Users/yh/Pictures/20230728/usf0.25-5.0-x-1.bmp")
​
# 创建窗口并将鼠标回调函数与窗口关联
cv2.namedWindow("Original Image", cv2.WINDOW_NORMAL)
refPt = cv2.selectROI("Original Image", image, fromCenter=False, showCrosshair=True)
​
# 绘制红色框
x, y, w, h = refPt
​
# 销毁选择ROI的窗口
cv2.destroyWindow("Original Image")
​
​
# 截取感兴趣区域
roi = image[y:y+h, x:x+w]
​
# 将 ROI 转换为灰度图像
gray_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
​
# 将灰度图像二值化
_, threshold_roi = cv2.threshold(gray_roi, 210, 255, cv2.THRESH_BINARY_INV)
​
# 提取轮廓
contours_roi, _ = cv2.findContours(threshold_roi, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
​
# 在原始图像中绘制轮廓
cv2.drawContours(roi, contours_roi, -1, (0, 255, 0), 3)
​
# 显示图像和提取的轮廓
cv2.namedWindow("Image with Contours",cv2.WINDOW_NORMAL)
cv2.imshow("Image with Contours", roi)
cv2.waitKey(0)
cv2.destroyAllWindows()

2、读取图像并提取轮廓 

import cv2
import numpy as np
import matplotlib.pyplot as plt
import sympy as sy
#已知参数
#
pr={}
#输入参数
Line1_p1=[-0.557/2,0]
Line1_angle=280*np.pi/180
Line1_length=0.4182
Line2_p1=[0.557/2,0]
Line2_angle=236*np.pi/180
Line2_length=0.489
Arc1_r=0.1
pr['r1']=Arc1_r
Arc1_angle=41*np.pi/180
#定义符号变量
x1,y1,x2,y2,l1,l2,theta_l1,theta_l2=sy.symbols('x1,y1,x2,y2,l1,l2,theta_l1,theta_l2')
r1,theta_arc1_start,theta_arc1_end,xr1_center,yr1_center=sy.symbols('r1,theta_arc1_start,theta_arc1_end,xr1_center,yr1_center')
r2,theta_arc2,theta_arc2_start=sy.symbols('r2,theta_arc2,theta_arc2_start')
l,theta,x,y,d,da=sy.symbols('l,theta,x,y,d,da')
​
#第一条直线的参数方程,x1=Line1_p1[0],y1=Line1_p1[1],theta_l1=Line1_angle,l为参数
xl1=x1+l*sy.cos(theta_l1)
yl1=y1+l*sy.sin(theta_l1)
​
#计算直线终点坐标
u_1=xl1.subs([(x1,Line1_p1[0]),(theta_l1,Line1_angle),(l,Line1_length)])
u_1_y=yl1.subs([(y1,Line1_p1[1]),(theta_l1,Line1_angle),(l,Line1_length)])
pr['u_1']=u_1
#圆弧1初始角度
theta_arc1_start=theta_l1-np.pi/2
start=theta_arc1_start.subs([(theta_l1,Line1_angle)])
#圆弧1终止角度,圆心角取
theta_arc1_end=theta_arc1_start+theta
end=theta_arc1_end.subs([(theta_arc1_start,start),(theta,Arc1_angle)])
#圆弧1的圆心,r1=3,l1=2
xr1_center=x1+l1*sy.cos(theta_l1)+r1*sy.cos(theta_l1+np.pi/2)
yr1_center=y1+l1*sy.sin(theta_l1)+r1*sy.sin(theta_l1+np.pi/2)
​
#存圆弧1的圆心点坐标,第4点
o1x=xr1_center.subs([(x1,Line1_p1[0]),(theta_l1,Line1_angle),(l1,Line1_length),(r1,Arc1_r)])
o1y=yr1_center.subs([(y1,Line1_p1[1]),(theta_l1,Line1_angle),(l1,Line1_length),(r1,Arc1_r)])
pr['o1x']=o1x
pr['o1y']=o1y
#第一条圆弧上任意一点的坐标
xr1=xr1_center+r1*sy.cos(theta)
yr1=yr1_center+r1*sy.sin(theta)
​
​
#计算圆弧1终点坐标
b=np.arange(start,end, 0.01)
u_2=xr1.subs([(x1,Line1_p1[0]),(theta_l1,Line1_angle),(r1,Arc1_r),(l1,Line1_length),(theta, end)])
u_2_y=yr1.subs([(y1,Line1_p1[1]),(theta_l1,Line1_angle),(r1,Arc1_r),(l1,Line1_length),(theta, end)])
pr['u_2']=u_2
​
#第二条直线的参数方程,x2=10,y2=0,theta_l2=4*np.pi/3,l为参数
xl2=x2+l*sy.cos(theta_l2)
yl2=y2+l*sy.sin(theta_l2)
#计算直线2终点
u_3=xl2.subs([(x2,Line2_p1[0]),(theta_l2,Line2_angle),(l,Line2_length)])
u_3_y=yl2.subs([(y2,Line2_p1[1]),(theta_l2,Line2_angle),(l,Line2_length)])
pr['u_3']=u_3
#直线2终点处法线方程
x_ln=u_3+l*sy.cos(theta_l2-np.pi/2)
y_ln=u_3_y+l*sy.sin(theta_l2-np.pi/2)
​
lh0=x_ln.subs([(x2, Line2_p1[0]),(theta_l2,Line2_angle),(l2, Line2_length)])
lh1=y_ln.subs([(y2,Line2_p1[1]),(theta_l2,Line2_angle),(l2, Line2_length)])
​
#中垂线方程:不包括斜率不存在的情况
x3=u_2
y3=u_2_y
x4=u_3
y4=u_3_y
flz=(x4-x3)*(x-(x4+x3)/2)+(y4-y3)*(y-(y4+y3)/2)
​
#求解第二条圆弧的圆心及半径
exp=[x-lh0,y-lh1,flz]
m=sy.solve(exp,[x,y,l])
pr['o2x']=m[x]
pr['o2y']=m[y]
pr['r2']=m[l]
if Arc1_angle>=80*np.pi/180:
    max_u=float(pr['o1x'])
if Arc1_angle<80*np.pi/180:
    if float(pr['o2x'])>=float(pr['u_2']) and float(pr['o2x'])<=float(pr['u_3']):
        max_u=float(pr['o2x'])
    else:
        max_u=float(pr['u_2'])
# 砂轮轮廓函数
o1_x,o1_y,o2_x,o2_y=sy.symbols('o1_x,o1_y,o2_x,o2_y')
u1,u2,u3=sy.symbols('u1,u2,u3')
u,v=sy.symbols('u,v')
g1=sy.Piecewise((o1_y-sy.sqrt(r1**2-(u-o1_x)**2), (u1< u) & (u <= u2)),(o2_y-sy.sqrt(r2**2-(u-o2_x)**2), (u2 < u) & (u <= u3)))
g2=u
# # 通过subs代入已知值
g1_subs = g1.subs({o1_x: pr['o1x'], o1_y: pr['o1y'], r1: pr['r1'], u1: pr['u_1'], u2: pr['u_2'], o2_x:pr['o2x'],
                   o2_y: pr['o2y'], r2:pr['r2'], u3:pr['u_3']})
​
# 将已知值代入的表达式编译为可计算的lambda函数
g1_lambda = sy.lambdify(u, g1_subs)
​
# 创建u的取值范围
u_values = np.linspace(float(pr['u_1']),float(pr['u_3']), 500)[1:-1]
# 计算g1函数在u_values上的取值
g1_values = g1_lambda(u_values)
​
pos=np.argmin(g1_values)
wheel_x=u_values+(0-u_values[pos])
wheel_y=g1_values-g1_values[pos]
​
​
# 读取图像
image = cv2.imread(r"C:/Users/yh/Pictures/20230728/usf0.25-5.0-x-1.bmp")
​
# 创建窗口并将鼠标回调函数与窗口关联
cv2.namedWindow("Original Image", cv2.WINDOW_NORMAL)
refPt = cv2.selectROI("Original Image", image, fromCenter=False, showCrosshair=True)
​
# 绘制红色框
x, y, w, h = refPt
​
# 销毁选择ROI的窗口
cv2.destroyWindow("Original Image")
​
​
# 截取感兴趣区域
roi = image[y:y+h, x:x+w]
​
# 将 ROI 转换为灰度图像
gray_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
​
# 将灰度图像二值化
_, threshold_roi = cv2.threshold(gray_roi, 210, 255, cv2.THRESH_BINARY_INV)
​
# 提取轮廓
contours_roi, _ = cv2.findContours(threshold_roi, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
​
# 在原始图像中绘制轮廓
cv2.drawContours(roi, contours_roi, -1, (0, 255, 0), 3)
​
# 显示图像和提取的轮廓
cv2.namedWindow("Image with Contours",cv2.WINDOW_NORMAL)
cv2.imshow("Image with Contours", roi)
cv2.waitKey(0)
cv2.destroyAllWindows()
​
t=7.7/4/4024
s=np.argmax([len(i) for i in contours_roi])
contour=contours_roi[s].squeeze()*t
pos=np.argmin(contour[:,1])
contour_x=contour[:,0]-contour[:,0][pos]
contour_y=contour[:,1]-contour[:,1][pos]
​
fig = plt.figure(figsize=(5, 5))
plt.rcParams['xtick.direction'] = 'in'  # 将x周的刻度线方向设置向内
plt.rcParams['ytick.direction'] = 'in'  # 将y轴的刻度方向设置向内
clist = ['blue', 'red', 'green', 'black', 'darkgreen', 'lime', 'gold', 'purple', 'green', 'cyan', 'salmon', 'grey',
             'mediumvioletred', 'darkkhaki', 'gray', 'darkcyan', 'violet', 'powderblue']
​
​
plt.plot(contour_x,contour_y,'g*',label="contour for measure")
plt.plot(wheel_x,wheel_y,'r.',label="contour for design")
plt.legend()
plt.grid(True)
plt.show()
​
# def save_points_to_file(Point_x,Point_y, filename):
#     with open(filename, 'w') as file:
#         for i in range(len(Point_x)):
#             x, y= Point_x[i],Point_y[i]
#             file.write(f"{x},{y}\n")
# filename="contour for grinding wheel.txt"
# save_points_to_file(contour[:,0],contour[:,1],filename)

3、对比设计轮廓与测量轮廓 

结果1

结果2

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用OpenCV提取图片轮廓的基本步骤如下: 1. 读取图片,转换为灰度图像。 2. 对图像进行二值化处理,将图像转换为黑白图像。 3. 使用cv2.findContours函数查找轮廓。 4. 绘制轮廓。 以下是示例代码: ``` import cv2 # 读取图片 img = cv2.imread('test.jpg') # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化处理 ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 查找轮廓 contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 绘制轮廓 cv2.drawContours(img, contours, -1, (0, 0, 255), 2) # 显示结果 cv2.imshow('contours', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 其中cv2.findContours函数的参数含义如下: - binary:二值化图像。 - cv2.RETR_TREE:轮廓的检索模式,表示提取所有轮廓并建立轮廓间的层级关系。 - cv2.CHAIN_APPROX_SIMPLE:轮廓的近似方法,表示只保留轮廓的端点。 绘制轮廓使用的是cv2.drawContours函数,其中参数含义如下: - img:要绘制轮廓的图像。 - contours:要绘制的轮廓。 - -1:表示绘制所有轮廓。 - (0, 0, 255):轮廓的颜色,这里为红色。 - 2:轮廓的宽度。 ### 回答2: Python中的OpenCV库是一个用于图像处理和计算机视觉任务的强大工具。要提取图像的轮廓,我们可以使用OpenCV中的findContours函数。 首先,我们需要导入必要的库: import cv2 import numpy as np 然后,我们读取图像,并将其转换为灰度图像: image = cv2.imread('image.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 接下来,我们需要对图像进行阈值处理,以便更好地分离图像的前景和背景。我们可以使用cv2.threshold函数来实现: _, threshold = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) 然后,我们可以使用cv2.findContours函数来提取图像的轮廓: contours, _ = cv2.findContours(threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) findContours函数返回两个值:轮廓列表和层次结构。在这里,我们只关心轮廓列表。第一个参数是输入图像,第二个参数是轮廓检测模式,第三个参数是轮廓逼近方法。 最后,我们可以使用cv2.drawContours函数在图像上绘制提取到的轮廓: cv2.drawContours(image, contours, -1, (0, 255, 0), 3) drawContours函数的第一个参数是输入图像,第二个参数是轮廓列表,第三个参数是轮廓索引(-1表示绘制所有轮廓),第四个参数是轮廓的颜色,第五个参数是轮廓的线宽。 最后,我们可以显示处理后的图像: cv2.imshow('Contours', image) cv2.waitKey(0) cv2.destroyAllWindows() 以上就是使用PythonOpenCV提取图像轮廓的基本步骤。通过调整阈值和使用不同的轮廓逼近方法,可以实现更复杂的轮廓提取
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值