本示例是《OpenCV3编程入门》中7.3.2中的示例程序的C# + EMGU 3.4.1版,这个示例演示了重映射函数remap的用法,与C++ OpenCv的版本相比,有如下几点需要注意:
1. C# EMGU中,不能用类似map_x.at<float>(i,j)的形式遍历mat中的元素;
2. 为了实现mat元素的遍历,替代的方法是,首先获得mat变量的首地址(指针),然后通过类似于一维数组的访问方式(中括号中写入index值),遍历所有元素;
3. 指针操作需要在unsafe语句中运行,并且需要首先进行如下的设置步骤:调试-->属性-->生成-->允许不安全代码。
关于map_x和map_y的说明:
map_x和map_y分别代表目标图中的(x,y)点在原图中的x坐标(由map_x提供)和y坐标(由map_y提供)。
程序代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
using Emgu.CV.Util;
namespace Remap
{
class Program
{
static void Main(string[] args)
{
//变量定义
Mat srcImage = new Mat(), dstImage = new Mat();
Mat map_x = new Mat(), map_y = new Mat();
//载入原始图
srcImage = CvInvoke.Imread("tower.jpg");
//显示原始图
CvInvoke.Imshow("original image", srcImage);
//创建和原始图一样的效果图,x重映射图,y重映射图
dstImage.Create(srcImage.Rows, srcImage.Cols, srcImage.Depth, srcImage.NumberOfChannels);
map_x.Create(srcImage.Rows, srcImage.Cols, DepthType.Cv32F, 1);
map_y.Create(srcImage.Rows, srcImage.Cols, DepthType.Cv32F, 1);
//C#中指针操作需要在unsafe模式下运行
unsafe
{
//定义float*类型的指针,指向map_x和map_y
float* ptr_to_map_x = (float*)map_x.DataPointer; //获得map_x的首地址
float* ptr_to_map_y = (float*)map_y.DataPointer; //获得map_y的首地址
//步进值,这里为srcImage的Cols数
int step = srcImage.Cols; //注意不能用srcImage.Step,它返回的是mat变量一行所占据的“字节”数
//双层循环,遍历map_x和map_y的每一个像素点,实现位置(坐标)映射
for (int i = 0; i < srcImage.Rows; i++)
{
for (int j = 0; j < srcImage.Cols; j++)
{
ptr_to_map_x[i * step + j] = j;
ptr_to_map_y[i * step + j] = srcImage.Rows - i;
}
}
}
//进行重映射操作
CvInvoke.Remap(srcImage, dstImage, map_x, map_y, Inter.Linear);
//显示效果图
CvInvoke.Imshow("remaped image", dstImage);
CvInvoke.WaitKey(0);
}
}
}
程序运行截图如下: