如何将OpenCV中的Iplimage转化为C#中的Bitmap
GitHub代码地址:https://github.com/peiyixi/IplImageToBitmap
完整代码可以直接去GitHub上下载,上面还有一个小的demo程序
最近项目用到了OpenCV与C#的交互问题,通过查阅信息和看源码总结了出一种将Iplimage转化为Bitmap的方法
废话不多说直接上代码吧
代码:
1、首先建立一个MIplImage的struct:
(复制的Emgu中的源码,直接复制粘贴就好)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace IplImageToBitmap.cv
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MIplImage
{
/// <summary>
/// sizeof(IplImage)
/// </summary>
public int NSize;
/// <summary>
/// version (=0)
/// </summary>
public int ID;
/// <summary>
/// Most of OpenCV functions support 1,2,3 or 4 channels
/// </summary>
public int NChannels;
/// <summary>
/// ignored by OpenCV
/// </summary>
public int AlphaChannel;
/// <summary>
/// pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U, IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported
/// </summary>
public IplDepth Depth;
/// <summary>
/// ignored by OpenCV
/// </summary>
public byte ColorModel0;
/// <summary>
/// ignored by OpenCV
/// </summary>
public byte ColorModel1;
/// <summary>
/// ignored by OpenCV
/// </summary>
public byte ColorModel2;
/// <summary>
/// ignored by OpenCV
/// </summary>
public byte ColorModel3;
/// <summary>
/// ignored by OpenCV
/// </summary>
public byte ChannelSeq0;
/// <summary>
/// ignored by OpenCV
/// </summary>
public byte ChannelSeq1;
/// <summary>
/// ignored by OpenCV
/// </summary>
public byte ChannelSeq2;
/// <summary>
/// ignored by OpenCV
/// </summary>
public byte ChannelSeq3;
/// <summary>
/// 0 - interleaved color channels, 1 - separate color channels.
/// cvCreateImage can only create interleaved images
/// </summary>
public int DataOrder;
/// <summary>
/// 0 - top-left origin,
/// 1 - bottom-left origin (Windows bitmaps style)
/// </summary>
public int Origin;
/// <summary>
/// Alignment of image rows (4 or 8).
/// OpenCV ignores it and uses widthStep instead
/// </summary>
public int Align;
/// <summary>
/// image width in pixels
/// </summary>
public int Width;
/// <summary>
/// image height in pixels
/// </summary>
public int Height;
/// <summary>
/// image ROI. when it is not NULL, this specifies image region to process
/// </summary>
public IntPtr Roi;
/// <summary>
/// must be NULL in OpenCV
/// </summary>
public IntPtr MaskROI;
/// <summary>
/// ditto
/// </summary>
public IntPtr ImageId;
/// <summary>
/// ditto
/// </summary>
public IntPtr TileInfo;
/// <summary>
/// image data size in bytes
/// (=image->height*image->widthStep in case of interleaved data)
/// </summary>
public int ImageSize;
/// <summary>
/// pointer to aligned image data
/// </summary>
public IntPtr ImageData;
/// <summary>
/// size of aligned image row in bytes
/// </summary>
public int WidthStep;
/// <summary>
/// border completion mode, ignored by OpenCV
/// </summary>
public int BorderMode0;
/// <summary>
/// border completion mode, ignored by OpenCV
/// </summary>
public int BorderMode1;
/// <summary>
/// border completion mode, ignored by OpenCV
/// </summary>
public int BorderMode2;
/// <summary>
/// border completion mode, ignored by OpenCV
/// </summary>
public int BorderMode3;
/// <summary>
/// border const, ignored by OpenCV
/// </summary>
public int BorderConst0;
/// <summary>
/// border const, ignored by OpenCV
/// </summary>
public int BorderConst1;
/// <summary>
/// border const, ignored by OpenCV
/// </summary>
public int BorderConst2;
/// <summary>
/// border const, ignored by OpenCV
/// </summary>
public int BorderConst3;
/// <summary>
/// pointer to a very origin of image data (not necessarily aligned) - it is needed for correct image deallocation
/// </summary>
public IntPtr ImageDataOrigin;
}
}
struct MIplImage中还需要用到enum IplDepth也直接复制吧:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace IplImageToBitmap.cv
{
public enum IplDepth : uint
{
/// <summary>
/// indicates if the value is signed
/// </summary>
IplDepthSign = 0x80000000,
/// <summary>
/// 1bit unsigned
/// </summary>
IplDepth_1U = 1,
/// <summary>
/// 8bit unsigned (Byte)
/// </summary>
IplDepth_8U = 8,
/// <summary>
/// 16bit unsigned
/// </summary>
IplDepth16U = 16,
/// <summary>
/// 32bit float (Single)
/// </summary>
IplDepth32F = 32,
/// <summary>
/// 8bit signed
/// </summary>
IplDepth_8S = (IplDepthSign | 8),
/// <summary>
/// 16bit signed
/// </summary>
IplDepth16S = (IplDepthSign | 16),
/// <summary>
/// 32bit signed
/// </summary>
IplDepth32S = (IplDepthSign | 32),
/// <summary>
/// double
/// </summary>
IplDepth64F = 64
}
}
2、然后就可以调用IpilImage了:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Runtime.InteropServices;
using IplImageToBitmap.cv;
using IplImageToBitmap;
using System.Drawing.Imaging;
namespace IplImageToBitmap
{
public static class Ctransform
{
/// <summary>
/// 将IplImage指针转换成位图对象;
/// </summary>
/// <param name="ptr">IplImage指针</param>
/// <returns>返回位图对象</returns>
public static Bitmap IplImageToBitmap(IntPtr ptr)
{
IntPtr pp = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MIplImage)));
pp = ptr;
PixelFormat pixelFormat; //像素格式
MIplImage mptr = (MIplImage)Marshal.PtrToStructure((IntPtr)(pp.ToInt32()), typeof(MIplImage));
IntPtr aa = new IntPtr();
aa = mptr.ImageData;
int width = mptr.Width;
int height = mptr.Height;
int step = mptr.WidthStep;
string unsupportedDepth = "不支持的像素位深度IPL_DEPTH";
string unsupportedChannels = "不支持的通道数(仅支持1,2,4通道)";
switch (mptr.NChannels) //根据深度和通道数对应C#中的像素的颜色数据格式
{
case 1: //Grayscale image;
switch (mptr.Depth)
{
case IplDepth.IplDepth_8U:
pixelFormat = PixelFormat.Format8bppIndexed;
break;
case IplDepth.IplDepth16U:
pixelFormat = PixelFormat.Format16bppGrayScale;
break;
default:
throw new NotImplementedException(unsupportedDepth);
}
break;
case 3: //BGR image
switch (mptr.Depth)
{
case IplDepth.IplDepth_8U:
pixelFormat = PixelFormat.Format24bppRgb;
break;
case IplDepth.IplDepth16U:
pixelFormat = PixelFormat.Format48bppRgb;
break;
default:
throw new NotImplementedException(unsupportedDepth);
}
break;
case 4:
switch (mptr.Depth)
{
case IplDepth.IplDepth_8U:
pixelFormat = PixelFormat.Format32bppArgb;
break;
case IplDepth.IplDepth16U:
pixelFormat = PixelFormat.Format64bppArgb;
break;
default:
throw new NotImplementedException(unsupportedDepth);
}
break;
default:
throw new NotImplementedException(unsupportedChannels);
}
Bitmap img = new Bitmap(width, height, step, pixelFormat, aa);
//对于灰度图像,还要修改调色板
if (pixelFormat == PixelFormat.Format8bppIndexed)
{
img.Palette = CvToolbox.GrayscalePalette;
}
return img;
}
}
}
上面的灰度图像的调色板函数,我建了一个CvToolbox类:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IplImageToBitmap.cv
{
public static class CvToolbox
{ // #region Color Pallette
/// <summary>
/// The ColorPalette of Grayscale for Bitmap Format8bppIndexed
/// </summary>
public static readonly ColorPalette GrayscalePalette = GenerateGrayscalePalette();
private static ColorPalette GenerateGrayscalePalette()
{
using (Bitmap image = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
{
ColorPalette palette = image.Palette;
for (int i = 0; i < 256; i++)
{
palette.Entries[i] = Color.FromArgb(i, i, i);
}
return palette;
}
}
}
}
参考博客:https://blog.csdn.net/yeyang911/article/details/23735145