python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python OpenCV文档扫描与图像风格迁移

Python基于OpenCV实现文档扫描与图像风格迁移

作者:陈年老古董

想知道怎么用OpenCV把摄像头画面中的文档自动摆正并二值化吗,这篇文章手把手教你边缘检测、轮廓近似和透视变换的完整流程,还附赠一个用dnn模块实现风格迁移的小例子,把普通照片变成卡通效果,代码不长但很实用,快来试试吧

最近又捣鼓了两个 OpenCV 的小项目,一个是实时检测摄像头画面中的文档,通过透视变换把它“摆正”并二值化,有点像手机扫描软件;另一个是用训练好的神经网络模型对图片做风格迁移,把普通照片变成卡通或油画效果。代码都不长,但涉及的知识点挺实用,整理出来分享一下。

一、文档扫描与透视变换

这个例子实现了一个实时文档扫描功能:打开摄像头,检测画面中的四边形文档,然后利用透视变换把倾斜的文档转成正视图,最后做二值化处理,方便后续识别或保存。核心步骤是:边缘检测 → 轮廓近似 → 找到四边形 → 透视变换。

1. 导入库和辅助函数

import numpy as np
import cv2
def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(1)

2. 坐标排序函数 order_points

def order_points(pts):
    # 一共4个坐标点
    rect = np.zeros((4, 2), dtype="float32")  # 用来存储排序之后的坐标位置
    # 按顺序找到对应坐标0123分别是 左上,右上,右下,左下
    s = pts.sum(axis=1)  # 对pts矩阵的每一行进行求和操作。(x+y)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]

    diff = np.diff(pts, axis=1)  # 对pts矩阵的每一行进行求差操作。(y-x)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]
    return rect

这个函数的作用是把随意输入的四个点按“左上、右上、右下、左下”的顺序排好。

3. 透视变换函数 four_point_transform

def four_point_transform(image, pts):
    # 获取输入坐标点
    rect = order_points(pts)
    (tl, tr, br, bl) = rect

    # 计算输入的w和h值
    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(image, M, dsize=(maxWidth, maxHeight))

    # 返回变换后结果
    return warped

4. 打开摄像头并循环读取

cap = cv2.VideoCapture(0)  # 确保摄像头是可以启动的状态。
if not cap.isOpened():  # 打开失败
    print("Cannot open camera")
    exit()

while True:
    flag = 0  # 用于标识 当前是否检测到文档
    ret, image = cap.read()  # 如果正确读取帧,ret为True
    image=cv2.flip(image, 1) #画面反转
    orig = image.copy()
    if not ret:  # 读取失败,则退出循环
        print("不能读取摄像头")
        break
    cv_show("image", image)

5. 预处理:灰度、高斯模糊、边缘检测

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, ksize=(5, 5), sigmaX=0)
    edged = cv2.Canny(gray, threshold1=15, threshold2=45)
    cv_show('1', edged)

6. 查找轮廓并排序

    cnts = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
    cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:3]
    image_contours = cv2.drawContours(image, cnts, -1, color=(0, 255, 0), thickness=2)
    cv_show("image_contours", image_contours)

7. 遍历轮廓,找到四边形文档

    for c in cnts:
        # 计算轮廓近似
        peri = cv2.arcLength(c, closed=True)  #计算轮廓的周长
        # C表示输入的点集
        # epsilon表示从原始轮廓到近似轮廓的最大距离,它是一个准确度参数
        # True表示封闭的
        approx = cv2.approxPolyDP(c, 0.05 * peri, closed=True)  # 轮廓近似
        area = cv2.contourArea(approx)
        # 4个点的时候就拿出来
        if area > 30000 and len(approx) == 4:  #20000
            screenCnt = approx
            flag = 1
            print(peri, area)
            print('检测到文档')
            break

8. 如果检测到文档,进行透视变换和二值化

    if flag == 1:
        # 展示结果
        # print("STEP 2: 获取轮廓")
        image_contours = cv2.drawContours(image, contours=[screenCnt], contourIdx=0, color=(0, 255, 0), thickness=2)
        cv_show("image", image_contours)
        # 透视变换
        warped = four_point_transform(orig, screenCnt.reshape(4, 2))
        cv_show("warped", warped)
        # 二值处理
        warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
        ref = cv2.threshold(warped,135, 255, cv2.THRESH_BINARY)[1]
        # ref = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
        cv_show("ref", ref)
    if cv2.waitKey(20)==27:
        break

9. 释放资源

cap.release()
cv2.destroyAllWindows()

小结:这个例子完整演示了从摄像头采集图像、边缘检测、轮廓逼近到透视变换的流程,是实现文档扫描的基础。实际应用中还可以加入自动检测阈值、去除阴影等优化。

二、图像风格迁移:用神经网络把照片变成卡通画

第二个例子使用一个已经训练好的风格迁移模型(candy.t7)对输入图片进行处理,生成卡通风格的图像。OpenCV 的 dnn 模块可以加载多种深度学习模型,使用起来很方便。

1. 读取并显示输入图像

import cv2
image = cv2.imread('haimianbaobao.png')
cv2.imshow('yuan tu', image)
cv2.waitKey(0)

2. 图像预处理 blobFromImage

(h, w) = image.shape[:2]
blob = cv2.dnn.blobFromImage(image, scalefactor=1, size=(w, h), mean=(0, 0, 0), swapRB=False, crop=False)

3. 加载模型并前向传播

net = cv2.dnn.readNet(r'model\candy.t7')
net.setInput(blob)
out = net.forward()

4. 输出后处理并显示

# ======输出处理=======
# 重塑形状(忽略第1维),4维变3维
# 调整输出out的形状,模型推理输出out是四维BCHW形式的,调整为三维CHW形式
out_new = out.reshape(out.shape[1], out.shape[2], out.shape[3])

# 对输入的数组(或图像)进行归一化处理,使其数值范围在指定的范围内
cv2.normalize(out_new, out_new, norm_type=cv2.NORM_MINMAX)

# 转置输出结果的维度
result = out_new.transpose(1, 2, 0)

# 显示转换后的图像
cv2.imshow('Stylized Image', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

小结:这个例子展示了 OpenCV 的 dnn 模块如何加载预训练模型并做推理,核心就三步:blobFromImage 预处理、forward 前向传播、后处理转回图像。更换不同的模型文件就能实现不同的风格效果。

以上两个例子覆盖了 OpenCV 中传统图像处理和深度学习模块的常见用法,代码都不复杂,跑通之后可以再根据自己的需求调整参数或模型。希望对你有所帮助,有问题欢迎在评论区留言。

以上就是Python基于OpenCV实现文档扫描与图像风格迁移的详细内容,更多关于Python OpenCV文档扫描与图像风格迁移的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文