zoukankan      html  css  js  c++  java
  • OpenCV函数 重映射

    重映射是什么意思?

    • 把一个图像中一个位置的像素放置到另一个图片指定位置的过程.

    • 为了完成映射过程, 有必要获得一些插值为非整数像素坐标,因为源图像与目标图像的像素坐标不是一一对应的.

    • 我们通过重映射来表达每个像素的位置 (x,y) :

      g(x,y) = f ( h(x,y) )

      这里 g() 是目标图像, f() 是源图像, h(x,y) 是作用于 (x,y) 的映射方法函数.

    让我们来思考一个快速的例子. 想象一下我们有一个图像 I , 我们想满足下面的条件作重映射:

    h(x,y) = (I.cols - x, y )

    会发生什么? 图像会按照 x 轴方向发生翻转. 

    映射函数 remap. 参数说明:

    代码如下:

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include <iostream>
    #include <stdio.h>
    
    using namespace cv;
    
    /// Global variables
    Mat src, dst;
    Mat map_x, map_y;
    char* remap_window = "Remap demo";
    int ind = 0;
    
    /// Function Headers
    void update_map(void);
    
    /**
    * @function main
    */
    int main(int argc, char** argv)
    {
        /// Load the image
        src = imread("E:\VS2015Opencv\vs2015\project\picture\06.jpg", 1);
    
        /// Create dst, map_x and map_y with the same size as src:
        dst.create(src.size(), src.type());
        map_x.create(src.size(), CV_32FC1);
        map_y.create(src.size(), CV_32FC1);
    
        /// Create window
        namedWindow(remap_window, CV_WINDOW_AUTOSIZE);
    
        /// Loop
        while (true)
        {
            /// Each 1 sec. Press ESC to exit the program
            int c = waitKey(1000);
    
            if ((char)c == 27)
            {
                break;
            }
    
            /// Update map_x & map_y. Then apply remap
            update_map();
            remap(src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    
            /// Display results
            imshow(remap_window, dst);
        }
        return 0;
    }
    
    void update_map(void)
    {
        ind = ind % 4;
    
        for (int j = 0; j < src.rows; j++)
        {
            for (int i = 0; i < src.cols; i++)
            {
                switch (ind)
                {
                case 0:
                    if (i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75)
                    {
                        map_x.at<float>(j, i) = 2 * (i - src.cols*0.25) + 0.5;
                        map_y.at<float>(j, i) = 2 * (j - src.rows*0.25) + 0.5;
                    }
                    else
                    {
                        map_x.at<float>(j, i) = 0;
                        map_y.at<float>(j, i) = 0;
                    }
                    break;
                case 1:
                    map_x.at<float>(j, i) = i;
                    map_y.at<float>(j, i) = src.rows - j;
                    break;
                case 2:
                    map_x.at<float>(j, i) = src.cols - i;
                    map_y.at<float>(j, i) = j;
                    break;
                case 3:
                    map_x.at<float>(j, i) = src.cols - i;
                    map_y.at<float>(j, i) = src.rows - j;
                    break;
                } // end of switch
            }
        }
        ind++;
    }

    主要代码说明:

    建立一个间隔1000毫秒的循环,每次循环执行更新映射矩阵参数并对源图像进行重映射处理(使用 mat_x 和 mat_y),然后把更新后的目标图像显示出来:

    重映射函数 remap. 参数说明:

    • src: 源图像
    • dst: 目标图像,与 src 相同大小
    • map_x: x方向的映射参数. 它相当于方法 h(i,j) 的第一个参数
    • map_y: y方向的映射参数. 注意 map_y 和 map_x 与 src 的大小一致。
    • CV_INTER_LINEAR: 非整数像素坐标插值标志. 这里给出的是默认值(双线性插值).
    • BORDER_CONSTANT: 默认
    while (true)
    	{
    		/// Each 1 sec. Press ESC to exit the program
    		int c = waitKey(1000);
    
    		if ((char)c == 27)
    		{
    			break;
    		}
    
    		/// Update map_x & map_y. Then apply remap
    		update_map();
    		remap(src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    
    		/// Display results
    		imshow(remap_window, dst);
    	}
    	return 0;
    }
    

      我们做了什么哪些映射过程?(在这里 map_x 代表第一个坐标 h(i,j) , map_y 是第二个坐标,映射后的坐标)

    void update_map(void)
    {
        ind = ind % 4;
    
        for (int j = 0; j < src.rows; j++)
        {
            for (int i = 0; i < src.cols; i++)
            {
                switch (ind)
                {
                case 0:
                    if (i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75)
                    {
                        map_x.at<float>(j, i) = 2 * (i - src.cols*0.25) + 0.5;
                        map_y.at<float>(j, i) = 2 * (j - src.rows*0.25) + 0.5;
                    }
                    else
                    {
                        map_x.at<float>(j, i) = 0;
                        map_y.at<float>(j, i) = 0;
                    }
                    break;
                case 1:
                    map_x.at<float>(j, i) = i;
                    map_y.at<float>(j, i) = src.rows - j;
                    break;
                case 2:
                    map_x.at<float>(j, i) = src.cols - i;
                    map_y.at<float>(j, i) = j;
                    break;
                case 3:
                    map_x.at<float>(j, i) = src.cols - i;
                    map_y.at<float>(j, i) = src.rows - j;
                    break;
                } // end of switch
            }
        }
        ind++;

    结果如下:

    图像宽高缩小一半,并显示在中间:

     图像上下颠倒:

    图像左右颠倒:

     两个方向同时颠倒:

  • 相关阅读:
    Qt QMutex使用详解
    libpng warning: iCCP: cHRM chunk does not match sRGB
    Qt tr()的作用
    Qt 关于QT_BEGIN_NAMESPACE宏的作用
    Qt 串口收发数据
    Qt QSerialPort串口通讯的时候,readyRead()信号不产生的解决方案
    Qt QSerialPort串口 接收数据 QIODevice::readyRead()
    Qt QString与QByteArray互相转换的方法
    Qt QString字符串分割、截取
    Qt 从QString中提取出数字
  • 原文地址:https://www.cnblogs.com/fcfc940503/p/11305349.html
Copyright © 2011-2022 走看看