本示例是《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窗體中
}
}
}
程式運作截圖如下:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX90zdORDNyImdxcVZzplMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2LcRHelR3LcJzLctmch1mclRXY39zN2EDMwczMxEjNykDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
完整的程式資源可到如下連結下載下傳:
https://download.csdn.net/download/flymoon87/10687977