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

如何使用OpenCV获取扫描图像的边角坐标?

我来帮你搞定这个扫描图裁剪的问题!要自动识别四个角的矩形标记并获取裁剪坐标,咱们可以用OpenCV的图像处理工具一步步实现,下面是完整的解决方案:

一、图像预处理

首先得对原始图像做预处理,突出边缘信息,方便后续找轮廓:

import cv2
import numpy as np

# 读取图像(替换成你的图像路径)
image = cv2.imread("your_scanned_image.jpg")
# 转灰度图,减少计算维度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 高斯模糊去噪,避免边缘检测误判
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# Canny边缘检测,提取图像中的边缘特征
edged = cv2.Canny(blurred, 50, 150)

二、检测并筛选目标轮廓

接下来从边缘图里找出所有轮廓,然后筛选出四个角的小矩形标记:

# 查找图像中的所有外部轮廓
contours, _ = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 筛选符合特征的标记轮廓
marker_contours = []
for c in contours:
    # 计算轮廓的近似多边形,简化轮廓形状
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    # 筛选条件:近似为4边形(矩形),且面积在合理范围(根据你的图像尺寸调整)
    if len(approx) == 4 and 100 < cv2.contourArea(c) < 1000:
        marker_contours.append(approx)

说明:面积阈值可以根据你扫描图里标记的实际大小微调,确保只留下四个角的小矩形。

三、提取裁剪用的四个角点

现在我们有了四个标记矩形的轮廓,接下来要从每个矩形中提取出对应文档的角点(比如每个矩形最靠近图像角落的顶点),并按裁剪要求排序:

# 存储最终的文档角点
corners = []
h, w = image.shape[:2]  # 获取图像的宽高

for cnt in marker_contours:
    # 把轮廓顶点转换成(x,y)格式
    pts = cnt.reshape(4, 2)
    # 计算每个顶点到图像四个角落的距离,找到距离最近的点(即文档的实际角点)
    min_dist = float("inf")
    target_pt = None
    for (x, y) in pts:
        # 计算当前点到四个图像角落的距离最小值
        dists = [
            np.sqrt((x-0)**2 + (y-0)**2),      # 到左上角
            np.sqrt((x-w)**2 + (y-0)**2),      # 到右上角
            np.sqrt((x-0)**2 + (y-h)**2),      # 到左下角
            np.sqrt((x-w)**2 + (y-h)**2)       # 到右下角
        ]
        current_min = min(dists)
        if current_min < min_dist:
            min_dist = current_min
            target_pt = (x, y)
    corners.append(target_pt)

# 将角点按「左上→右上→右下→左下」的顺序排序(匹配你提供的裁剪代码要求)
corners = np.array(corners, dtype="float32")
# 先按y坐标排序,区分顶部和底部的点
sorted_by_y = corners[corners[:,1].argsort()]
# 顶部两个点按x从小到大排序(左上在前,右上在后)
top_corners = sorted_by_y[:2][sorted_by_y[:2,0].argsort()]
# 底部两个点按x从大到小排序(右下在前,左下在后)
bottom_corners = sorted_by_y[2:][sorted_by_y[2:,0].argsort()[::-1]]
# 组合成最终的有序角点
ordered_corners = np.concatenate([top_corners, bottom_corners])

四、应用四点变换完成裁剪

现在可以用你提供的裁剪代码完成透视变换了,如果没有four_point_transform函数,也可以自己实现一个:

先实现四点变换函数(如果需要)

def four_point_transform(image, pts):
    # 提取有序的四个角点
    (tl, tr, br, bl) = pts

    # 计算目标图像的宽度
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    maxWidth = max(int(widthA), int(widthB))

    # 计算目标图像的高度
    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    maxHeight = max(int(heightA), int(heightB))

    # 构造目标图像的标准角点
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype = "float32")

    # 计算透视变换矩阵并应用
    M = cv2.getPerspectiveTransform(pts, dst)
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

    return warped

执行裁剪并查看结果

# 应用透视变换
warped = four_point_transform(image, ordered_corners)

# 显示原始图和裁剪后的结果
cv2.imshow("Original Scanned Image", image)
cv2.imshow("Cropped Result", warped)
cv2.waitKey(0)
cv2.destroyAllWindows()

注意事项

  • 如果轮廓筛选不准确,可以调整面积阈值(100 < cv2.contourArea(c) < 1000),适配你的扫描图标记大小。
  • 若角点排序出现错误,可以微调排序逻辑,确保最终顺序是「左上→右上→右下→左下」。

内容的提问来源于stack exchange,提问作者yozawiratama

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:41:25