1.项目右键-->Manage Nuget Package中查找Emgu
2.先读取二进制文件至buffer缓冲区,将buffer指针传入mat函数,转换出image,然后显示。
public Mat(int[] sizes, DepthType type, IntPtr data, IntPtr[] steps = null);
//
// Summary:
// Create a Mat header from existing data
//
// Parameters:
// size:
// Size of the Mat
//
// type:
// Mat element type
//
// channels:
// Number of channels
//
// data:
// Pointer to the user data. Matrix constructors that take data and step parameters
// do not allocate matrix data. Instead, they just initialize the matrix header
// that points to the specified data, which means that no data is copied. This operation
// is very efficient and can be used to process external data using OpenCV functions.
// The external data is not automatically deallocated, so you should take care of
// it.
//
// step:
// Number of bytes each matrix row occupies. The value should include the padding
// bytes at the end of each row, if any.
参考代码如下:
using System;
using System.Drawing;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
using Emgu.Util;
using System.IO;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace OpenCV
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string fPath = @"C:\Users\Antony WU\Desktop\ADBTest20190604\vpu\raw.dat";
string savePath = @"C:\Users\Antony WU\Desktop\ADBTest20190604\vpu\png.png";
FileInfo finfo = new FileInfo(fPath); //实例化FileInfo
FileStream fs = finfo.OpenRead();
const int vpu_image_width = 1280;
const int vpu_image_height = 800;
Size size = new Size(vpu_image_width, vpu_image_height);
int bufLength = vpu_image_width* vpu_image_height;//1280*800
byte[] buffer = new byte[bufLength]; //定义缓冲器
int readSize = fs.Read(buffer, 0, bufLength); //从FileStream中读取数据到缓冲区
if(readSize>0)
{
GCHandle hObject = GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr pObject = hObject.AddrOfPinnedObject();
int[] sizes = new int[] { vpu_image_height, vpu_image_width };
Mat image = new Mat(sizes, DepthType.Cv8U, pObject);
pictureBox1.Image = image.Bitmap;
if (hObject.IsAllocated)
hObject.Free();
image.Save(savePath);
CvInvoke.Imshow("ShowImg", image);
//CvInvoke.WaitKey(0);
//Bitmap bmp = ToGrayBitmap(buffer, vpu_image_width, vpu_image_height);
//pictureBox1.Image = bmp;///方法二也OK
}
}
public static Bitmap ToGrayBitmap(byte[] rawValues, int width, int height)
{
申请目标位图的变量,并将其内存区域锁定
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
获取图像参数
int stride = bmpData.Stride; // 扫描线的宽度
int offset = stride - width; // 显示宽度与扫描线宽度的间隙
IntPtr iptr = bmpData.Scan0; // 获取bmpData的内存起始位置
int scanBytes = stride * height; // 用stride宽度,表示这是内存区域的大小
下面把原始的显示大小字节数组转换为内存中实际存放的字节数组
int posScan = 0, posReal = 0; // 分别设置两个位置指针,指向源数组和目标数组
byte[] pixelValues = new byte[scanBytes]; //为目标数组分配内存
for (int x = 0; x < height; x++)
{
下面的循环节是模拟行扫描
for (int y = 0; y < width; y++)
{
pixelValues[posScan++] = rawValues[posReal++];
}
posScan += offset; //行扫描结束,要将目标位置指针移过那段“间隙”
}
用Marshal的Copy方法,将刚才得到的内存字节数组复制到BitmapData中
System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, iptr, scanBytes);
bmp.UnlockBits(bmpData); // 解锁内存区域
下面的代码是为了修改生成位图的索引表,从伪彩修改为灰度
ColorPalette tempPalette;
using (Bitmap tempBmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
{
tempPalette = tempBmp.Palette;
}
for (int i = 0; i < 256; i++)
{
Color ColorTemp = Color.FromArgb(i, i, i);
tempPalette.Entries[i] = ColorTemp;
}
bmp.Palette = tempPalette;
算法到此结束,返回结果
return bmp;
}
}
}