using System; using System.IO; namespace YOLODetectProcessLib { /// /// 裸图像 /// 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 实现接口 /// /// 数据区,长度=Stride*Height,通道顺序为BGR /// public byte[] DataBuffer { get => _dataBuffer; } /// /// 图像宽度 /// public int Width { get => _width; set => _width = value; } /// /// 图像高度 /// public int Height { get => _height; set => _height = value; } /// /// 图像通道数 /// public int Channel { get => _channel; set => _channel = value; } /// /// 步长=Width*Channel /// public int Stride { get => _stride; set => _stride = value; } /// /// 图像区的长度=width*height*channel /// public int DataBufferSize { get => _dataBufferSize; set => _dataBufferSize = value; } /// /// 从文件读入 /// /// /// 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; } /// /// 保存到文件 /// /// /// 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; } /// /// 销毁资源 /// public void Dispose() { DoDispose(); GC.SuppressFinalize(this); LogHelper.InfoLog("RawImage.Disposed manually."); } /// /// 析构函数 /// ~RawImage() { DoDispose(); LogHelper.InfoLog("RawImage.Disposed by destructor."); } #endregion #region constructor /// /// 构造函数 /// public RawImage() { _dataBuffer = null; _width = 0; _height = 0; _channel = 0; _stride = 0; _dataBufferSize = 0; } /// /// 构造函数 /// /// 数据区,长度=stride*height /// 图像宽 /// 图像高 /// 图像通道数 /// 图像一行的步长(行尾没有pad,则stride=width*channel,行尾有pad,则stride=ceil(width*channel/4.0)*4) /// 在创建图像时是否拷贝整个数据区 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 /// /// 重新设置图像尺寸 /// /// /// /// public void SetDataBufferSize(int newSize) { Array.Resize(ref _dataBuffer, newSize); } /// /// 从原图复制出一幅图,尺寸和通道数均与原图保持一致 /// /// 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); } /// /// 从原图复制出一幅图,尺寸和原图一致,指定被复制后的图像通道数 /// /// /// 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); } /// /// 将图像数据复制到指定数组 /// /// 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); } /// /// 从指定byte数组 /// /// 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 /// /// 销毁 /// public void DoDispose() { if (_dataBuffer != null) { Array.Clear(_dataBuffer, 0, _dataBuffer.Length); _dataBuffer = null; } } #endregion } }