remap实现多种重映射
视频讲解如下:
当前系列所有demo下载地址:
https://github.com/GaoRenBao/OpenCv4-Demo
不同编程语言对应的OpenCv版本以及开发环境信息如下:
语言 | OpenCv版本 | IDE |
C# | OpenCvSharp4.4.8.0.20230708 | Visual Studio 2022 |
C++ | OpenCv-4.5.5-vc14_vc15 | Visual Studio 2022 |
Python | OpenCv-Python (4.6.0.66) | PyCharm Community Edition 2022.1.3 |
本章节给大家讲讲如何实现remap多种重映射。当前代码主体还是使用毛星云的demo,C#和Python都是在C++版本的基础上转换过来的,三个版本的效果基本一致。
首先我们需要准备一张测试图片:

三组代码运行效果都是一样的,我这里就不一一展示了,通过键盘的数字键:1、2、3、4,就能实现4种图像变换,最终运行效果如下:

C#版本代码
C#版本需要安装“OpenCvSharp4”、“OpenCvSharp4.runtime.win”两个库才行。不然会报错。
如果需要使用“ BitmapConverter.ToBitmap”操作,则需要追加安装“OpenCvSharp4.Extensions”库。
using OpenCvSharp;
namespace demo
{
internal class Program
{
public static Mat g_srcImage = new Mat();
public static Mat g_dstImage = new Mat();
public static Mat g_map_x = new Mat();
public static Mat g_map_y = new Mat();
public static int key = 0;
static void Main(string[] args)
{
//【1】载入原始图
g_srcImage = Cv2.ImRead("../../../images/Robot.jpg");
//【2】显示原始图
Cv2.ImShow("【原始图】", g_srcImage);
//【2】创建和原始图一样的效果图,x重映射图,y重映射图
g_dstImage = new Mat(g_srcImage.Size(), g_srcImage.Type());
g_map_x = new Mat(g_srcImage.Size(), MatType.CV_32FC1);
g_map_y = new Mat(g_srcImage.Size(), MatType.CV_32FC1);
// 异步操作
while (true)
{
if (key != 0)
{
// 根据按下的键盘按键来更新 map_x & map_y的值. 然后调用remap( )进行重映射
update_map(key);
// 进行重映射操作
Cv2.Remap(g_srcImage, g_dstImage, g_map_x, g_map_y, InterpolationFlags.Linear, BorderTypes.Constant, new Scalar(0, 0, 0));
// 显示效果图
Cv2.ImShow("【C# 效果图】", g_dstImage);
key = 0;
}
int k = Cv2.WaitKey(30);
if (k == 49) key = 1; // 按键1
if (k == 50) key = 2; // 按键1
if (k == 51) key = 3; // 按键1
if (k == 52) key = 4; // 按键1
}
}
// 描述:根据按键来更新map_x与map_x的值
public static int update_map(int key)
{
//双层循环,遍历每一个像素点
for (int j = 0; j < g_srcImage.Rows; j++)
{
for (int i = 0; i < g_srcImage.Cols; i++)
{
switch (key)
{
case 1: // 键盘【1】键按下,进行第一种重映射操作
if (i > g_srcImage.Cols * 0.25 && i < g_srcImage.Cols * 0.75 && j > g_srcImage.Rows * 0.25 && j < g_srcImage.Rows * 0.75)
{
g_map_x.Set(j, i, (float)(2 * (i - g_srcImage.Cols * 0.25) + 0.5));
g_map_y.Set(j, i, (float)(2 * (j - g_srcImage.Rows * 0.25) + 0.5));
}
else
{
g_map_x.Set(j, i, (float)(0));
g_map_y.Set(j, i, (float)(0));
}
break;
case 2:// 键盘【2】键按下,进行第二种重映射操作
g_map_x.Set(j, i, (float)(i));
g_map_y.Set(j, i, (float)(g_srcImage.Rows - j));
break;
case 3:// 键盘【3】键按下,进行第三种重映射操作
g_map_x.Set(j, i, (float)(g_srcImage.Cols - i));
g_map_y.Set(j, i, (float)(j));
break;
case 4:// 键盘【4】键按下,进行第四种重映射操作
g_map_x.Set(j, i, (float)(g_srcImage.Cols - i));
g_map_y.Set(j, i, (float)(g_srcImage.Rows - j));
break;
}
}
}
return 1;
}
}
}
C++版本代码
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME "【程序窗口】" //为窗口标题定义的宏
Mat g_srcImage, g_dstImage;
Mat g_map_x, g_map_y;
int update_map(int key);
static void ShowHelpText();//输出帮助文字
int main(int argc, char** argv)
{
//改变console字体颜色
system("color 5F");
//显示帮助文字
ShowHelpText();
//【1】载入原始图
g_srcImage = imread("../images/Robot.jpg", 1);
if (!g_srcImage.data) {
printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n");
return false;
}
imshow("原始图", g_srcImage);
//【2】创建和原始图一样的效果图,x重映射图,y重映射图
g_dstImage.create(g_srcImage.size(), g_srcImage.type());
g_map_x.create(g_srcImage.size(), CV_32FC1);
g_map_y.create(g_srcImage.size(), CV_32FC1);
//【3】创建窗口并显示
// opencv3:CV_WINDOW_AUTOSIZE
// opencv4:WINDOW_AUTOSIZE
namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
imshow(WINDOW_NAME, g_srcImage);
//【4】轮询按键,更新map_x和map_y的值,进行重映射操作并显示效果图
while (1)
{
//获取键盘按键
int key = waitKey(0);
//判断ESC是否按下,若按下便退出
if ((key & 255) == 27)
{
cout << "程序退出...........\n";
break;
}
//根据按下的键盘按键来更新 map_x & map_y的值. 然后调用remap( )进行重映射
update_map(key);
// opencv3:CV_INTER_LINEAR
// opencv4:INTER_LINEAR
remap(g_srcImage, g_dstImage, g_map_x, g_map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
//显示效果图
imshow(WINDOW_NAME, g_dstImage);
}
return 0;
}
// 描述:根据按键来更新map_x与map_x的值
int update_map(int key)
{
//双层循环,遍历每一个像素点
for (int j = 0; j < g_srcImage.rows; j++)
{
for (int i = 0; i < g_srcImage.cols; i++)
{
switch (key)
{
case '1': // 键盘【1】键按下,进行第一种重映射操作
if (i > g_srcImage.cols * 0.25 && i < g_srcImage.cols * 0.75 && j > g_srcImage.rows * 0.25 && j < g_srcImage.rows * 0.75)
{
g_map_x.at<float>(j, i) = static_cast<float>(2 * (i - g_srcImage.cols * 0.25) + 0.5);
g_map_y.at<float>(j, i) = static_cast<float>(2 * (j - g_srcImage.rows * 0.25) + 0.5);
}
else
{
g_map_x.at<float>(j, i) = 0;
g_map_y.at<float>(j, i) = 0;
}
break;
case '2':// 键盘【2】键按下,进行第二种重映射操作
g_map_x.at<float>(j, i) = static_cast<float>(i);
g_map_y.at<float>(j, i) = static_cast<float>(g_srcImage.rows - j);
break;
case '3':// 键盘【3】键按下,进行第三种重映射操作
g_map_x.at<float>(j, i) = static_cast<float>(g_srcImage.cols - i);
g_map_y.at<float>(j, i) = static_cast<float>(j);
break;
case '4':// 键盘【4】键按下,进行第四种重映射操作
g_map_x.at<float>(j, i) = static_cast<float>(g_srcImage.cols - i);
g_map_y.at<float>(j, i) = static_cast<float>(g_srcImage.rows - j);
break;
}
}
}
return 1;
}
// 描述:输出一些帮助信息
static void ShowHelpText()
{
//输出一些帮助信息
printf("\n\t欢迎来到重映射示例程序~\n\n");
printf("\n\t按键操作说明: \n\n"
"\t\t键盘按键【ESC】- 退出程序\n"
"\t\t键盘按键【1】- 第一种映射方式\n"
"\t\t键盘按键【2】- 第二种映射方式\n"
"\t\t键盘按键【3】- 第三种映射方式\n"
"\t\t键盘按键【4】- 第四种映射方式\n");
}
Python版本代码
import cv2
import numpy as np
# 【1】载入原始图
g_srcImage = cv2.imread("../images/Robot.jpg")
cv2.imshow("srcImage", g_srcImage)
# 【2】创建和原始图一样的效果图,x重映射图,y重映射图
sp = g_srcImage.shape[:2]
g_map_x = np.zeros((sp[0], sp[1]), np.float32)
g_map_y = np.zeros((sp[0], sp[1]), np.float32)
def update_map(key):
# 双层循环,遍历每一个像素点,改变map_x & map_y的值
for y in range(0, int(sp[0] - 1)):
for x in range(0, int(sp[1] - 1)):
if key == 49:
if x > sp[1] * 0.25 and x < sp[1] * 0.75 and y > sp[0] * 0.25 and y < sp[0] * 0.75:
g_map_x[y, x] = 2 * (x - sp[1] * 0.25) + 0.5
g_map_y[y, x] = 2 * (y - sp[0] * 0.25) + 0.5
else:
g_map_x[y, x] = 0
g_map_y[y, x] = 0
if key == 50:
g_map_x[y, x] = x
g_map_y[y, x] = sp[0] - y
if key == 51:
g_map_x[y, x] = sp[1] - x
g_map_y[y, x] = y
if key == 52:
g_map_x[y, x] = sp[1] - x
g_map_y[y, x] = sp[0] - y
while True:
# 获取键盘键值
key = cv2.waitKey(0)
# 根据按下的键盘按键来更新 map_x & map_y的值. 然后调用remap( )进行重映射
update_map(key)
# 进行重映射操作
g_dstImage = cv2.remap(g_srcImage, g_map_x, g_map_y, cv2.INTER_LINEAR, cv2.BORDER_CONSTANT)
# 显示效果图
cv2.imshow('dstImage', g_dstImage)