You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

压力表图像校正:如何将椭圆长轴垂直对齐并完成图像裁剪?

问题:压力表显示区域的旋转校正与裁剪实现

我正在实现一篇压力表读数相关的论文,其中有一个步骤不知如何操作:

将显示轮廓旋转至椭圆长轴垂直对齐,然后内切到矩形中以裁剪压力表图像

目前我处于步骤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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 11:10:24