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
}
}