利用单应性将椭圆投影为圆时的OpenCV图像投影异常问题
表盘椭圆转圆的单应性投影问题
我是计算机视觉领域新手,正尝试从图像中提取表盘。已成功为表盘拟合椭圆,希望通过修正视角将椭圆投影为圆,使表盘正对相机。经了解,该任务通常使用homography(单应性)实现。
按照OpenCV单应性教程操作后,发现源图像与目标匹配效果极差。查阅相关问题得知,透视投影的圆并非严格意义上的椭圆,无法实现完美投影,但即使是简单案例,投影结果仍不理想。
已标注4张输入图像的椭圆(红色)、单位圆(蓝色)、源点(黄色)和目标点(青色),应用OpenCV(及Scikit)计算的单应性后,椭圆未成功投影到单位圆上,增加计算单应性的点数量也无改善。
使用的代码
def persp_transform(orig): img = orig.copy() ellipses = find_ellipses(img) ellipse = ellipses[0] # Use the largest one center_x = ellipse[0] center_y = ellipse[1] center = np.array([center_x, center_y]) width = ellipse[2] height = ellipse[3] angle = ellipse[4] minor_semiaxis = min(width, height)/2 major_semiaxis = max(width, height)/2 # Translate the image to center the ellipse img_center = np.array([img.shape[0]//2, img.shape[1]//2]) translation = center - img_center M = np.float32([[1, 0, -translation[1]], [0, 1, -translation[0]]]) img = cv.warpAffine(img, M, (img.shape[1], img.shape[0])) # Draw ellipse before projection rr, cc = ellipse_perimeter(img_center[0], img_center[1], int(major_semiaxis), int(minor_semiaxis), orientation=angle, shape=img.shape) draw_ellipse(img, rr, cc, color=0, thickness=10) def sin(a): return np.sin(np.deg2rad(a)) def cos(a): return np.cos(np.deg2rad(a)) # Source points around the ellipse num_points = 5 rotation = np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]]) from_points = np.array([[major_semiaxis*sin(a), minor_semiaxis*cos(a)] for a in np.linspace(0, 360, num_points)]) @ rotation + img_center from_points = from_points.astype(np.float32) # Destination points around a centered circle to_radius = int((min(img.shape[:2]) / 2) * 0.8) to_points = np.array([[to_radius*sin(a), to_radius*cos(a)] for a in np.linspace(0, 360, num_points)]) @ rotation + img_center to_points = to_points.astype(np.float32) # Draw ellipse center and source points before projection cv.circle(img, (img_center[1], img_center[0]), 20, (255, 255, 0), -1) for fp in from_points: cv.circle(img, (int(fp[1]), int(fp[0])), 20, (255, 255, 0), -1) # Compute homography and project M, _ = cv.findHomography(from_points, to_points, cv.RANSAC, 5.0) img = cv.warpPerspective(img, M, (img.shape[1], img.shape[0])) # Draw target unit circle and destination points after projection cv.circle(img, (img_center[1], img_center[0]), to_radius, (0, 0, 255), 20) cv.circle(img, (img_center[1], img_center[0]), 20, (0, 255, 255), -1) for tp in to_points: cv.circle(img, (int(tp[1]), int(tp[0])), 20, (0, 255, 255), -1) return img
编辑1
补充4张原始输入图像,椭圆拟合采用AAMED方法,代码如下:
def find_ellipses(orig, scale=0.3, theta_fsa=20, length_fsa=5.4, T_val=0.9): img = cv.resize(orig.copy(), None, fx=scale, fy=scale) gray_image = cv.cvtColor(img, cv.COLOR_BGR2GRAY) aamed = AAMED(img.shape[0]+1, img.shape[1]+1) aamed.setParameters(np.deg2rad(theta_fsa), length_fsa, T_val) ellipses = aamed.run_AAMED(gray_image) aamed.release() ellipses = sorted(ellipses, key=lambda e: ellipse_area(e), reverse=True) ellipses = [np.array(e) / scale for e in ellipses] return ellipses
随后使用skimage.draw.ellipse_perimeter(...)在图像上绘制最大的椭圆。
编辑2
进一步排查发现问题可能出在cv.warpPerspective(...):
- 已对各点对进行颜色编码,确认映射关系正确
- 使用
cv.perspectiveTransform(...)单独投影源点时,结果正常 - 但使用
cv.warpPerspective(...)投影图像时,结果与点投影不一致
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

