• c++视觉处理---图像重映射


    图像重映射:cv::remap

    cv::remapOpenCV中的一个函数,用于执行图像重映射,允许您通过重新映射像素的位置来变换图像。这个函数非常有用,可以用于各种图像处理任务,如校正畸变、透视变换、几何变换等。

    下面是 cv::remap 函数的基本用法:

    cv::remap(src, dst, map1, map2, interpolation, borderMode, borderValue);
    
    • 1
    • src: 输入图像。
    • dst: 输出图像,用于存储重映射后的结果。
    • map1map2: 两个与 src 相同尺寸的浮点型(32位浮点)或短整型(16位整数)的映射矩阵,用于定义像素的新位置。
    • interpolation: 插值方法,可选参数,用于确定新位置的像素值。通常使用 cv::INTER_LINEAR 进行双线性插值。
    • borderMode: 边界模式,可选参数,定义当像素越出图像边界时的处理方式,通常使用 cv::BORDER_CONSTANTcv::BORDER_REPLICATE
    • borderValue: 当 borderModecv::BORDER_CONSTANT 时使用,用于指定图像边界外的像素值。

    通过提供 map1map2 矩阵,您可以指定图像中每个像素的新位置。这允许您进行多种变换,如校正畸变、投影变换、透视变换等。

    以下是一个简单的示例,演示如何使用 cv::remap 进行图像重映射以实现水平镜像效果:

    #include 
    
    int main() {
        cv::Mat image = cv::imread("1.jpg", cv::IMREAD_COLOR);
    
        if (image.empty()) {
            std::cerr << "无法加载图像" << std::endl;
            return -1;
        }
    
        cv::Mat result(image.size(), image.type());
    
        cv::Mat map1, map2;
        map1.create(image.size(), CV_32F);
        map2.create(image.size(), CV_32F);
    
        for (int y = 0; y < image.rows; y++) {
            for (int x = 0; x < image.cols; x++) {
                map1.at<float>(y, x) = image.cols - x - 1; // 在X轴上反转像素位置
                map2.at<float>(y, x) = y;
            }
        }
    
        cv::remap(image, result, map1, map2, cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));
    
        cv::imshow("原始图像", image);
        cv::imshow("重映射后的图像", result);
        cv::waitKey(0);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这个示例中,我们创建了一个水平镜像效果,通过重新映射图像的像素位置,将每个像素的X坐标反转,从而实现镜像效果。请注意,您可以通过调整 map1map2 来实现不同的重映射效果。

    在这里插入图片描述

    相机实时重映射

    #include 
    
    int main() {
        cv::VideoCapture cap(0); // 打开本地相机(通常是0号摄像头)
    
        if (!cap.isOpened()) {
            std::cerr << "无法打开相机" << std::endl;
            return -1;
        }
    
        cv::Mat map1, map2;
        cv::Mat mirrorMap1, mirrorMap2;
    
        int width = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
        int height = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
    
        map1.create(height, width, CV_32F);
        map2.create(height, width, CV_32F);
        mirrorMap1.create(height, width, CV_32F);
        mirrorMap2.create(height, width, CV_32F);
    
        // 生成映射矩阵,实现水平镜像
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                map1.at<float>(y, x) = x;
                map2.at<float>(y, x) = y;
                mirrorMap1.at<float>(y, x) = width - x - 1;
                mirrorMap2.at<float>(y, x) = y;
            }
        }
    
        cv::Mat frame;
        cv::Mat mirroredFrame;
    
        while (true) {
            cap >> frame; // 从相机捕获一帧图像
    
            if (frame.empty()) {
                std::cerr << "无法捕获图像" << std::endl;
                break;
            }
    
            // 应用重映射
            cv::remap(frame, mirroredFrame, mirrorMap1, mirrorMap2, cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));
    
            cv::imshow("原始图像", frame);
            cv::imshow("水平镜像图像", mirroredFrame);
    
            // 检查用户是否按下ESC键,然后退出循环
            if (cv::waitKey(1) == 27) {
                break;
            }
        }
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
  • 相关阅读:
    gstreamer插件开发-Specifying the pads
    JetPack架构组件之ViewModel和Livedata使用
    #ArrayList 和 LinkedList 的区别(超容易理解)
    Java调试谷歌PC浏览器,控制操作网页
    【博主推荐】html好看的爱心告白源码
    「元宇宙」成为发展新坐标,文化产业如何「沉浸式」升维?
    C语言 cortex-A7核 按键中断 实验【重点】
    分块 学习笔记
    什么是P问题、NP问题和NPC问题
    Electron笔记
  • 原文地址:https://blog.csdn.net/qq_46107892/article/details/133763954