【图像处理基石】如何进行图像畸变校正?

在这里插入图片描述
图像畸变校正常用于计算机视觉、摄影测量学和机器人导航等领域,能够修正因镜头光学特性或传感器排列问题导致的图像失真。下面我将介绍几种常用的图像畸变校正算法,并提供Python实现和测试用例。

常用算法及Python实现

1. 径向畸变校正

径向畸变是最常见的畸变类型,表现为图像中心区域正常,边缘区域出现拉伸或压缩。校正公式如下:

import numpy as np
import cv2
from matplotlib import pyplot as pltdef correct_radial_distortion(image, k1, k2, k3=0):"""校正图像的径向畸变参数:image: 输入的畸变图像k1, k2, k3: 径向畸变系数返回:corrected_image: 校正后的图像"""h, w = image.shape[:2]# 创建网格坐标x, y = np.meshgrid(np.arange(w), np.arange(h))x_c, y_c = w / 2, h / 2  # 图像中心# 计算离中心的距离r = np.sqrt((x - x_c)**2 + (y - y_c)**2)# 径向畸变校正公式x_distorted = (x - x_c) * (1 + k1 * r**2 + k2 * r**4 + k3 * r**6) + x_cy_distorted = (y - y_c) * (1 + k1 * r**2 + k2 * r**4 + k3 * r**6) + y_c# 使用双线性插值进行重采样corrected_image = np.zeros_like(image)# 处理整数坐标x_distorted_int = np.clip(x_distorted.astype(int), 0, w - 1)y_distorted_int = np.clip(y_distorted.astype(int), 0, h - 1)# 应用校正if len(image.shape) == 3:  # 彩色图像corrected_image[y, x] = image[y_distorted_int, x_distorted_int]else:  # 灰度图像corrected_image[y, x] = image[y_distorted_int, x_distorted_int]return corrected_image# 测试用例
def test_radial_distortion():# 创建测试图像(棋盘格)test_image = np.zeros((400, 400), dtype=np.uint8)for i in range(8):for j in range(8):if (i + j) % 2 == 0:test_image[i*50:(i+1)*50, j*50:(j+1)*50] = 255# 引入径向畸变(k1=0.00005, k2=0.0000002)distorted_image = correct_radial_distortion(test_image, 0.00005, 0.0000002)# 校正径向畸变corrected_image = correct_radial_distortion(distorted_image, -0.00005, -0.0000002)# 显示结果plt.figure(figsize=(15, 5))plt.subplot(131), plt.imshow(test_image, cmap='gray')plt.title('原始图像'), plt.axis('off')plt.subplot(132), plt.imshow(distorted_image, cmap='gray')plt.title('畸变图像'), plt.axis('off')plt.subplot(133), plt.imshow(corrected_image, cmap='gray')plt.title('校正图像'), plt.axis('off')plt.show()# 运行测试
test_radial_distortion()
2. 切向畸变校正

切向畸变是由于镜头与图像传感器不平行引起的,表现为图像局部区域的倾斜。校正公式如下:

def correct_tangential_distortion(image, p1, p2):"""校正图像的切向畸变参数:image: 输入的畸变图像p1, p2: 切向畸变系数返回:corrected_image: 校正后的图像"""h, w = image.shape[:2]# 创建网格坐标x, y = np.meshgrid(np.arange(w), np.arange(h))x_c, y_c = w / 2, h / 2  # 图像中心# 计算离中心的距离r = np.sqrt((x - x_c)**2 + (y - y_c)**2)# 切向畸变校正公式x_distorted = (x - x_c) + (2 * p1 * (x - x_c) * (y - y_c) + p2 * (r**2 + 2 * (x - x_c)**2)) + x_cy_distorted = (y - y_c) + (p1 * (r**2 + 2 * (y - y_c)**2) + 2 * p2 * (x - x_c) * (y - y_c)) + y_c# 使用双线性插值进行重采样corrected_image = np.zeros_like(image)# 处理整数坐标x_distorted_int = np.clip(x_distorted.astype(int), 0, w - 1)y_distorted_int = np.clip(y_distorted.astype(int), 0, h - 1)# 应用校正if len(image.shape) == 3:  # 彩色图像corrected_image[y, x] = image[y_distorted_int, x_distorted_int]else:  # 灰度图像corrected_image[y, x] = image[y_distorted_int, x_distorted_int]return corrected_image# 测试用例
def test_tangential_distortion():# 创建测试图像(棋盘格)test_image = np.zeros((400, 400), dtype=np.uint8)for i in range(8):for j in range(8):if (i + j) % 2 == 0:test_image[i*50:(i+1)*50, j*50:(j+1)*50] = 255# 引入切向畸变(p1=0.001, p2=0.0008)distorted_image = correct_tangential_distortion(test_image, 0.001, 0.0008)# 校正切向畸变corrected_image = correct_tangential_distortion(distorted_image, -0.001, -0.0008)# 显示结果plt.figure(figsize=(15, 5))plt.subplot(131), plt.imshow(test_image, cmap='gray')plt.title('原始图像'), plt.axis('off')plt.subplot(132), plt.imshow(distorted_image, cmap='gray')plt.title('畸变图像'), plt.axis('off')plt.subplot(133), plt.imshow(corrected_image, cmap='gray')plt.title('校正图像'), plt.axis('off')plt.show()# 运行测试
test_tangential_distortion()
3. 使用OpenCV进行相机标定与畸变校正

实际应用中,通常使用OpenCV提供的相机标定功能来自动计算畸变系数:

def camera_calibration_and_undistortion():"""使用OpenCV进行相机标定和图像畸变校正"""# 准备对象点,如 (0,0,0), (1,0,0), (2,0,0) ..., (7,5,0)objp = np.zeros((6*8, 3), np.float32)objp[:, :2] = np.mgrid[0:8, 0:6].T.reshape(-1, 2)# 存储对象点和图像点的数组objpoints = []  # 3D点在现实世界中的坐标imgpoints = []  # 2D点在图像平面中的坐标# 生成模拟标定图像(通常需要使用多幅图像)images = []for i in range(5):img = np.zeros((480, 640), dtype=np.uint8)# 生成模拟的棋盘格角点corners = np.zeros((48, 2), dtype=np.float32)for j in range(48):x = 50 + (j % 8) * 60 + np.random.randint(-5, 6)  # 添加随机畸变y = 50 + (j // 8) * 60 + np.random.randint(-5, 6)corners[j] = [x, y]imgpoints.append(corners)objpoints.append(objp)# 在图像上绘制角点for corner in corners:cv2.circle(img, (int(corner[0]), int(corner[1])), 5, 255, -1)images.append(img)# 相机标定ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, images[0].shape[::-1], None, None)# 生成测试图像test_img = np.zeros((480, 640), dtype=np.uint8)for i in range(8):for j in range(6):cv2.circle(test_img, (100 + i * 60, 100 + j * 60), 10, 255, -1)# 畸变校正h, w = test_img.shape[:2]newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))undistorted_img = cv2.undistort(test_img, mtx, dist, None, newcameramtx)# 显示结果plt.figure(figsize=(10, 5))plt.subplot(121), plt.imshow(test_img, cmap='gray')plt.title('畸变图像'), plt.axis('off')plt.subplot(122), plt.imshow(undistorted_img, cmap='gray')plt.title('校正图像'), plt.axis('off')plt.show()# 返回标定结果return mtx, dist# 运行相机标定和畸变校正
camera_matrix, distortion_coeffs = camera_calibration_and_undistortion()
print("相机内参矩阵:\n", camera_matrix)
print("畸变系数:\n", distortion_coeffs)

算法解释

  1. 径向畸变校正

    • 径向畸变是最常见的畸变类型,表现为图像中心区域正常,边缘区域出现拉伸或压缩。
    • 校正公式基于多项式模型,通过径向畸变系数(k1, k2, k3)来调整像素位置。
  2. 切向畸变校正

    • 切向畸变是由于镜头与图像传感器不平行引起的,表现为图像局部区域的倾斜。
    • 校正公式使用切向畸变系数(p1, p2)来调整像素位置。
  3. 相机标定与OpenCV实现

    • 实际应用中,通常使用已知的标定板(如棋盘格)来计算相机的内参矩阵和畸变系数。
    • OpenCV提供了完整的相机标定和畸变校正功能,能够自动计算所有参数并进行图像校正。

以上代码实现了常见的图像畸变校正算法,并提供了测试用例来验证算法的有效性。在实际应用中,你可能需要根据具体的相机型号和场景来调整参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/83976.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯_DS18B20温度传感器---新手入门级别超级详细解析

目录 一、引言 DS18B20的原理图 单总线简介: ​编辑暂存器简介: DS18B20的温度转换与读取流程 二、代码配置 maic文件 疑问 关于不同格式化输出符号的使用 为什么要rd_temperature()/16.0? onewire.h文件 这个配置为什么要先读lo…

MySQL的并发事务问题及事务隔离级别

一、并发事务问题 1). 赃读:一个事务读到另外一个事务还没有提交的数据。 比如 B 读取到了 A 未提交的数据。 2). 不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。 事务 A 两次读取同一条记录&…

密码学基础——SM4算法

博客主页:christine-rr-CSDN博客 ​​​​专栏主页:密码学 📌 【今日更新】📌 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 ​编辑…

练习:对象数组 4

定义数组存储 4 个女朋友的对象。女朋友的属性:姓名、年龄、性别、爱好;要求1:计算出四个女朋友的平均年龄;要求2:统计年龄比平均值低的女朋友有几个?并把他们的所有信息打印出来。 代码: //对…

React Hooks 基础指南

React Hooks 是 React 16.8 引入的重要特性,它允许开发者在函数组件中使用状态和其他 React 特性。本文将详细介绍 6 个最常用的 React Hooks。 1. useState useState 是最常用的 Hook,用于在函数组件中添加 state。 import React, { useState } from…

【Python 算法零基础 4.排序 ⑥ 快速排序】

既有锦绣前程可奔赴,亦有往日岁月可回首 —— 25.5.25 选择排序回顾 ① 遍历数组:从索引 0 到 n-1(n 为数组长度)。 ② 每轮确定最小值:假设当前索引 i 为最小值索引 min_index。从 i1 到 n-1 遍历,若找到…

处理git没做修改,但是文件显示变更的情况

使用 TortoiseGit(小乌龟 Git) 时遇到 “文件内容没改,但显示为变更,提示有 n 行删除、n 行添加”,你可以按照以下步骤操作来排查并解决问题: ✅ 一、定位问题根源(是否为行尾差异)…

智慧货运飞船多维度可视化管控系统

图扑搭建智慧货运飞船可视化系统,借数字孪生技术,高精度复刻货运飞船外观、结构与运行场景。整合多维度数据,实时呈现飞行状态、设备参数等信息,助力直观洞察货运飞船运行逻辑,为航天运维、任务推演及决策提供数字化支…

maven微服务${revision}依赖打包无法识别

1、场景描述 我现在又一个微服务项目&#xff0c;父pom的版本&#xff0c;使用<properties>定义好&#xff0c;如下所示&#xff1a; <name>ypsx-finance-center</name> <artifactId>ypsx-finance</artifactId> <packaging>pom</pack…

详解代理型RAG与MCP服务器集成

检索增强型生成(RAG)将语言模型与外部知识检索相结合,让模型的回答基于最新的事实,而不仅仅是其训练数据呢。 RAG(高级别) 在 RAG 流程中,用户查询用于搜索知识库(通常通过向量数据库中的嵌入来实现),并将检索到的最相关文档“增强”到模型的提示中,以帮助生成事实…

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…

如何防止服务器被用于僵尸网络(Botnet)攻击 ?

防止服务器被用于僵尸网络&#xff08;Botnet&#xff09;攻击是关键的网络安全措施之一。僵尸网络是黑客利用大量被感染的计算机、服务器或物联网设备来发起攻击的网络。以下是关于如何防止服务器被用于僵尸网络攻击的技术文章&#xff1a; 防止服务器被用于僵尸网络&#xff…

贪心算法应用:硬币找零问题详解

贪心算法与硬币找零问题详解 贪心算法&#xff08;Greedy Algorithm&#xff09;在解决优化问题时表现出简洁高效的特点&#xff0c;尤其适用于特定结构的组合优化问题。本文将用2万字篇幅&#xff0c;深入探讨贪心算法在硬币找零问题中的应用&#xff0c;覆盖算法原理、正确性…

Java高级 | 【实验一】Springboot安装及测试 |最新

隶属文章&#xff1a;Java高级 | &#xff08;二十二&#xff09;Java常用类库-CSDN博客 目录 一、SpringBoot的特点 二、Spring Boot安装及测试 &#xff08;一&#xff09;安装Intellij IDEA &#xff08;二&#xff09;安装MySQL &#xff08;三&#xff09;安装postma…

C# WPF 左右布局实现学习笔记(1)

开发流程视频&#xff1a; https://www.youtube.com/watch?vCkHyDYeImjY&ab_channelC%23DesignPro Git源码&#xff1a; GitHub - CSharpDesignPro/Page-Navigation-using-MVVM: WPF - Page Navigation using MVVM 1. 新建工程 新建WPF应用&#xff08;.NET Framework) 2.…

从零开始,学会上传,更新,维护github仓库

以下是一份从头到尾、覆盖安装、配置、创建仓库、上传项目到 GitHub 的完整教程。全程使用通用示例&#xff0c;不包含任何具体的仓库链接&#xff0c;仅供参考。 一、准备工作 1. 注册 GitHub 账号 打开浏览器&#xff0c;访问 GitHub 官网&#xff08;输入 “GitHub” 即可找…

使用 Docker Compose 从零部署 TeamCity + PostgreSQL(详细新手教程)

JetBrains TeamCity 是一款专业的持续集成&#xff08;CI&#xff09;服务器工具&#xff0c;支持各种编程语言和构建流程。本文将一步一步带你用 Docker 和 Docker Compose 快速部署 TeamCity&#xff0c;搭配 PostgreSQL 数据库&#xff0c;并确保 所有操作新手可跟着做。 一…

微软推出SQL Server 2025技术预览版,深化人工智能应用集成

在Build 2025 大会上&#xff0c;微软向开发者社区开放了SQL Server 2025的测试版本。该版本的技术改进主要涵盖人工智能功能集成、系统性能优化与开发工具链升级三个维度&#xff0c;展示了数据库管理系统在智能化演进方向上的重要进展。 智能数据处理功能更新 新版本的技术亮…

企业管理中,商业智能BI主要做哪些事情?

开门见山的告诉大家&#xff0c;在企业管理中商业智能BI 主要就做三件事&#xff1a;拉通数据、整合数据、数据可视化展现。 技术角度的商业智能BI 从技术的角度来讲&#xff0c;商业智能BI是一套完整的由数据仓库、查询报表、数据分析等组成的数据类技术解决方案。它有一个非…

openharmony5.0.0中kernel子系统编译构建流程概览(rk3568)

概述 在梳理openharmony对linux内核做了哪些更改时&#xff0c;简单梳理了下kernel部分的编译构建流程&#xff0c;并根据源码做了简单论证。分享出来&#xff0c;希望对大家有所帮助。 系统版本:openharmony5.0.0 开发板:dayu200 编译环境:ubuntu22 执行流程 在kernel\l…