本示例是《OpenCV3编程入门》中7.3.4中的综合示例程序的C# + EMGU 3.4.1版,演示了重映射函数remap的用法,并可以通过按键控制四种不同的映射模式。
其中要变换的四种模式如下:
1. 图像宽高缩小一半,并居中显示:
映射方法函数h(i,j) = (2 * j - src.cols / 2 + 0.5, 2 * i - src.rows / 2 + 0.5),所有成对的参数(i,j)都必须符合:
src.rows / 4 < i < 3 * src.rows / 4 和 src.cols / 4 < j < 3 * src.cols / 4;
2. 图像上下翻转:h(i,j) = (j, src.rows - i );
3. 图像左右翻转:h(i,j) = (src.cols - j, i);
4. 同时执行上下和左右翻转:h(i,j) = (src.cols - j, src.rows - i)。
程序代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
namespace Remap_MultipleTypes
{
public partial class Form1 : Form
{
//定义变量
Mat srcImage = new Mat(), dstImage = new Mat();
Mat map_x = new Mat(), map_y = new Mat();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//载入原始图
srcImage = CvInvoke.Imread("IronMan.jpg");
if (srcImage.IsEmpty)
MessageBox.Show("读取图片错误,请确认目录下是否有imread函数指定的图片存在!");
//显示原始图
imageBox1.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);
}
//按键事件处理
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//调用自定义函数,根据按键来更新map_x和map_y的值
update_map(e.KeyCode);
//调用Remap()函数进行重映射
CvInvoke.Remap(srcImage, dstImage, map_x, map_y, Inter.Linear);
//显示效果图
imageBox2.Image = dstImage;
//更新label2的显示内容
switch (e.KeyCode)
{
case Keys.Escape:
MessageBox.Show("程序退出中...");
Application.Exit();
break;
case Keys.D1:
label2.Text = "效果图:图像长宽缩小为原来的一半并居中显示";
break;
case Keys.D2:
label2.Text = "效果图:图像上下翻转";
break;
case Keys.D3:
label2.Text = "效果图:图像左右翻转";
break;
case Keys.D4:
label2.Text = "效果图:图像上下翻转并左右翻转";
break;
}
}
//自定义函数,根据按键来更新map_x和map_y的值
void update_map(Keys key)
{
//C#中指针操作需要在unsafe语句块中进行
unsafe
{
//定义float*类型的指针,指向map_x和map_y的首地址
float* ptr_to_map_x = (float*)map_x.DataPointer;
float* ptr_to_map_y = (float*)map_y.DataPointer;
//定义步进值
int step = srcImage.Cols;
//双层循环,遍历每一个像素点
for (int i = 0; i < srcImage.Rows; i++)
{
for (int j = 0; j < srcImage.Cols; j++)
{
switch(key)
{
//若键盘【1】键被按下,则执行“图像长宽缩小为原来的一半并居中显示”的操作
case Keys.D1:
if (i > srcImage.Rows * 0.25 && i < srcImage.Rows * 0.75 &&
j > srcImage.Cols * 0.25 && j < srcImage.Cols * 0.75)
{
ptr_to_map_x[i * step + j] = (float)(2 * j - srcImage.Cols/2 + 0.5);
ptr_to_map_y[i * step + j] = (float)(2 * i - srcImage.Rows/2 + 0.5);
}
else
{
ptr_to_map_x[i * step + j] = 0;
ptr_to_map_y[i * step + j] = 0;
}
break;
//若键盘【2】键被按下,则执行“图像上下翻转”的操作
case Keys.D2:
ptr_to_map_x[i * step + j] = j;
ptr_to_map_y[i * step + j] = srcImage.Rows - i;
break;
//若键盘【3】键被按下,则执行“图像左右翻转”的操作
case Keys.D3:
ptr_to_map_x[i * step + j] = srcImage.Cols - j;
ptr_to_map_y[i * step + j] = i;
break;
//若键盘【4】键被按下,则执行“图像上下翻转并左右翻转”的操作
case Keys.D4:
ptr_to_map_x[i * step + j] = srcImage.Cols - j;
ptr_to_map_y[i * step + j] = srcImage.Rows - i;
break;
}
}
}
}
}
//按键操作说明
private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
Form form2 = new Form(); //创建新窗口
form2.Size = new Size(410, 150); //定义窗口尺寸
form2.Show(); //显示新窗口
RichTextBox rtb = new RichTextBox(); //创建RichTexBox
rtb.Dock = DockStyle.Fill; //定义文本框的dock模式
//文本框的显示内容
rtb.AppendText("键盘按键【ESC】 - 退出程序\n");
rtb.AppendText("键盘按键【1】 - 执行“图像长宽缩小为原来的一半并居中显示”的操作\n");
rtb.AppendText("键盘按键【2】 - 执行“图像上下翻转”的操作\n");
rtb.AppendText("键盘按键【3】 - 执行“图像左右翻转”的操作\n");
rtb.AppendText("键盘按键【4】 - 执行“图像上下翻转并左右翻转”的操作");
form2.Controls.Add(rtb); //将rtb文本框添加到form2窗体中
}
}
}
程序运行截图如下:
完整的程序资源可到如下链接下载: