Python OpenCV 图像矫正的原理与实现

这篇具有很好参考价值的文章主要介绍了Python OpenCV 图像矫正的原理与实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目描述

目录hw1下的图像是一些胶片的照片,请将其进行度量矫正。

推荐流程:采用Canny算子,检测边缘点;采用Hough直线检测,根据边缘点检测胶片边缘对应的4条直线;4条直线在图像平面中的交点为胶片图像的4个顶点。根据4个顶点与真实世界中胶片的位置(假设胶片图像长宽比为4:3),得到两个平面之间的单应变换矩阵,并根据单应变换矩阵实现图像矫正。

基本思路

  • 使用Canny算子,检测边缘点;
  • 以边缘点作为输入,采用Hough直线检测,检测出最多点共线的四条直线,这四条直线的交点就是照片中屏幕的四个顶点;
  • 假设胶片图像长宽比为4:3,那么此时已知四个匹配的点,可以求解出两个平面之间的单应变换矩阵;
  • 从而可以使用原图像、单应变换矩阵,对原图像进行变换,即可实现图像矫正。

实现日志

Canny边缘检测:Python OpenCV Canny边缘检测算法的原理与实现_乔卿的博客-CSDN博客

Hough直线检测:Python OpenCV Hough直线检测算法的原理与实现_乔卿的博客-CSDN博客

在具体实现时,发现对于给定的图像,几乎不可能通过调整阈值的方式,使得Hough检测到的直线刚好是屏幕边框。经过多轮调整,在下界为180、上界为260时取得了较为理想的结果,如下图所示。

opencv-python 图像矫正,计算机视觉,opencv,python,计算机视觉,人工智能

对于三张图像,经过实验,最终选择的最佳阈值为:

correct('images/1.jpeg', 180, 260)
correct('images/2.jpeg', 30, 100)
correct('images/3.jpeg', 100, 160)

但即便是最佳阈值,也无法做到仅检测出四条线。思考过后,决定加入一步人工筛选。有两种可行的技术方案:

  • 人工筛选直线
  • 人工筛选交点

考虑到如果筛选交点的话,工作量明显比筛选直线更大,所以选择人工筛选直线。后面有时间的话考虑加入图形化界面,目前因时间原因,选择专注于算法本身,暂不考虑可视化编程。直接显示出下图用于筛选:

opencv-python 图像矫正,计算机视觉,opencv,python,计算机视觉,人工智能

这里符合条件的直线id为2、3、6、7。求解得到的交点:

opencv-python 图像矫正,计算机视觉,opencv,python,计算机视觉,人工智能

opencv-python 图像矫正,计算机视觉,opencv,python,计算机视觉,人工智能

我们假设目标图像是4:3的,也就是其大小为(800, 600),从而我们可以确定目标图像中四个关键点位置为[0, 0], [800, 0], [0, 600], [800, 600]。为了保证交点与目标点一一对应,最为高效的解决方案是,我们筛选图像的时候,按照上、左、下、右的顺序即可。

核心代码

def correct(image_path, threshold1, threshold2):
    # 读取图像并转换为灰度图像
    image = cv2.imread(image_path)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # 使用Canny算子检测边缘
    edges = canny_detect(gray, threshold1, threshold2, show=False)

    # 使用Hough检测直线
    lines = hough_detect(image, edges, show=False)

    # 手动筛选
    for id, line in enumerate(lines):
        rho, theta = line[0]
        x1, y1, x2, y2 = convert_polar_to_two_points(rho, theta)
        temp_image = image.copy()
        cv2.line(temp_image, (x1, y1), (x2, y2), (255, 0, 0), 7)
        plt.subplot(5, 5, id + 1)
        plt.imshow(temp_image)
        plt.title('{}'.format(id))
        plt.xticks([])
        plt.yticks([])
    plt.show()
    choose = input('请输入您选择的直线的id,以空格分隔:').split(' ')

    # 求解交点
    crossover_points = []
    assert len(choose) == 4
    for i in range(4):
        for j in range(i+1, 4):
            rho1, theta1 = lines[int(choose[i])][0]
            rho2, theta2 = lines[int(choose[j])][0]
            # 如果角度差太小,认为它们是平行线
            if abs(theta2 - theta1) > np.pi / 8 and abs(theta2 - theta1) < np.pi * 7 / 8:
                crossover_points.append(cal_crossover(rho1, theta1, rho2, theta2))

    # 确定变换前后的坐标
    before = np.float32(crossover_points)
    after = np.float32([[0, 0], [800, 0], [0, 600], [800, 600]])

    # 单应变换
    h = cv2.getPerspectiveTransform(before, after)
    result = cv2.warpPerspective(image, h, (800, 600))

    cv2.imwrite(image_path.split('.')[0] + '_correct.jpeg', result)
    return result

完整代码

import cv2
import numpy as np
from matplotlib import pyplot as plt


def canny_detect(gray, threshold1=100, threshold2=200, show=True):
    # 获取边缘检测结果
    edges = cv2.Canny(gray, threshold1, threshold2, apertureSize=3)

    if show:
        # 绘制原图
        plt.subplot(121)
        plt.imshow(gray, cmap='gray')
        plt.title('Original Image')
        plt.xticks([])
        plt.yticks([])

        # 绘制边缘图
        plt.subplot(122)
        plt.imshow(edges, cmap='gray')
        plt.title('Edge Image')
        plt.xticks([])
        plt.yticks([])

        plt.show()

    # 返回的是一个二值图像
    return edges


def hough_detect(image, edges, show=True):
    # 使用Hough检测直线
    lines = cv2.HoughLines(edges, 1, np.pi/180, 200)

    if show:
        # 绘制直线
        for line in lines:
            rho, theta = line[0]
            x1, y1, x2, y2 = convert_polar_to_two_points(rho, theta)
            cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)

        cv2.imshow('line,jpg', image)
        cv2.waitKey()

    return lines


# 将极坐标转换为两点
def convert_polar_to_two_points(rho, theta):
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + 10000 * (-b))
    y1 = int(y0 + 10000 * (a))
    x2 = int(x0 - 10000 * (-b))
    y2 = int(y0 - 10000 * (a))
    return x1, y1, x2, y2


# 一般式 Ax+By+C=0
def GeneralEquation(x1, y1, x2, y2):
    A = y2 - y1
    B = x1 - x2
    C = x2 * y1 - x1 * y2
    return A, B, C


# 求解交点
def cal_crossover(rho1, theta1, rho2, theta2):
    x11, y11, x12, y12 = convert_polar_to_two_points(rho1, theta1)
    x21, y21, x22, y22 = convert_polar_to_two_points(rho2, theta2)
    A1, B1, C1 = GeneralEquation(x11, y11, x12, y12)
    A2, B2, C2 = GeneralEquation(x21, y21, x22, y22)
    m = A1 * B2 - A2 * B1
    x = (C2 * B1 - C1 * B2) / m
    y = (C1 * A2 - C2 * A1) / m
    return [x, y]


def correct(image_path, threshold1, threshold2):
    # 读取图像并转换为灰度图像
    image = cv2.imread(image_path)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # 使用Canny算子检测边缘
    edges = canny_detect(gray, threshold1, threshold2, show=False)

    # 使用Hough检测直线
    lines = hough_detect(image, edges, show=False)

    # 手动筛选,按照上、左、下、右的顺序
    for id, line in enumerate(lines):
        rho, theta = line[0]
        x1, y1, x2, y2 = convert_polar_to_two_points(rho, theta)
        temp_image = image.copy()
        cv2.line(temp_image, (x1, y1), (x2, y2), (255, 0, 0), 7)
        plt.subplot(5, 5, id + 1)
        plt.imshow(temp_image)
        plt.title('{}'.format(id))
        plt.xticks([])
        plt.yticks([])
    plt.show()
    choose = input('请输入您选择的直线的id,以空格分隔:').split(' ')

    # 求解交点
    crossover_points = []
    assert len(choose) == 4
    for i in range(4):
        for j in range(i+1, 4):
            rho1, theta1 = lines[int(choose[i])][0]
            rho2, theta2 = lines[int(choose[j])][0]
            # 如果角度差太小,认为它们是平行线
            if abs(theta2 - theta1) > np.pi / 8 and abs(theta2 - theta1) < np.pi * 7 / 8:
                print(abs(theta2 - theta1) / np.pi)
                print(choose[i], choose[j])
                crossover_points.append(cal_crossover(rho1, theta1, rho2, theta2))
                temp_image = image.copy()
                cv2.circle(temp_image, (int(cal_crossover(rho1, theta1, rho2, theta2)[0]), int(cal_crossover(rho1, theta1, rho2, theta2)[1])), 10, (255, 0, 0), 2)
                cv2.imshow('point', temp_image)
                cv2.waitKey()

    # 确定变换前后的坐标
    before = np.float32(crossover_points)
    after = np.float32([[0, 0], [800, 0], [0, 600], [800, 600]])

    # 单应变换
    h = cv2.getPerspectiveTransform(before, after)
    result = cv2.warpPerspective(image, h, (800, 600))

    cv2.imwrite(image_path.split('.')[0] + '_correct.jpeg', result)
    return result


# correct('images/1.jpeg', 180, 260)
# correct('images/2.jpeg', 30, 100)
correct('images/3.jpeg', 100, 160)

矫正结果

opencv-python 图像矫正,计算机视觉,opencv,python,计算机视觉,人工智能

opencv-python 图像矫正,计算机视觉,opencv,python,计算机视觉,人工智能

opencv-python 图像矫正,计算机视觉,opencv,python,计算机视觉,人工智能文章来源地址https://www.toymoban.com/news/detail-595170.html

到了这里,关于Python OpenCV 图像矫正的原理与实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenCv-Python图像特征识别

    本练习学习了OpenCv-Python关于图像特征识别的一些算法,算法理解起来较为困难,但函数用起来上手比较快,主要要明白函数的输入输出的含义。 虽然算法理解不容易,但程序还算有趣,输入是一个完整的图片和一组图片碎片,如下图,然后经过算法计算,把碎片匹配到正确

    2024年02月07日
    浏览(54)
  • OpenCV-Python(49):图像去噪

    学习使用非局部平均值去噪算法去除图像中的噪音 学习函数cv2.fastNlMeansDenoising()、cv2.fastNlMeansDenoisingColored等         在前面的章节中我们已经学习了很多图像平滑技术,比如高斯平滑、中值平滑等。当噪声比较小时,这些技术的效果都是很好的。在这些技术中我们选取像

    2024年01月21日
    浏览(40)
  • OpenCV-Python中的图像基础操作

    首先读入一副图像: 获取像素值及修改的更好方法: img = cv2.imread(‘./resource/image/1.jpg’, cv2.IMREAD_COLOR) img.shape: 图像的形状(包括行数,列数,通道数的元组) img.size : 图像的像素数目 img.dtype :图像的数据类型 ROI(regionofinterest),感兴趣区域。机器视觉、图像处理中,从被

    2024年02月11日
    浏览(39)
  • opencv-python 将图像迷宫转为迷宫数组

    起因是我想做个自动走迷宫的外挂(其实是想做点实践),所以我需要在游戏中捕捉画面并自动寻路,然后再控制自动移动,此为第一部分:捕捉画面。 1.取得图像迷宫 2.处理图像 3.图像分割 4.生成数组 首先我们得捕捉屏幕画面,即获得迷宫图像,这里我是在steam上面找了一

    2024年02月07日
    浏览(48)
  • OpenCV-Python中的图像处理-图像直方图

    通过直方图你可以对整幅图像的灰度分布有一个整体的了解。直方图的 x 轴是灰度值( 0 到 255), y 轴是图片中具有同一个灰度的点的数目。 BINS:上面的直方图显示了每个灰度值对应的像素数。如果像素值为 0到255,你就需要 256 个数来显示上面的直方图。但是,如果你不需

    2024年02月12日
    浏览(61)
  • OpenCV-Python中的图像处理-视频分析

    学习使用 Meanshift 和 Camshift 算法在视频中找到并跟踪目标对象: Meanshift 算法的基本原理是和很简单的。假设我们有一堆点(比如直方 图反向投影得到的点),和一个小的圆形窗口,我们要完成的任务就是将这个窗 口移动到最大灰度密度处(或者是点最多的地方)。如下图所

    2024年02月12日
    浏览(53)
  • OpenCV-Python中的图像处理-模板匹配

    使用模板匹配可以在一幅图像中查找目标 函数: cv2.matchTemplate(), cv2.minMaxLoc() 模板匹配是用来在一副大图中搜寻查找模版图像位置的方法。 OpenCV 为我们提供了函数: cv2.matchTemplate()。和 2D 卷积一样,它也是用模板图像在输入图像(大图)上滑动,并在每一个位置对模板图像

    2024年02月12日
    浏览(45)
  • OpenCV-Python中的图像处理-霍夫变换

    霍夫(Hough)变换在检测各种形状的技术中非常流行,如果要检测的形状可以用数学表达式描述,就可以是使用霍夫变换检测它。即使要检测的形状存在一点破坏或者扭曲也是可以使用。 Hough直线变换,可以检测一张图像中的直线 cv2.HoughLines(image, rho, theta, threshold) return:返回值

    2024年02月12日
    浏览(45)
  • OpenCV-Python学习(21)—— OpenCV 图像几何变换之图像翻转(cv.flip、np.flip)

    1. 学习目标 学习 OpenCV 图像的翻转函数 cv.flip; 学习 NumPy 矩阵的反转函数 np.flip; 自己实现矩阵反转的函数。 2. OpenCV 翻转 翻转也称镜像,是指将图像沿轴线进行轴对称变换。水平镜像是将图像沿垂直中轴线进行左右翻转,垂直镜像是将图像沿水平中轴线进行上下翻转,水平

    2024年02月06日
    浏览(63)
  • 使用python-opencv对双目摄像头进行立体视觉图像矫正,去畸变

            1、一张棋盘图         可以直接从opencv官方github下载,这是一个拥有10*7个格子的棋盘,共有 9*6个角点,每个格子24mm ,本文所使用的就是这一个棋盘。你需要将它打印在A4纸上用于后续使用。(也可以根据官方教程自行设置棋盘大小OpenCV: Create calibration pattern)

    2024年02月10日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包