【图像处理基石】如何进行图像畸变校正?
图像畸变校正常用于计算机视觉、摄影测量学和机器人导航等领域,能够修正因镜头光学特性或传感器排列问题导致的图像失真。下面我将介绍几种常用的图像畸变校正算法,并提供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)
算法解释
-
径向畸变校正:
- 径向畸变是最常见的畸变类型,表现为图像中心区域正常,边缘区域出现拉伸或压缩。
- 校正公式基于多项式模型,通过径向畸变系数(k1, k2, k3)来调整像素位置。
-
切向畸变校正:
- 切向畸变是由于镜头与图像传感器不平行引起的,表现为图像局部区域的倾斜。
- 校正公式使用切向畸变系数(p1, p2)来调整像素位置。
-
相机标定与OpenCV实现:
- 实际应用中,通常使用已知的标定板(如棋盘格)来计算相机的内参矩阵和畸变系数。
- OpenCV提供了完整的相机标定和畸变校正功能,能够自动计算所有参数并进行图像校正。
以上代码实现了常见的图像畸变校正算法,并提供了测试用例来验证算法的有效性。在实际应用中,你可能需要根据具体的相机型号和场景来调整参数。
相关文章:

【图像处理基石】如何进行图像畸变校正?
图像畸变校正常用于计算机视觉、摄影测量学和机器人导航等领域,能够修正因镜头光学特性或传感器排列问题导致的图像失真。下面我将介绍几种常用的图像畸变校正算法,并提供Python实现和测试用例。 常用算法及Python实现 1. 径向畸变校正 径向畸变是最常…...
软件开发项目管理工具选型及禅道开源版安装
软件开发项目管理工具选型及禅道开源版安装 为啥选禅道 你以为我选禅道之前没有对比吗? 作为Java码农,首先想到的就是Jira,然而它太重了。。 我们用企微作为沟通工具,腾讯的TAPD的确好用,但是它不开源啊,…...
【架构艺术】平衡技术架构设计和预期的产品形态
近期笔者因为工作原因,开始启动team内部部分技术项目的重构。在事情启动的过程中,内部对于这件事情的定性和投入有一些争论,但最终还是敲定了下来。其中部分争论点主要在于产品形态,因为事情涉及到跨部门合作,所以产品…...

电力系统时间同步系统
电力系统中,电压、电流、功率变化等特征量测量都是时间相关函数[1],统一精准的时间源对于电网安全稳定运行至关重要,因此,电力系统运行规程[2]中明确要求继电保护装置、自动化装置、安全稳定控制系统、能量管理系统和生产信息管理…...

Vue使用toFixed保留两位小数的三种写法
第一种:直接写在js里面,这是最简单的 val.toFixed(2)第二种:在ElementUi表格中使用 第三种:在取值符号中使用 {{}} 定义一个方法 towNumber(val) { return val.toFixed(2) } 使用 {{ towNumber(row.equiV…...
华为云【Astro zero】如何做“设备编辑”页面
目录 一、整体原理概述(逻辑图+原理) 1. 页面组件组装(用户交互界面) 2. 数据模型(数据临时存储) 3. 页面事件(逻辑交互) 二、详细操作步骤(按功能模块分) ✅【1】页面创建与结构组装 ✅【2】定义自定义模型与字段(临时数据绑定) ✅【3】定义服务模型(与后…...

Arch安装botw-save-state
devkitPro https://blog.csdn.net/qq_39942341/article/details/148387077?spm1001.2014.3001.5501 cargo https://blog.csdn.net/qq_39942341/article/details/148387783?spm1001.2014.3001.5501 megaton https://blog.csdn.net/qq_39942341/article/details/148388164?spm…...

电脑为什么换个ip就上不了网了
在日常使用电脑上网时,很多人可能遇到过这样的问题:当IP地址发生变化后,突然就无法连接网络了。当电脑更换IP地址后无法上网,这一现象可能由多种因素导致,涉及网络配置、硬件限制或运营商策略等层面。以下是系统性分析…...
NULL与空字符串的区别:数据库专家详解
NULL与空字符串的区别:数据库专家详解 1. NULL的概念解析 1.1 NULL的定义 在数据库系统中,NULL是一个特殊标记,表示"未知"或"不存在"的值。它不是任何数据类型的实例,而是表示缺失值的标记。 go专栏&#…...

github 2FA双重认证丢失解决
文章目录 前言一. 凭借ssh 解锁步骤1.1 要求输入设备码1.2.进入二重验证界面1.3.开始2FA恢复1.4.选择使用ssh验证 二.预防措施2.1 云盘上传git_recover_codes.txt2.2 开启多源FA认证2.2.1 大陆无法使用手机验证码 三.参考资料 前言 场景:没有意识到github recovery …...

linux驱动 - 5: simple usb device驱动
参考第2节, 准备好编译环境并实现hello.ko: linux驱动 - 2: helloworld.ko_linux 驱动开发 hello world ko-CSDN博客 下面在hello模块的基础上, 添加代码, 实现一个usb设备驱动的最小骨架. #include <linux/init.h> #include <linux/module.h> #include <lin…...
OpenCV CUDA模块直方图计算------在 GPU 上计算输入图像的直方图(histogram)函数histEven()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 该函数用于在 GPU 上计算输入图像的直方图(histogram)。它将像素值区间均匀划分为若干个 bin(桶)…...
QT/c++航空返修数据智能分析系统
简介 1、区分普通用户和管理员 2、界面精美 3、功能丰富 4、使用cppjieba分词分析数据 5、支持数据导入导出 6、echarts展示图表 效果展示 演示链接 源码获取 int main(){ //非白嫖 printf("📡:%S","joyfelic"); return 0; }...
Spring Security架构中过滤器的实现
Spring Security过滤器基础 过滤器链工作原理 在Spring Security架构中,过滤器链(Filter Chain)是安全机制的核心实现方式。当HTTP请求到达时,会依次通过一系列具有明确顺序的过滤器。例如认证过滤器会拦截请求并将认证职责委托给授权管理器。若需要在认证前执行特定逻辑…...
Playwright Python API 测试:从入门到实践
Playwright Python API 测试:从入门到实践 在现代软件开发中,API 测试是确保应用程序后端功能正常运行的关键环节。Playwright 是一个强大的自动化测试工具,支持多种编程语言,其中包括 Python。通过 Playwright,我们可…...

ETL脚本节点使用的方式
随着大数据时代的到来,企业对数据处理的需求日益增长,ETL 作为数据整合的关键技术,逐渐走进我们的视野。本文将为您揭秘 ETL 脚本节点的使用方式,助您轻松驾驭数据处理新境界。 一、ETL脚本的优势 1.提高效率:ETL 脚…...

PH热榜 | 2025-06-02
1. Circuit Tracer 标语:Anthropic的开放工具:让我们了解AI是如何思考的 介绍:Anthropic的开源工具Circuit Tracer可以帮助研究人员理解大型语言模型(LLMs),它通过将内部计算可视化为归因图的方式展现相关…...
Domain Adaptation in Vision-Language Models (2023–2025): A Comprehensive Review
Domain Adaptation in Vision-Language Models (2023–2025): A Comprehensive Review Overview Recent research (2023–2025) has increasingly focused on adapting large Vision-Language Models (VLMs) to new domains and tasks with minimal supervision. A core tren…...
容器化革命:告别传统Dockerfile,拥抱现代构建最佳实践
前言 还记得我第一次自信满满地写Dockerfile时,感觉自己像个DevOps天才👑。但很快我就发现,管理这些文件变成了噩梦——安全问题、意外的构建问题、臃肿的镜像层出不穷。如果你一直在手动编写Dockerfile,让我告诉你:有更好的方法! 本文将揭示传统Dockerfile编写方式的…...

: influxdb + grafana+JMeter
influxdb和Grafana 不安装在被测机器上,可以统一放到一台机器上面 1、influxdb:一种时序数据库, 可以永久性保存数据【除非手动清除和数据库坏了】 2、Grafana:grafana是一款用go编写的开源应用,用于大规模指标数据的可…...
Vue拖拽组件:vue-draggable-plus
vue-draggable-plus 学习文档 简介 vue-draggable-plus 是一个基于 Sortablejs 的 Vue 拖拽排序组件,专为 Vue 3 (>v3) 或 Vue >2.7 设计。该组件解决了官方 Sortablejs Vue 组件与 Vue 3 严重脱节的问题。 核心特性 🎯 多种使用方式ÿ…...

TDengine 基于 TDgpt 的 AI 应用实战
基于 TDgpt 时序数据智能体的风力发电预测 作者: derekchen Demo 数据集准备 我们使用公开的UTSD数据集里面的某风场发电数据,作为预测算法的数据来源,基于历史数据预测未来一天内的每15分钟的发电量。原始数据集的采集频次为4秒ÿ…...

RocketMQ 消息发送核心源码解析:DefaultMQProducerImpl.send () 方法深度剖析
引言 在分布式系统中,消息队列是实现异步通信、服务解耦和流量削峰的关键组件。Apache RocketMQ 作为一款高性能、高可靠的消息中间件,被广泛应用于各类互联网场景。其中,消息发送是最基础也是最重要的功能之一。本文将深入剖析 RocketMQ 中…...

BiliNote部署实践
开源地址: https://github.com/JefferyHcool/BiliNote 🚀 快速开始 1. 克隆仓库 git clone https://github.com/JefferyHcool/BiliNote.git cd BiliNote mv .env.example .env2. 启动后端(FastAPI) cd backend pip insta…...
deepseek问答记录:请讲解一下transformers.HfArgumentParser()
1. 核心概念: transformers.HfArgumentParser 是 Hugging Face Transformers 库提供的一个命令行参数解析器。它基于 Python 内置的 argparse 模块,但进行了专门增强,目的是为了更简单、更优雅地管理机器学习(尤其是 NLP 任务&am…...

bismark OT CTOT OB CTOB 以及mapping后的bam文件中的XG,XR列的含义
首先,OT,OB,CTOT,CTOB都是描述测序reads的,而不是描述参考基因组的。 bisul-fate建库会将DNA双链文库中非甲基化的C转化成U。转化结束后,被转化的U和互补链的G并不配对。此时正链(,…...
new语法
在C中,new 是用于动态内存分配的操作符,允许在运行时请求内存空间。以下是 new 的完整语法和用法说明: 1. 基本语法 1.1 单一对象分配 type* pointer new type(initializer);作用:分配一个 type 类型的对象,并返回…...
npm、yarn幽灵依赖问题
很好!我们来专门讲讲**幽灵依赖(Phantom Dependency)**是什么,以及为什么 pnpm 对这个问题非常严格。 👻 什么是幽灵依赖? 幽灵依赖(Phantom Dependency),指的是&#x…...

Android Native 之 adbd进程分析
目录 1、adbd守护进程 2、adbd权限降级 3、adbd命令解析 1)adb shell 2)adb root 3)adb reboot 4、案例 1)案例之实现不需要执行adb root命令自动具有root权限 2)案例之实现不需要RSA认证直接能够使用adb she…...

CAN通讯协议中各种参数解析
1.各种参数缩写 2.多帧传输时间参数解析 - Sender(左侧) 指的是 多帧数据的发送者,也就是: ECU(被测系统 / 响应方) - Receiver(右侧) 指的是 多帧数据的接收者,也就是…...