OpenCV开发笔记(四十五):红胖子8分钟带你深入了解重映射(图文并茂+浅显易懂+程序源码)

若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105633350
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

目录

前言

相关博客

Demo

重映射

概述

X轴旋转/Y轴旋转/XY轴旋转原理示意图

缩放1/2原理示意图

倾斜45度示意图

函数原型

扫描二维码关注公众号,回复: 11025691 查看本文章

Demo源码

工程模板:对应版本号v1.40.0


红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门).

OpenCV开发专栏(点击传送门)

 

    OpenCV开发笔记(四十五):红胖子8分钟带你深入了解重映射(图文并茂+浅显易懂+程序源码)

 

前言

红胖子,来也!!!

本篇章讲解重映射。

 

相关博客

      图像检测中对图像进行旋转、镜像等操作是可以对原尺寸进行操作的,有专门的旋转、翻转函数进行处理。

OpenCV开发笔记(八):OpenCV常用操作之计时、缩放、旋转、镜像

      该文章中,也同样实现了部分简单重映射效果,使用的四个函数:

  • 旋转函数1:cv::transpose,直接对矩阵进行顺时钟旋转90°
  • 旋转函数2:cv::rotate,三个枚举可以旋转90°,180°,270°
  • 翻转函数:cv::flip,xy轴翻转
  • 缩放函数:cv::resize,缩放

Demo

 

重映射

概述

      重映射,按照与原图一样大小的尺寸,通过像素下标的序列号的矩阵进行映射得到结果,简而言之,就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。

X轴旋转/Y轴旋转/XY轴旋转原理示意图

缩放1/2原理示意图

倾斜45度示意图

函数原型

void remap( InputArray src,
            OutputArray dst,
            InputArray map1,
            InputArray map2,
            int interpolation,
            int borderMode = BORDER_CONSTANT,
            const Scalar& borderValue = Scalar());
  • 参数一:InputArray类型的src,一般为cv::Mat;
  • 参数二:OutputArray类型的dst,目标图像。它的大小与map1相同,类型与src相同。
  • 参数三:InputArray类型的map1,它有两种可能的表示对象:表示点(x,y)的第一个映射或者表示CV_16SC2 , CV_32FC1 或CV_32FC2类型的x值。
  • 参数四:InputArray类型的map2,它也有两种可能的表示对象,而且他是根据map1来确定表示哪种对象。若map1表示点(x,y)时,这个参数不代表任何值,否则,表示CV_16UC1 , CV_32FC1类型的y值(第二个值)。
  • 参数五:int类型的interpolation,使用的插值方法;
  • 参数六:int类型的borderMode,边界处理方式;
  • 参数七:Scalar类型的borderValue,重映射后,离群点的背景,需要broderMode设置为BORDER_CONSTRANT时才有效。(离群点:当图片大小为400x300,那么对应的map1和map2范围为0~399、0~299,小于0或者大于299的则为离散点,使用该颜色填充);

Demo源码

void OpenCVManager::testRemap()
{
QString fileName1 =         "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";           
    cv::Mat srcMat = cv::imread(fileName1.toStdString());
    cv::Mat dstMat;
    int width = 400;
    int height = 300;

    cv::resize(srcMat, srcMat, cv::Size(width, height));

    cv::String windowName = _windowTitle.toStdString();
    cvui::init(windowName);

    cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, srcMat.rows * 4),
                                srcMat.type());

    while(true)
    {
        windowMat = cv::Scalar(0, 0, 0);

        cv::Mat mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
                                cv::Range(srcMat.cols * 0, srcMat.cols * 1));
        cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat);

        cv::Mat mapX;
        cv::Mat mapY;
        // 第一种x翻转
        {
            mapX.create(srcMat.size(), CV_32FC1);
            mapY.create(srcMat.size(), CV_32FC1);
            for(int row = 0; row < srcMat.rows; row++)
            {
                for(int col = 0; col < srcMat.cols; col++)
                {
                    mapX.at<float>(row, col) = static_cast<float>(col);
                    mapY.at<float>(row, col) = static_cast<float>(srcMat.rows - row - 1);
                }
            }
            dstMat.create(srcMat.size(), srcMat.type());
            cv::remap(srcMat,
                      dstMat,
                      mapX,
                      mapY,
                      CV_INTER_LINEAR,
                      cv::BORDER_CONSTANT,
                      cv::Scalar(255, 0, 0));
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第二种y翻转
        {
            mapX.create(srcMat.size(), CV_32FC1);
            mapY.create(srcMat.size(), CV_32FC1);
            for(int row = 0; row < srcMat.rows; row++)
            {
                for(int col = 0; col < srcMat.cols; col++)
                {
                    mapX.at<float>(row, col) = static_cast<float>(srcMat.cols - col - 1);
                    mapY.at<float>(row, col) = static_cast<float>(row);
                }
            }
            dstMat.create(srcMat.size(), srcMat.type());
            cv::remap(srcMat,
                      dstMat,
                      mapX,
                      mapY,
                      CV_INTER_LINEAR,
                      cv::BORDER_CONSTANT,
                      cv::Scalar(255, 0, 0));
            mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第三种x,y翻转
        {
            mapX.create(srcMat.size(), CV_32FC1);
            mapY.create(srcMat.size(), CV_32FC1);
            for(int row = 0; row < srcMat.rows; row++)
            {
                for(int col = 0; col < srcMat.cols; col++)
                {
                    mapX.at<float>(row, col) = static_cast<float>(srcMat.cols - col - 1);
                    mapY.at<float>(row, col) = static_cast<float>(srcMat.rows - row - 1);
                }
            }
            dstMat.create(srcMat.size(), srcMat.type());
            cv::remap(srcMat,
                      dstMat,
                      mapX,
                      mapY,
                      CV_INTER_LINEAR,
                      cv::BORDER_CONSTANT,
                      cv::Scalar(255, 0, 0));
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第四种:右半边拉伸一倍
        {
            mapX.create(srcMat.size(), CV_32FC1);
            mapY.create(srcMat.size(), CV_32FC1);
            for(int row = 0; row < srcMat.rows; row++)
            {
                for(int col = 0; col < srcMat.cols; col++)
                {
                    mapX.at<float>(row, col) = static_cast<float>(col / 2);
                    mapY.at<float>(row, col) = static_cast<float>(row);
                }
            }
            dstMat.create(srcMat.size(), srcMat.type());
            cv::remap(srcMat,
                      dstMat,
                      mapX,
                      mapY,
                      CV_INTER_LINEAR,
                      cv::BORDER_CONSTANT,
                      cv::Scalar(255, 0, 0));
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第五种,缩小1/2,并显示在中间,底色为蓝色
        {
            mapX.create(srcMat.size(), CV_32FC1);
            mapY.create(srcMat.size(), CV_32FC1);
            for(int row = 0; row < srcMat.rows; row++)
            {
                for(int col = 0; col < srcMat.cols; col++)
                {
                    if(col < srcMat.cols / 4 || row < srcMat.rows / 4)
                    {
                        mapX.at<float>(row, col) = -1;
                        mapY.at<float>(row, col) = -1;
                    }else if(col >= srcMat.cols / 4 * 3 || row >= srcMat.rows / 4 * 3)
                    {
                        mapX.at<float>(row, col) = -1;
                        mapY.at<float>(row, col) = -1;
                    }else{
                        mapX.at<float>(row, col) = static_cast<float>((col - srcMat.cols / 4) * 2);
                        mapY.at<float>(row, col) = static_cast<float>((row - srcMat.rows / 4) * 2);
                    }
                }
            }
            dstMat.create(srcMat.size(), srcMat.type());
            cv::remap(srcMat,
                      dstMat,
                      mapX,
                      mapY,
                      CV_INTER_LINEAR,
                      cv::BORDER_CONSTANT,
                      cv::Scalar(255, 0, 0));
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第六种,矩阵旋转90度(输出必须和输入大小一样,此时可以使用resize缩放至快高对调的比例)
        {
            mapX.create(srcMat.size(), CV_32FC1);
            mapY.create(srcMat.size(), CV_32FC1);
            for(int row = 0; row < srcMat.rows; row++)
            {
                for(int col = 0; col < srcMat.cols; col++)
                {
                    mapX.at<float>(row, col) = static_cast<float>(row);
                    mapY.at<float>(row, col) = static_cast<float>(col);
                }
            }
            dstMat.create(srcMat.size(), srcMat.type());
            cv::remap(srcMat,
                      dstMat,
                      mapX,
                      mapY,
                      CV_INTER_LINEAR,
                      cv::BORDER_CONSTANT,
                      cv::Scalar(255, 0, 0));
            mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第七种,顺时针倾斜45°
        {
            mapX.create(srcMat.size(), CV_32FC1);
            mapY.create(srcMat.size(), CV_32FC1);
            for(int row = 0; row < srcMat.rows; row++)
            {
                for(int col = 0; col < srcMat.cols; col++)
                {
                    mapX.at<float>(row, col) = static_cast<float>((col + (srcMat.cols * 2 - (srcMat.rows - row) - 1)) % srcMat.cols);
                    mapY.at<float>(row, col) = static_cast<float>(row);
                }
            }
            dstMat.create(srcMat.size(), srcMat.type());
            cv::remap(srcMat,
                      dstMat,
                      mapX,
                      mapY,
                      CV_INTER_LINEAR,
                      cv::BORDER_CONSTANT,
                      cv::Scalar(255, 0, 0));
            mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 更新
        cvui::update();
        // 显示
        cv::imshow(windowName, windowMat);
        // esc键退出
        if(cv::waitKey(25) == 27)
        {
            break;
        }
    }
}

工程模板:对应版本号v1.40.0

      对应版本号v1.40.0

 

原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105633350

发布了271 篇原创文章 · 获赞 475 · 访问量 55万+

猜你喜欢

转载自blog.csdn.net/qq21497936/article/details/105633350