C#解析RAW图文件并在PictureBox中显示

RAW图文件是仅包含图像数据的文件,它是由图像传感器拍摄得到的最初始的图像数据。

RAW图一个像素只包含一个通道的颜色信息,所以解析出来是灰色的图像,要得到彩色图像,还需要根据RAW图的颜色滤波阵列进行插值,进行去马赛克处理。

解析RAW图文件首先打开并读取到文件的比特流,下面以位深度为10位的RAW图位例:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ReadRAW
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
		public byte[] ImgData= null;
		public int[] ImgInt = null;
		public byte[] ImgByte= null;
		public byte[,] ImgRGB= null;
		public Bitmap Bmp = null;

		public int Width = 1920;
		public int Height = 1080;
		public string Bits = "10";

		//打开RAW图按钮
		private void LoadRaw_Click(object sender, EventArgs e)
		{
			OpenFileDialog ofd = new OpenFileDialog();
			ofd.Title = "请选择文件";

			ofd.Filter = "RAW文件(*.raw)|*.raw|所有文件(*.*)|*.*";
			ofd.FilterIndex = 1;

			if (ofd.ShowDialog() == DialogResult.OK)
			{
				ImgData = File.ReadAllBytes(ofd.FileName);
				ImgInt = GetImgInt(ImgData, Width, Height, Bits);
				ImgByte = GetImgByte(ImgInt, Width, Height, Bits);
				ImgRGB = GetImgRGB(ImgByte, Width, Height);
				Bmp = GetBmp(ImgRGB, Width, Height);
				if (Bmp!= null)
				{
					pictureBox1.Image = new Bitmap(Bmp, pictureBox1.Width, pictureBox1.Height);
				}
			}
		}
    }
}

根据图像位深度和宽度、高度将RAW图比特流转换为整型数组:

// 文件字节流解析,10位的图是两个字节转为一个整形数据
public int[] GetImgInt(byte[] img, int width, int height, string Bits)
{
	if (img == null)
	{
		return null;
	}
	int Index = 0;
	int[] OriImg = new int[width * height];
	try
	{
		if (Bits == "8")
		{
			if (img.Length != width * height)
			{
				return null;
			}
			for (int i = 0; i < img.Length; i += 4)
			{
				OriImg[i] = img[i];
				OriImg[i + 1] = img[i + 1];
				OriImg[i + 2] = img[i + 2];
				OriImg[i + 3] = img[i + 3];
			}
			return OriImg;
		}
		else if (Bits == "10" || Bits == "12")
		{
			if (img.Length != width * height * 2)
			{
				return null;
			}
			//图像的像素个数一定是4的倍数,所以一次性处理4个像素,循环展开,提高循环效率
			for (int i = 1; i < img.Length; i += 8)
			{
				OriImg[Index] = (0x00FF & img[i - 1]) | (0xFF00 & img[i] << 8);
				Index++;
				OriImg[Index] = (0x00FF & img[i + 1]) | (0xFF00 & img[i + 2] << 8);
				Index++;
				OriImg[Index] = (0x00FF & img[i + 3]) | (0xFF00 & img[i + 4] << 8);
				Index++;
				OriImg[Index] = (0x00FF & img[i + 5]) | (0xFF00 & img[i + 6] << 8);
				Index++;
			}
			return OriImg;
		}
	}
	finally
	{
		GC.Collect();
	}
	return null;
}

由于位深度为10的图像灰阶范围为0~1023,为了能在显示器上显示,需要将图像整型数组转化为位深度为8的图像数组。

// 将整型数组转为8位图像数据
public byte[] GetImgByte(int[] img, int width, int height, string Bits)
{
	if (img == null)
	{
		return null;
	}
	byte[] Img = new byte[img.Length];
	try
	{
		switch (Bits)
		{
			case ("8"):
				for (int i = 0; i < img.Length; i += 4)
				{
					Img[i] = (byte)img[i];
					Img[i + 1] = (byte)img[i + 1];
					Img[i + 2] = (byte)img[i + 2];
					Img[i + 3] = (byte)img[i + 3];
				}
				break;
			case ("10"):
				for (int i = 0; i < img.Length; i += 4)
				{
					Img[i] = (byte)(img[i] >> 2);
					Img[i + 1] = (byte)(img[i + 1] >> 2);
					Img[i + 2] = (byte)(img[i + 2] >> 2);
					Img[i + 3] = (byte)(img[i + 3] >> 2);
				}
				break;
			case ("12"):
				for (int i = 0; i < img.Length; i += 4)
				{
					Img[i] = (byte)(img[i] >> 4);
					Img[i + 1] = (byte)(img[i + 1] >> 4);
					Img[i + 2] = (byte)(img[i + 2] >> 4);
					Img[i + 3] = (byte)(img[i + 3] >> 4);
				}
				break;
		}
	}
	catch (Exception) {; }
	finally
	{
		GC.Collect();
	}
	return Img;
}

将8位深度的数组转为具有RGB三个通道信息的图像数组:

//byte[]转为RGB图像矩阵byte[3,]
public byte[,] GetImgRGB(byte[] img, int width, int height)
{
	if (img == null)
	{
		return null;
	}
	byte[,] Img = new byte[3, width * height];
	for (int y = 0; y < height; y++)
	{
		for (int x = 0; x < width; x++)
		{
			Img[0, y * width + x] = img[y * width + x];
			Img[1, y * width + x] = img[y * width + x];
			Img[2, y * width + x] = img[y * width + x];
		}
	}
	return Img;
}

将图像矩阵转化为Bitmap位图:

// RGB图像矩阵转为Bitmap
public Bitmap GetBmp(byte[,] img, int width, int height)
{
	if (img == null || width * height * 3 != img.Length)
	{
		return null;
	}
	Bitmap bt = new Bitmap(width, height);
	BitmapData data = bt.LockBits(new Rectangle(new Point(), bt.Size), ImageLockMode.WriteOnly, bt.PixelFormat);
	int ofs = 0;
	int pix;
	try
	{
		for (int y = 0; y < height; y++)
		{
			for (int x = 0; x < width; x++)
			{
				pix = Color.FromArgb(img[0, y * width + x], img[1, y * width + x], img[2, y * width + x]).ToArgb();
				Marshal.WriteInt32(data.Scan0, ofs, pix);
				ofs += 4;
			}
		}
	}
	catch (EndOfStreamException)
	{
	}
	finally
	{
		bt.UnlockBits(data);
	}
	return bt;
}

显示出来的图像是灰度图像,效果如下所示:

若想得到彩色图像,需要加入插值算法去马赛克。

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值