C# EMGU 3.4.1学习笔记(十)综合示例:实现多种重映射

本示例是《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窗体中
        }
    }
}

程序运行截图如下:

C# EMGU 3.4.1学习笔记(十)综合示例:实现多种重映射

完整的程序资源可到如下链接下载:

https://download.****.net/download/flymoon87/10687977