找回密码
 立即注册
首页 业界区 业界 OpenCV开发笔记(八十三):图像remap实现哈哈镜效果 ...

OpenCV开发笔记(八十三):图像remap实现哈哈镜效果

嗳歉楞 2025-6-4 21:18:53
前言

  对图像进行非规则的扭曲,实现哈哈镜就是一种非常规的扭曲方式,本文先描述remap的原理,然后通过remap实现哈哈镜。
 Demo

  
1.png

  
2.png

  
3.png

  
4.png

  基于原始算法,可以进行二次开发,实现一些其他效果:
  
5.png

  
6.png

  
7.png

 矫正映射remap(畸变映射)

  当进行图像矫正时,必须指定输入图像的每个像素在输出图像中移动到的位置,成为“矫正映射”(畸变映射)。
双通道浮点数表示方式

  N x M的矩阵A中,重映射由双通道浮点数的N x M的矩阵B表示,对于图像A中的任意一点aPoint(i, j),映射为b1Point(i’, j’)和b2Point(i’, j’),在A中假设i=2,j=3,那么(假设重映射之后4.5,5.5)在B1中b1Point(i’, j’)值为4.5,b2Point(i’, j’)值为5.5,由于坐标是浮点数,那么需要插值得到整数位置以及中间过渡的区域颜色(平滑处理)。
  
8.png

双矩阵浮点数表示方式

  双矩阵浮点数表示,N x M的矩阵A中,重映射由一对N x M的矩阵B和C描述,这里所有的N x M矩阵都是单通道浮点矩阵,在A中的点aPoint(i, j),重映射矩阵B中的点bPoint(i,j)存储了重映射后的i’ (映射后的i坐标), 重映射矩阵C中的点cPoint(i,j)存储了重映射后的j’(映射后的j坐标)。
  
9.png

定点表示方式

  映射由双通道有符号整数矩阵(即CV_16SC2类型)表示。该方式与双通道浮点数表示方式相同,但使用此格式要快得多(笔者理解:由浮点数插值改为整数插值,会要快一些,但是肯定双通道浮点数的表示方式图像效果会稍微好一些)。
  
10.png

 remap核心关键

  在于得到插值的坐标系来映射新位置的x和y位置,要渐近等,所以本方法的核心关键在于得到标定后的矩阵,得到映射矩阵的方式可以自己写算法,也可以使用其他方式,后续文章继续深入这块。
 remap演示

  为了更好的展示remap的作用,我们使用一张100x100的图,这样可以更好的看到remap的原理效果。
  先做一张100x100的图,图里面用不同的颜色,如下:
  
11.png

  使用opencv打开:
  
12.png

Map1使用第一种表示点的方式

  使用点的方式映射:
  1. // 表示点的第一种
  2. std::vector<cv::Point2f> vectorPoints;
  3. for(int index = 0; index < 10; index++)
  4. {
  5.     vectorPoints.push_back(cv::Point2f(0, 0));
  6.     vectorPoints.push_back(cv::Point2f(10, 10));
  7.     vectorPoints.push_back(cv::Point2f(20, 20));
  8.     vectorPoints.push_back(cv::Point2f(30, 30));
  9.     vectorPoints.push_back(cv::Point2f(40, 40));
  10.     vectorPoints.push_back(cv::Point2f(50, 50));
  11.     vectorPoints.push_back(cv::Point2f(60, 60));
  12.     vectorPoints.push_back(cv::Point2f(70, 70));
  13.     vectorPoints.push_back(cv::Point2f(80, 80));
  14.     vectorPoints.push_back(cv::Point2f(90, 90));
  15. }
复制代码
  
13.png

  这是相当于把点提取出来映射到一个mat里面,一直堆下去:
  1. // 表示点的第一种
  2. std::vector<cv::Point2f> vectorPoints;
  3. for(int index = 0; index < 50; index++)
  4. {
  5.     vectorPoints.push_back(cv::Point2f(0, 0));
  6.     vectorPoints.push_back(cv::Point2f(10, 10));
  7.     vectorPoints.push_back(cv::Point2f(20, 20));
  8.     vectorPoints.push_back(cv::Point2f(30, 30));
  9.     vectorPoints.push_back(cv::Point2f(40, 40));
  10.     vectorPoints.push_back(cv::Point2f(50, 50));
  11.     vectorPoints.push_back(cv::Point2f(60, 60));
  12.     vectorPoints.push_back(cv::Point2f(70, 70));
  13.     vectorPoints.push_back(cv::Point2f(80, 80));
  14.     vectorPoints.push_back(cv::Point2f(90, 90));
  15. }
复制代码
  
14.png

Map1使用第二种表示点的方式

  直接初始化:
[code]cv::Mat mapX(srcMat.rows, srcMat.cols, CV_32F); // x 方向cv::Mat mapY(srcMat.rows, srcMat.cols, CV_32F); // y 方向for(int row = 0; row < 100; row++){    for(int col = 0; col < 100; col++)    {        std::cout
您需要登录后才可以回帖 登录 | 立即注册