如何用Python识别旋转圆盘角度以驱动步进电机
基于圆盘图像旋转角度控制步进电机的解决方案
问题描述
我拍摄了旋转圆盘的图像,希望根据圆盘的旋转角度来驱动步进电机旋转相同角度。圆盘示例图像如下:
我尝试通过旋转原始图像360度寻找均方误差(MSE)最小的角度,但该方法无效,相关代码如下:
MSE计算函数
def mse(img1, img2): img1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY) img2 = cv.cvtColor(img2, cv.COLOR_BGR2GRAY) h, w = img1.shape diff = cv.subtract(img1, img2) err = np.sum(diff**2) mse = err/(float(h*w)) return mse
旋转匹配代码
for i in range(0,360,5): rotate = imutils.rotate(r,i) differ = mse(rotate,r) print(differ,i)
可行解决方案
1. 提取圆盘特征标记计算角度
圆盘上有明显的黑白扇形标记,直接利用这些标记计算角度:
- 对图像做二值化处理,提取白色区域轮廓
- 计算白色扇形的中心角度:通过轮廓的最小外接矩形/拟合椭圆得到角度范围,或计算白色区域重心,结合圆盘中心计算夹角
- 对比初始参考图像的白色标记角度,得到旋转差值
2. 局部模板匹配优化检测
- 截取圆盘上一个独特的局部标记(比如某块白色扇形的局部)作为模板
- 在目标图像中结合旋转操作使用
cv2.matchTemplate进行匹配,找到匹配度最高的角度,即为圆盘旋转角度 - 相比全图MSE,局部模板匹配受背景干扰更小,精度更高
3. 霍夫圆检测+圆心角计算
- 用霍夫圆检测定位圆盘的中心和半径
- 提取圆盘边缘像素,结合二值化后的黑白区域,计算白色区域对应的圆心角
- 对比初始状态的圆心角,得到旋转角度差
4. 改进原有MSE方法
你之前的MSE方法无效,大概率是因为旋转图像时出现黑边(imutils.rotate默认会保留或裁剪黑边),导致全图对比误差大:
- 改用
cv2.warpAffine进行旋转,保持图像尺寸并填充背景(比如用圆盘背景色填充) - 先通过霍夫圆检测提取圆盘掩码,只计算掩码内区域的MSE,排除背景干扰
代码示例(特征点角度计算)
import cv2 import numpy as np def get_disk_angle(img_path): # 读取图像并预处理 img = cv2.imread(img_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 检测圆盘中心(霍夫圆) circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=100, maxRadius=200) if circles is not None: circles = np.uint16(np.around(circles)) center_x, center_y = circles[0][0][0], circles[0][0][1] # 提取白色区域轮廓 contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: # 计算轮廓重心 M = cv2.moments(cnt) if M["m00"] != 0: cx = int(M["m10"] / M["m00"]) cy = int(M["m01"] / M["m00"]) # 计算重心与中心的夹角(以y轴正方向为0度,顺时针为正) angle = np.arctan2(cx - center_x, center_y - cy) * 180 / np.pi if angle < 0: angle += 360 return angle return 0 # 计算初始角度和当前角度 initial_angle = get_disk_angle("initial_disk.jpg") current_angle = get_disk_angle("current_disk.jpg") rotation_diff = (current_angle - initial_angle) % 360 print(f"圆盘旋转角度:{rotation_diff}度") # 驱动步进电机(示例,根据电机参数调整) # step_angle = 1.8 # 步进电机步距角 # steps_needed = int(rotation_diff / step_angle) # 调用电机驱动代码发送steps_needed步
内容的提问来源于stack exchange,提问作者SRIKANTH S
相关产品推荐
相关产品推荐

