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

如何用Python实现批量图像自动裁剪与透视矫正(仿CamScanner效果)

棋盘格图像批量裁剪与俯视矫正方案

相机标定主要用于消除镜头畸变,你需要的是透视变换实现鸟瞰视角矫正,以下是基于OpenCV的可行方案,无需依赖标定数据:

核心步骤

  • 图像预处理:灰度化+高斯模糊+Canny边缘检测,突出棋盘格轮廓
  • 轮廓检测与筛选:提取图像中最大的四边形轮廓(对应棋盘格边界)
  • 顶点排序:将检测到的四边形顶点按左上、右上、右下、左下顺序排列
  • 透视变换:将不规则四边形映射为矩形,得到俯视视角的棋盘格图像
  • 批量处理:遍历指定目录下的所有图像,自动执行上述流程

完整代码实现

import cv2
import numpy as np
import os

def get_chessboard_corners(img):
    # 预处理
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5,5), 0)
    edges = cv2.Canny(blur, 50, 150)
    
    # 检测轮廓
    contours, _ = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 筛选面积最大的轮廓
    contours = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
    
    target_contour = None
    for cnt in contours:
        perimeter = cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, 0.02 * perimeter, True)
        # 筛选四边形轮廓
        if len(approx) == 4:
            target_contour = approx
            break
    
    if target_contour is None:
        return None
    
    # 顶点排序:左上、右上、右下、左下
    pts = target_contour.reshape(4, 2)
    rect = np.zeros((4, 2), dtype="float32")
    
    # 按x+y排序,最小的是左上,最大的是右下
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]
    
    # 按x-y排序,最小的是右上,最大的是左下
    diff = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]
    
    return rect

def warp_chessboard(img, rect):
    (tl, tr, br, bl) = rect
    # 计算目标矩形的宽度和高度
    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(rect, dst)
    warped = cv2.warpPerspective(img, M, (maxWidth, maxHeight))
    
    return warped

def batch_process_images(input_dir, output_dir):
    # 创建输出目录
    os.makedirs(output_dir, exist_ok=True)
    
    for filename in os.listdir(input_dir):
        if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
            img_path = os.path.join(input_dir, filename)
            img = cv2.imread(img_path)
            if img is None:
                print(f"无法读取图像: {filename}")
                continue
            
            rect = get_chessboard_corners(img)
            if rect is None:
                print(f"未检测到棋盘格轮廓: {filename}")
                continue
            
            warped_img = warp_chessboard(img, rect)
            output_path = os.path.join(output_dir, f"corrected_{filename}")
            cv2.imwrite(output_path, warped_img)
            print(f"处理完成: {filename}")

# 示例调用
if __name__ == "__main__":
    INPUT_DIR = "input_images"  # 替换为你的输入目录
    OUTPUT_DIR = "output_images"  # 替换为你的输出目录
    batch_process_images(INPUT_DIR, OUTPUT_DIR)

关键说明

  1. 轮廓筛选逻辑:优先选择面积最大的四边形,确保是棋盘格的外边界,避免干扰轮廓
  2. 顶点排序:通过坐标的和与差排序,保证透视变换的顶点顺序正确,避免图像颠倒
  3. 自适应尺寸:根据检测到的棋盘格实际尺寸计算目标矩形大小,保证矫正后的图像比例正确
  4. 批量处理:自动遍历指定目录下的所有图像,跳过无法处理的文件并给出提示

如果部分图像检测效果不佳,可以调整以下参数:

  • Canny边缘检测的阈值(cv2.Canny(blur, 50, 150)中的50和150)
  • 轮廓近似的精度(0.02 * perimeter中的0.02,可在0.01-0.05之间微调)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 22:10:42