在winform设计器托一个PictureBox、一个按钮,界面如下:
代码
using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using OpenCvSharp; //引入opencvusing OpenCvSharp.Extensions; //Mat转换时需要该模块namespace PictureBoxShowMat{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void button1_Click(object sender, EventArgs e){OpenFileDialog dialog = new OpenFileDialog();dialog.Multiselect = false; //是否可以选择多个文件dialog.Title = "请选择文件夹";dialog.Filter = "所有文件(*.*)|*.*";dialog.RestoreDirectory = true;string imgName = "";if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK){imgName = dialog.FileName;//读取本地的图片Mat srcImg = new Mat(imgName, ImreadModes.Color);//把Mat格式的图片转换成BitmapBitmap bitmap = BitmapConverter.ToBitmap(srcImg);//显示图片pictureBox1.Image = bitmap;}}}}
运行结果
Mat转Bitmap需要调用OPenCVSharp拓展模块OpenCvSharp.Extensions, 调用该模块BitmapConverter类的一些方法即可完成相应的转换,该类声明如下:
BitmapConverter类定义了一些静态方法,可以把Mat转为Bitmap, 也可以把Bitmap转为Mat.
来看看转Bitmap的源码,在OpenCVSharp源码中查找BitmapConverter类的实现,ToBitmap的实现如下:
/// <summary>/// Converts Mat to System.Drawing.Bitmap/// </summary>/// <param name="src">Mat</param>/// <returns></returns>public static Bitmap ToBitmap(this Mat src){if (src == null){throw new ArgumentNullException(nameof(src));}PixelFormat pf;switch (src.Channels()){case 1:pf = PixelFormat.Format8bppIndexed; break;case 3:pf = PixelFormat.Format24bppRgb; break;case 4:pf = PixelFormat.Format32bppArgb; break;default:throw new ArgumentException("Number of channels must be 1, 3 or 4.", nameof(src));}return ToBitmap(src, pf);}
根据图片的通道数,最终会调用下面这个方法转换
public static unsafe void ToBitmap(this Mat src, Bitmap dst){if (src == null)throw new ArgumentNullException(nameof(src));if (dst == null)throw new ArgumentNullException(nameof(dst));if (src.IsDisposed)throw new ArgumentException("The image is disposed.", nameof(src));if (src.Depth() != MatType.CV_8U)throw new ArgumentException("Depth of the image must be CV_8U");//if (src.IsSubmatrix())// throw new ArgumentException("Submatrix is not supported");if (src.Width != dst.Width || src.Height != dst.Height)throw new ArgumentException("");PixelFormat pf = dst.PixelFormat;// 1プレーン用の場合、グレースケールのパレット情報を生成するif (pf == PixelFormat.Format8bppIndexed){ColorPalette plt = dst.Palette;for (int x = 0; x < 256; x++){plt.Entries[x] = Color.FromArgb(x, x, x);}dst.Palette = plt;}int w = src.Width;int h = src.Height;Rectangle rect = new Rectangle(0, 0, w, h);BitmapData? bd = null;bool submat = src.IsSubmatrix();bool continuous = src.IsContinuous();try{bd = dst.LockBits(rect, ImageLockMode.WriteOnly, pf);IntPtr srcData = src.Data;byte* pSrc = (byte*)(srcData.ToPointer());byte* pDst = (byte*)(bd.Scan0.ToPointer());int ch = src.Channels();int srcStep = (int)src.Step();int dstStep = ((src.Width * ch) + 3) / 4 * 4; // 4の倍数に揃えるint stride = bd.Stride;switch (pf){case PixelFormat.Format1bppIndexed:{if (submat)throw new NotImplementedException("submatrix not supported");// BitmapDataは4byte幅だが、IplImageは1byte幅// 手作業で移し替える //int offset = stride - (w / 8);int x = 0;byte b = 0;for (int y = 0; y < h; y++){for (int bytePos = 0; bytePos < stride; bytePos++){if (x < w){for (int i = 0; i < 8; i++){var mask = (byte)(0x80 >> i);if (x < w && pSrc[srcStep * y + x] == 0)b &= (byte)(mask ^ 0xff);elseb |= mask;x++;}pDst[bytePos] = b;}}x = 0;pDst += stride;}break;}case PixelFormat.Format8bppIndexed:case PixelFormat.Format24bppRgb:case PixelFormat.Format32bppArgb:if (srcStep == dstStep && !submat && continuous){long bytesToCopy = src.DataEnd.ToInt64() - src.Data.ToInt64();Buffer.MemoryCopy(pSrc, pDst, bytesToCopy, bytesToCopy);}else{for (int y = 0; y < h; y++){long offsetSrc = (y * srcStep);long offsetDst = (y * dstStep);long bytesToCopy = w * ch;// 一列ごとにコピーBuffer.MemoryCopy(pSrc + offsetSrc, pDst + offsetDst, bytesToCopy, bytesToCopy);}}break;default:throw new NotImplementedException();}}finally{if (bd != null)dst.UnlockBits(bd);}}#endregion}
在转换的时候,会进行加锁处理,保证不会跳出当前的处理线程。
bd = dst.LockBits(rect, ImageLockMode.WriteOnly, pf);//像素转换dst.UnlockBits(bd);