当前位置: 首页 > news >正文

[OpenCV] 数字图像处理 C++ 学习——15像素重映射(cv::remap) 附完整代码

文章目录

  • 前言
  • 1.像素重映射理论基础
  • 2.代码实现
    • (1) remap()细节
    • (2)水平翻转
    • (2)垂直翻转
    • (3)旋转 180 度
    • (4)径向扭曲
  • 3.完整代码

前言

像素重映射将图像中的每个像素映射到新位置,实现图像的扭曲、校正等操作。在 OpenCV 中,cv::remap() 函数就是用于实现这种功能的。本文将详细介绍像素重映射的基本原理以及在 OpenCV 中的实现方法,并给出完整代码。

1.像素重映射理论基础

像素重映射的原理是将图像的每个像素通过预定义的映射规则重新分配到新的位置。映射规则可以是任意的数学函数,比如旋转、缩放、扭曲等,甚至可以通过查表的方式进行非线性的映射。

在这里插入图片描述

像素重映射可以用以下公式表示:
dst ( x ′ , y ′ ) = src ( x , y ) \text{dst}(x', y') = \text{src}(x, y) dst(x,y)=src(x,y)
其中 (x, y) 是源图像中的像素位置,(x', y') 是目标图像中的像素位置。通过映射函数,可以将源图像的像素映射到目标图像的相应位置。

常见的重映射应用

图像扭曲:将图像以某种方式进行扭曲处理,使其变形。

镜头畸变校正:通过重映射可以校正图像中由于镜头引起的畸变,如鱼眼镜头畸变。

图像旋转与缩放:可以将图像按照指定的角度和比例进行旋转与缩放。

2.代码实现

实验用到图像,供学习使用sherlock.jpg

(1) remap()细节

cv::remap(
InputArray src,// 输入图像
OutputArray dst,// 输出图像
InputArray  map1,// x 映射表 CV_32FC1/CV_32FC2
InputArray map2,// y 映射表
int interpolation,// 选择的插值方法,常见线性插值,可选择立方等
int borderMode,// 指定图像边界的处理方式,默认为 BORDER_CONSTANT。
const Scalar borderValue// 用于边界像素的值,默认是黑色。
)

(2)水平翻转

map1 中的列坐标从右向左映射,map2 保持原始的行坐标不变。

for (int i = 0; i < src.rows; i++) {for (int j = 0; j < src.cols; j++) {map1.at<float>(i, j) = static_cast<float>(src.cols - j - 1);  // 水平翻转map2.at<float>(i, j) = static_cast<float>(i);}}Mat dst_hflip;remap(src, dst_hflip, map1, map2, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));namedWindow("Horizontal Flip", WINDOW_AUTOSIZE);imshow("Horizontal Flip", dst_hflip);

结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(2)垂直翻转

map2 中的行坐标从下向上映射,而 map1 保持列坐标不变。

	// 2. 垂直翻转for (int i = 0; i < src.rows; i++) {for (int j = 0; j < src.cols; j++) {map1.at<float>(i, j) = static_cast<float>(j);map2.at<float>(i, j) = static_cast<float>(src.rows - i - 1);  // 垂直翻转}}Mat dst_vflip;remap(src, dst_vflip, map1, map2, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));namedWindow("Vertical Flip", WINDOW_AUTOSIZE);imshow("Vertical Flip", dst_vflip);

结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(3)旋转 180 度

同时进行水平和垂直翻转

	// 3. 旋转 180 度for (int i = 0; i < src.rows; i++) {for (int j = 0; j < src.cols; j++) {map1.at<float>(i, j) = static_cast<float>(src.cols - j - 1);  // 水平翻转map2.at<float>(i, j) = static_cast<float>(src.rows - i - 1);  // 垂直翻转}}Mat dst_rotate180;remap(src, dst_rotate180, map1, map2, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));namedWindow("Rotate 180 degrees", WINDOW_AUTOSIZE);imshow("Rotate 180 degrees", dst_rotate180);

结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(4)径向扭曲

通过对极坐标中的半径进行二次变换,产生径向扭曲效果,图像向中心点扭曲,产生类似鱼眼镜头的效果。

	// 4. 径向扭曲效果float cx = src.cols / 2.0;float cy = src.rows / 2.0;float radius = min(cx, cy);for (int i = 0; i < src.rows; i++) {for (int j = 0; j < src.cols; j++) {float dx = j - cx;float dy = i - cy;float r = sqrt(dx * dx + dy * dy);float theta = atan2(dy, dx);float r_distorted = radius * (r / radius) * (r / radius);  // 径向扭曲map1.at<float>(i, j) = cx + r_distorted * cos(theta);map2.at<float>(i, j) = cy + r_distorted * sin(theta);}}Mat dst_radial;remap(src, dst_radial, map1, map2, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));namedWindow("Radial Distortion", WINDOW_AUTOSIZE);imshow("Radial Distortion", dst_radial);

结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.完整代码

#include<opencv2/opencv.hpp>
#include<highgui.hpp>
#include<iostream>
#include<math.h>using namespace cv;
using namespace std;void remap_image()
{cv::Mat src;src = imread("sherlock.jpg");if (src.empty()) {printf("could not find the image...\n");return;}namedWindow("Source Image", WINDOW_AUTOSIZE);imshow("Source Image", src);//创建映射矩阵Mat map1(src.size(), CV_32FC1);Mat map2(src.size(), CV_32FC1);// 1. 水平翻转for (int i = 0; i < src.rows; i++) {for (int j = 0; j < src.cols; j++) {map1.at<float>(i, j) = static_cast<float>(src.cols - j - 1);  // 水平翻转map2.at<float>(i, j) = static_cast<float>(i);}}Mat dst_hflip;remap(src, dst_hflip, map1, map2, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));namedWindow("Horizontal Flip", WINDOW_AUTOSIZE);imshow("Horizontal Flip", dst_hflip);// 2. 垂直翻转for (int i = 0; i < src.rows; i++) {for (int j = 0; j < src.cols; j++) {map1.at<float>(i, j) = static_cast<float>(j);map2.at<float>(i, j) = static_cast<float>(src.rows - i - 1);  // 垂直翻转}}Mat dst_vflip;remap(src, dst_vflip, map1, map2, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));namedWindow("Vertical Flip", WINDOW_AUTOSIZE);imshow("Vertical Flip", dst_vflip);// 3. 旋转 180 度for (int i = 0; i < src.rows; i++) {for (int j = 0; j < src.cols; j++) {map1.at<float>(i, j) = static_cast<float>(src.cols - j - 1);  // 水平翻转map2.at<float>(i, j) = static_cast<float>(src.rows - i - 1);  // 垂直翻转}}Mat dst_rotate180;remap(src, dst_rotate180, map1, map2, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));namedWindow("Rotate 180 degrees", WINDOW_AUTOSIZE);imshow("Rotate 180 degrees", dst_rotate180);// 4. 径向扭曲效果float cx = src.cols / 2.0;float cy = src.rows / 2.0;float radius = min(cx, cy);for (int i = 0; i < src.rows; i++) {for (int j = 0; j < src.cols; j++) {float dx = j - cx;float dy = i - cy;float r = sqrt(dx * dx + dy * dy);float theta = atan2(dy, dx);float r_distorted = radius * (r / radius) * (r / radius);  // 径向扭曲map1.at<float>(i, j) = cx + r_distorted * cos(theta);map2.at<float>(i, j) = cy + r_distorted * sin(theta);}}Mat dst_radial;remap(src, dst_radial, map1, map2, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));namedWindow("Radial Distortion", WINDOW_AUTOSIZE);imshow("Radial Distortion", dst_radial);waitKey(0);
}
int main() 
{remap_image();return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Ruoyi Cloud K8s 部署
  • 汇编调用C库函数—printf、scanf和Win32API
  • 俄罗斯方块——C语言实践(Dev-Cpp)
  • Unity 特殊文件夹
  • 面试题总结(四) -- STL与算法篇
  • TI DSP下载器XDS100 V2.0无法使用问题
  • MATLAB 从 R2024B 开始支持树莓派 5
  • 【C++】模板进阶:深入解析模板特化
  • 【C++题目】1.日期差值
  • C/C++内存管理——内存泄漏/内存碎片
  • 揭秘LLM计算数字的障碍的底层原理
  • 图论篇--代码随想录算法训练营第五十八天打卡|拓扑排序,dijkstra(朴素版),dijkstra(堆优化版)精讲
  • 洛谷9.16
  • 【C++】入门基础(下)
  • Java 流 (Stream) 详解
  • 分享的文章《人生如棋》
  • Angular Elements 及其运作原理
  • echarts花样作死的坑
  • PHP 7 修改了什么呢 -- 2
  • vue--为什么data属性必须是一个函数
  • 分布式事物理论与实践
  • 给初学者:JavaScript 中数组操作注意点
  • 如何实现 font-size 的响应式
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 鱼骨图 - 如何绘制?
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • 关于Android全面屏虚拟导航栏的适配总结
  • #if 1...#endif
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #pragma 指令
  • #stm32整理(一)flash读写
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (MTK)java文件添加简单接口并配置相应的SELinux avc 权限笔记2
  • (阿里云在线播放)基于SpringBoot+Vue前后端分离的在线教育平台项目
  • (多级缓存)缓存同步
  • (二)hibernate配置管理
  • (二)Kafka离线安装 - Zookeeper下载及安装
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (三)Honghu Cloud云架构一定时调度平台
  • (顺序)容器的好伴侣 --- 容器适配器
  • (四)React组件、useState、组件样式
  • 、写入Shellcode到注册表上线
  • .gitignore
  • .gitignore不生效的解决方案
  • .Net Remoting(分离服务程序实现) - Part.3
  • .net Stream篇(六)
  • .Net Web窗口页属性
  • .NET 指南:抽象化实现的基类
  • .NET设计模式(11):组合模式(Composite Pattern)
  • @ohos.systemParameterEnhance系统参数接口调用:控制设备硬件(执行shell命令方式)
  • [Algorithm][综合训练][kotori和气球][体操队形][二叉树中的最大路径和]详细讲解
  • [Android]使用Android打包Unity工程
  • [BJDCTF2020]The mystery of ip
  • [C puzzle book] types