压力表图像校正:如何将椭圆长轴垂直对齐并完成图像裁剪?
问题:压力表显示区域的旋转校正与裁剪实现
我正在实现一篇压力表读数相关的论文,其中有一个步骤不知如何操作:
将显示轮廓旋转至椭圆长轴垂直对齐,然后内切到矩形中以裁剪压力表图像
目前我处于步骤C,需要将图像转换为步骤D的状态(示例中文字检测暂不重要)。我已获取到显示区域的正确轮廓与椭圆,相关代码如下:
(cnts, boundingBoxes) = sort_contours(cnts) #find correct contours and fitellipse if len(cnts) != 0: for i in range(len(cnts)): if len(cnts[i]) >= 5: #if contours has more than 5 points # cv2.drawContours(image,cnts[0],-1,(150,10,255),3) ellipse = cv2.fitEllipse(cnts[i]) finalElps.append(ellipse) #(centx,centy), (width,height), angle for i in range(len(finalElps)): centx = finalElps[i][0][0] centy = finalElps[i][0][1] eWidth = finalElps[i][1][0] eHeight = finalElps[i][1][1] sfRes = Sf(eWidth, eHeight) cfRes = Cf(centx, imgCenterX, centy, imgCenterY) afRes = Af(eWidth,eHeight,imgWidth,imgHeight) print("SF: " + str(sfRes) + "| " + "CF: " + str(cfRes) + "| Af: " + str(afRes)) if(sfRes < 0.4 and cfRes < 6 and afRes < 0.9): print(finalElps[i]) cv2.ellipse(image, finalElps[i], (255,0,0), 2) plt.imshow(image)
注:sfRes、cfRes、afRes为筛选目标椭圆的计算参数。
请问下一步该如何实现图像的垂直旋转?我认为对应的技术是image rectification(图像校正),但不确定。
解决方案
你提到的image rectification(图像校正)确实是对应技术范畴,核心是围绕椭圆中心旋转图像,让椭圆长轴垂直对齐,之后再裁剪出目标区域。以下是具体实现步骤和代码:
1. 计算正确的旋转角度
OpenCV的cv2.fitEllipse返回的angle参数定义需要注意:
- 当椭圆的
width > height时,angle是长轴与水平轴的夹角(逆时针为正) - 当
width < height时,angle实际是短轴与水平轴的夹角,此时长轴的夹角为angle + 90°
要让长轴垂直,需计算旋转角度将长轴转到90°方向:
# 从筛选出的目标椭圆中提取参数 target_ellipse = finalElps[i] (centx, centy), (eWidth, eHeight), angle = target_ellipse # 确定长轴当前的实际角度 if eWidth > eHeight: major_axis_angle = angle else: major_axis_angle = angle + 90 # 计算需要旋转的角度:让长轴从当前角度转到垂直状态 rotate_angle = 90 - major_axis_angle # 处理角度超出范围的情况(确保在-180到180之间) rotate_angle = rotate_angle % 360
2. 生成旋转矩阵并执行图像旋转
使用OpenCV的cv2.getRotationMatrix2D生成旋转矩阵,再通过cv2.warpAffine完成旋转:
import cv2 import numpy as np # 获取原图像尺寸 img_h, img_w = image.shape[:2] # 生成旋转矩阵:中心为椭圆中心,旋转角度为计算值,缩放因子保持1(不改变尺寸) rotation_matrix = cv2.getRotationMatrix2D((centx, centy), rotate_angle, 1.0) # 执行旋转,用INTER_CUBIC插值保证图像质量,BORDER_REPLICATE填充边界 rotated_img = cv2.warpAffine(image, rotation_matrix, (img_w, img_h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
3. 裁剪旋转后的目标区域
旋转后椭圆长轴已垂直,此时椭圆的外接矩形就是垂直对齐的目标区域,计算坐标并裁剪:
# 计算椭圆的半长轴和半短轴 half_major = max(eWidth, eHeight) / 2 half_minor = min(eWidth, eHeight) / 2 # 推导外接矩形的坐标(以椭圆中心为基准) x1 = int(centx - half_minor) y1 = int(centy - half_major) x2 = int(centx + half_minor) y2 = int(centy + half_major) # 确保坐标在图像范围内,避免越界 x1 = max(0, x1) y1 = max(0, y1) x2 = min(img_w, x2) y2 = min(img_h, y2) # 裁剪得到最终的对齐图像 cropped_img = rotated_img[y1:y2, x1:x2]
整合到现有代码中
将上述代码插入到你筛选到目标椭圆的if块内即可:
if(sfRes < 0.4 and cfRes < 6 and afRes < 0.9): print(finalElps[i]) cv2.ellipse(image, finalElps[i], (255,0,0), 2) plt.imshow(image) # 新增:旋转校正与裁剪逻辑 target_ellipse = finalElps[i] (centx, centy), (eWidth, eHeight), angle = target_ellipse # 计算旋转角度 if eWidth > eHeight: major_axis_angle = angle else: major_axis_angle = angle + 90 rotate_angle = 90 - major_axis_angle rotate_angle = rotate_angle % 360 # 执行图像旋转 img_h, img_w = image.shape[:2] rotation_matrix = cv2.getRotationMatrix2D((centx, centy), rotate_angle, 1.0) rotated_img = cv2.warpAffine(image, rotation_matrix, (img_w, img_h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE) # 裁剪目标区域 half_major = max(eWidth, eHeight) / 2 half_minor = min(eWidth, eHeight) / 2 x1 = int(centx - half_minor) y1 = int(centy - half_major) x2 = int(centx + half_minor) y2 = int(centy + half_major) x1 = max(0, x1) y1 = max(0, y1) x2 = min(img_w, x2) y2 = min(img_h, y2) cropped_img = rotated_img[y1:y2, x1:x2] # 查看最终结果 plt.imshow(cropped_img) plt.show()
内容的提问来源于stack exchange,提问作者Chopper
相关产品推荐
相关产品推荐

