【OpenCV图像处理】1.22 像素值映射

相关理论

  • 什么是像素重映射

    • 简单点说就是把输入图像中各个像素按照一定的规则映射到另外一张图像的对应位置上去,形成一张新的图像
    • g ( x , y ) = f ( h ( x , y ) ) g(x, y)=f(h(x, y)) 这里 g ( x , y ) g(x,y) 是目标图像, h ( x , y ) h(x,y) 是功能函数, f f 是源图像。映射效果如下:
    • 在这里插入图片描述
    • 假设有映射函数 h ( z , y ) = ( I . c o l s x , y ) h(z, y)=(I.{cols}-x, y) ,图像会按照x轴方向发生反转,如下:
      在这里插入图片描述 在这里插入图片描述
      上图中,红色圈关于x的位置改变。
  • API介绍 – cv::remap

    remap(
    InputArray src,// 输入图像
    OutputArray dst,// 输出图像
    InputArray  map1,// x 映射表 CV_32FC1/CV_32FC2
    InputArray map2,// y 映射表
    int interpolation,// 选择的插值方法,常见线性插值,可选择立方等
    int borderMode,// BORDER_CONSTANT
    const Scalar borderValue// color 
    )
    
    • 参数解释:
      • 第三个参数map1:InputArray类型的map1,它有两种可能的表示对象:表示点(x,y)的第一个映射。表示CV_16SC2 , CV_32FC1 或CV_32FC2类型的X值。
      • 第四个参数map2:InputArray类型的map2,同样,它也有两种可能的表示对象,而且他是根据map1来确定表示那种对象。若map1表示点(x,y)时。这个参数不代表任何值。表示CV_16UC1 , CV_32FC1类型的Y值(第二个值)。
      • 第五个参数interpolation:int类型的interpolation,插值方式,之前的resize( )函数中有讲到,需要注意,resize( )函数中提到的INTER_AREA插值方式在这里是不支持的,所以可选的插值方式如下:
        在这里插入图片描述
      • 第六个参数borderMode:int类型的borderMode,边界模式,有默认值BORDER_CONSTANT,表示目标图像中“离群点(outliers)”的像素值不会被此函数修改。取值可以是如下几种:
      • 在这里插入图片描述
      • 第七个参数borderValue:const Scalar&类型的borderValue,当有常数边界时使用的值,其有默认值Scalar( ),即默认值为0。

代码 & 运行效果

完整代码:

#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/types_c.h>

using namespace std;
using namespace cv;

#ifndef P22
#define P22 22
#endif

#if P22 //像素映射
int t1_value = 50;
int max_value = 255;
const char* OUTPUT_TITLE = "Canny result";
Mat  src,dest, map_x, map_y;
int indexx = 0;

void update_map()
{
    for(int row=0; row < src.rows; row++)
    {
        for( int col=0; col < src.cols; col++)
        {
            switch(indexx)
            {
                //原图长宽各缩小一半,即原图的1/4
                case 0:
                    if(col > src.cols*0.25 && col < src.cols*0.75&&
                       row > src.rows*0.25 && row < src.rows*0.75)
                    {
                        map_x.at<float>(row, col) = 2*(col - src.cols*0.25) + 0.5;
                        map_y.at<float>(row, col) = 2*(row - src.rows*0.25) + 0.5;
                    } else {
                        map_x.at<float>(row, col) = 0;
                        map_y.at<float>(row, col) = 0;
                    }
                    break;

                //图像左右翻转,类似于照镜子
                case 1:
                    map_x.at<float>(row, col) = (src.cols-col-1);
                    map_y.at<float>(row, col) = row;
                    break;

                //图像上下翻转
                case 2:
                    map_x.at<float>(row, col) = col;
                    map_y.at<float>(row, col) = (src.rows-row-1);
                    break;

                //图像上下左右都翻转
                case 3:
                    map_x.at<float>(row, col) = (src.cols-col-1);
                    map_y.at<float>(row, col) = (src.rows-row-1);
                    break;
            }
        }
    }
}
#endif

int main() {
    std::string path = "../color_line.JPG";
    cv::Mat img = cv::imread(path, 5);

    string str_input = "input image";
    string str_output = "output image";

    if(img.empty())
    {
        std::cout << "open file failed" << std::endl;
        return -1;
    }
    
#if P22 //像素值映射
    map_x.create(img.size(), CV_32FC1);
    map_y.create(img.size(), CV_32FC1);

    src = img;

    int c = 0;
    while(true)
    {
        c = waitKey(500);
        indexx = c % 4;
        if((char)c == 27)  break;

        update_map();
        remap(src, dest, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0,255));
        imshow(str_output, dest);
    }
#endif

    cv::waitKey(0);
    cv::destroyAllWindows();
    return 0;
}

效果展示:

  • 图像缩小
    在这里插入图片描述
  • 左右翻转
    在这里插入图片描述
  • 上下翻转
    在这里插入图片描述
  • 上下左右都翻转
    在这里插入图片描述
发布了134 篇原创文章 · 获赞 30 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/donaldsy/article/details/102523696