123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- using System;
- using System.IO;
- namespace YOLODetectProcessLib
- {
- /// <summary>
- /// 裸图像
- /// </summary>
- public class RawImage : IImage
- {
- #region private variables
- private byte[] _dataBuffer;
- private int _width;
- private int _height;
- private int _channel;
- private int _stride;
- private int _dataBufferSize;
- #endregion
- #region 实现接口
- /// <summary>
- /// 数据区,长度=Stride*Height,通道顺序为BGR
- /// </summary>
- public byte[] DataBuffer { get => _dataBuffer; }
- /// <summary>
- /// 图像宽度
- /// </summary>
- public int Width { get => _width; set => _width = value; }
- /// <summary>
- /// 图像高度
- /// </summary>
- public int Height { get => _height; set => _height = value; }
- /// <summary>
- /// 图像通道数
- /// </summary>
- public int Channel { get => _channel; set => _channel = value; }
- /// <summary>
- /// 步长=Width*Channel
- /// </summary>
- public int Stride { get => _stride; set => _stride = value; }
- /// <summary>
- /// 图像区的长度=width*height*channel
- /// </summary>
- public int DataBufferSize { get => _dataBufferSize; set => _dataBufferSize = value; }
- /// <summary>
- /// 从文件读入
- /// </summary>
- /// <param name="filePath"></param>
- /// <returns></returns>
- public void ReadFromFile(string filePath)
- {
- if (!File.Exists(filePath))
- {
- throw new FileNotFoundException("Failed to read RawImage from file.", filePath);
- }
- FileStream fs = new FileStream(filePath, FileMode.Open);
- int len = (int)fs.Length;
- if (len < 20)
- {
- throw new ArgumentException("Unexpected file content.");
- }
- byte[] extraInfo = new byte[20];
- fs.Read(extraInfo, 0, 20);
- if (_dataBuffer != null)
- {
- if (_dataBuffer.Length != len - 20)
- {
- Array.Resize(ref _dataBuffer, len - 20);
- }
- }
- else
- {
- _dataBuffer = new byte[len - 20];
- }
- fs.Read(_dataBuffer, 0, len - 20);
- _width = System.BitConverter.ToInt32(extraInfo, 0);
- _height = System.BitConverter.ToInt32(extraInfo, 4);
- _channel = System.BitConverter.ToInt32(extraInfo, 8);
- _stride = System.BitConverter.ToInt32(extraInfo, 12);
- _dataBufferSize = System.BitConverter.ToInt32(extraInfo, 16);
- if (_dataBuffer.Length != _dataBufferSize)
- {
- throw new ArgumentException("Missing image data.");
- }
- return;
- }
- /// <summary>
- /// 保存到文件
- /// </summary>
- /// <param name="filePath"></param>
- /// <returns></returns>
- public void SaveIntoFile(string filePath)
- {
- FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
- byte[] width = System.BitConverter.GetBytes(_width);
- byte[] height = System.BitConverter.GetBytes(_height);
- byte[] channel = System.BitConverter.GetBytes(_channel);
- byte[] stride = System.BitConverter.GetBytes(_stride);
- byte[] dataSize = System.BitConverter.GetBytes(_dataBufferSize);
- fs.Write(width, 0, width.Length);
- fs.Write(height, 0, height.Length);
- fs.Write(channel, 0, channel.Length);
- fs.Write(stride, 0, stride.Length);
- fs.Write(dataSize, 0, dataSize.Length);
- fs.Write(_dataBuffer, 0, _dataBuffer.Length);
- fs.Close();
- return;
- }
- /// <summary>
- /// 销毁资源
- /// </summary>
- public void Dispose()
- {
- DoDispose();
- GC.SuppressFinalize(this);
- LogHelper.InfoLog("RawImage.Disposed manually.");
- }
- /// <summary>
- /// 析构函数
- /// </summary>
- ~RawImage()
- {
- DoDispose();
- LogHelper.InfoLog("RawImage.Disposed by destructor.");
- }
- #endregion
- #region constructor
- /// <summary>
- /// 构造函数
- /// </summary>
- public RawImage()
- {
- _dataBuffer = null;
- _width = 0;
- _height = 0;
- _channel = 0;
- _stride = 0;
- _dataBufferSize = 0;
- }
- /// <summary>
- /// 构造函数
- /// </summary>
- /// <param name="dataBuffer">数据区,长度=stride*height</param>
- /// <param name="width">图像宽</param>
- /// <param name="height">图像高</param>
- /// <param name="channel">图像通道数</param>
- /// <param name="stride">图像一行的步长(行尾没有pad,则stride=width*channel,行尾有pad,则stride=ceil(width*channel/4.0)*4)</param>
- /// <param name="copy">在创建图像时是否拷贝整个数据区</param>
- public RawImage(byte[] dataBuffer, int width, int height, int channel, int stride, bool copy = false)
- {
- if (width < 0)
- {
- throw new ArgumentOutOfRangeException("width", "The expected image width is not less than 0, but got:" + width + ".");
- }
- if (height < 0)
- {
- throw new ArgumentOutOfRangeException("height", "The expected image height is not less than 0, but got:" + height + ".");
- }
- if (channel != 0 && channel != 1 && channel != 3 && channel != 4)
- {
- throw new ArgumentOutOfRangeException("channel", "The expected image channel is 0,1,3 or 4, but got:" + channel + ".");
- }
- if (stride != width * channel && stride != Convert.ToInt32(Math.Ceiling(width * channel / 4.0) * 4))
- {
- throw new ArgumentOutOfRangeException("stride", "Unexpected stride:" + stride + " while width=" + width + " and channel=" + channel + ".");
- }
- if (dataBuffer == null)
- {
- if (width * height * channel != 0)
- {
- throw new ArgumentNullException("data", "The image data buffer is null while width height and channel are not zero");
- }
- _dataBuffer = null;
- _width = 0;
- _height = 0;
- _channel = 0;
- _stride = 0;
- _dataBufferSize = 0;
- return;
- }
- if (dataBuffer.Length != stride * height)
- {
- throw new ArgumentException("data", "The expected data length is equal to stride * height, but got:" + dataBuffer.Length + ".");
- }
- if (stride == width * channel)
- {
- if (copy)
- {
- _dataBuffer = new byte[stride * height];
- Buffer.BlockCopy(dataBuffer, 0, _dataBuffer, 0, stride * height);
- }
- else
- {
- _dataBuffer = dataBuffer;
- }
- _width = width;
- _height = height;
- _channel = channel;
- _stride = stride;
- _dataBufferSize = stride * height;
- return;
- }
- // 不管输入数据是否在行尾有pad,在这里全部将其转成紧凑排列的形式
- _stride = width * channel;
- _width = width;
- _height = height;
- _channel = channel;
- _dataBufferSize = stride * height;
- _dataBuffer = new byte[_dataBufferSize];
- for (int nh = 0; nh < height; nh++)
- {
- Buffer.BlockCopy(dataBuffer, nh * stride, _dataBuffer, nh * _stride, _stride);
- }
- }
- #endregion
- #region public funcs
- /// <summary>
- /// 重新设置图像尺寸
- /// </summary>
- /// <param name="newWidth"></param>
- /// <param name="newHeight"></param>
- /// <param name="newChannel"></param>
- public void SetDataBufferSize(int newSize)
- {
- Array.Resize(ref _dataBuffer, newSize);
- }
- /// <summary>
- /// 从原图复制出一幅图,尺寸和通道数均与原图保持一致
- /// </summary>
- /// <returns></returns>
- public IImage Clone()
- {
- if (_dataBuffer == null)
- {
- return new RawImage();
- }
- byte[] clonedData = new byte[_dataBufferSize];
- Buffer.BlockCopy(_dataBuffer, 0, clonedData, 0, _dataBufferSize);
- return new RawImage(clonedData, _width, _height, _channel, _stride);
- }
- /// <summary>
- /// 从原图复制出一幅图,尺寸和原图一致,指定被复制后的图像通道数
- /// </summary>
- /// <param name="channel"></param>
- /// <returns></returns>
- public IImage Clone(int channel)
- {
- if (_dataBuffer == null)
- {
- return new RawImage();
- }
- int imageSize = _width * _height;
- byte[] clonedData = new byte[imageSize * channel];
- if (channel == _channel)
- {
- Buffer.BlockCopy(_dataBuffer, 0, clonedData, 0, _dataBufferSize);
- }
- if (channel < _channel)
- {
- for (int ni = 0; ni < imageSize; ni++)
- {
- Buffer.BlockCopy(_dataBuffer, ni * _channel, clonedData, ni * channel, channel);
- }
- }
- if (channel > _channel)
- {
- for (int ni = 0; ni < imageSize; ni++)
- {
- int pixelCopyOffsetSrc = ni * _channel;
- int pixelCopyOffsetDst = ni * channel;
- for (int nj = 0; nj < channel; nj++)
- {
- clonedData[pixelCopyOffsetDst + nj] = _dataBuffer[pixelCopyOffsetSrc];
- }
- }
- }
- return new RawImage(clonedData, _width, _height, channel, _width * channel);
- }
- /// <summary>
- /// 将图像数据复制到指定数组
- /// </summary>
- /// <param name="data"></param>
- public void CopyTo(ref byte[] data)
- {
- if (_dataBuffer == null)
- {
- return;
- }
- // 如果目标数组长度不够,resize一下
- if (data.Length < _dataBufferSize)
- {
- Array.Resize(ref data, _dataBufferSize);
- }
- Buffer.BlockCopy(_dataBuffer, 0, data, 0, _dataBufferSize);
- }
- /// <summary>
- /// 从指定byte数组
- /// </summary>
- /// <param name="data"></param>
- public void CopyFrom(byte[] data, int width, int height, int channel)
- {
- if (_dataBuffer == null || _width != width || _height != height || _channel != channel)
- {
- _width = width;
- _height = height;
- _channel = channel;
- _stride = _width * _channel;
- _dataBufferSize = _stride * _height;
- Array.Resize(ref _dataBuffer, _dataBufferSize);
- }
- if (data == null)
- {
- _dataBuffer = null;
- }
- else
- {
- Buffer.BlockCopy(data, 0, _dataBuffer, 0, _dataBufferSize);
- }
- }
- #endregion
- #region private funcs
- /// <summary>
- /// 销毁
- /// </summary>
- public void DoDispose()
- {
- if (_dataBuffer != null)
- {
- Array.Clear(_dataBuffer, 0, _dataBuffer.Length);
- _dataBuffer = null;
- }
- }
- #endregion
- }
- }
|