1
0

RawImage.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. using System;
  2. using System.IO;
  3. namespace YOLODetectProcessLib
  4. {
  5. /// <summary>
  6. /// 裸图像
  7. /// </summary>
  8. public class RawImage : IImage
  9. {
  10. #region private variables
  11. private byte[] _dataBuffer;
  12. private int _width;
  13. private int _height;
  14. private int _channel;
  15. private int _stride;
  16. private int _dataBufferSize;
  17. #endregion
  18. #region 实现接口
  19. /// <summary>
  20. /// 数据区,长度=Stride*Height,通道顺序为BGR
  21. /// </summary>
  22. public byte[] DataBuffer { get => _dataBuffer; }
  23. /// <summary>
  24. /// 图像宽度
  25. /// </summary>
  26. public int Width { get => _width; set => _width = value; }
  27. /// <summary>
  28. /// 图像高度
  29. /// </summary>
  30. public int Height { get => _height; set => _height = value; }
  31. /// <summary>
  32. /// 图像通道数
  33. /// </summary>
  34. public int Channel { get => _channel; set => _channel = value; }
  35. /// <summary>
  36. /// 步长=Width*Channel
  37. /// </summary>
  38. public int Stride { get => _stride; set => _stride = value; }
  39. /// <summary>
  40. /// 图像区的长度=width*height*channel
  41. /// </summary>
  42. public int DataBufferSize { get => _dataBufferSize; set => _dataBufferSize = value; }
  43. /// <summary>
  44. /// 从文件读入
  45. /// </summary>
  46. /// <param name="filePath"></param>
  47. /// <returns></returns>
  48. public void ReadFromFile(string filePath)
  49. {
  50. if (!File.Exists(filePath))
  51. {
  52. throw new FileNotFoundException("Failed to read RawImage from file.", filePath);
  53. }
  54. FileStream fs = new FileStream(filePath, FileMode.Open);
  55. int len = (int)fs.Length;
  56. if (len < 20)
  57. {
  58. throw new ArgumentException("Unexpected file content.");
  59. }
  60. byte[] extraInfo = new byte[20];
  61. fs.Read(extraInfo, 0, 20);
  62. if (_dataBuffer != null)
  63. {
  64. if (_dataBuffer.Length != len - 20)
  65. {
  66. Array.Resize(ref _dataBuffer, len - 20);
  67. }
  68. }
  69. else
  70. {
  71. _dataBuffer = new byte[len - 20];
  72. }
  73. fs.Read(_dataBuffer, 0, len - 20);
  74. _width = System.BitConverter.ToInt32(extraInfo, 0);
  75. _height = System.BitConverter.ToInt32(extraInfo, 4);
  76. _channel = System.BitConverter.ToInt32(extraInfo, 8);
  77. _stride = System.BitConverter.ToInt32(extraInfo, 12);
  78. _dataBufferSize = System.BitConverter.ToInt32(extraInfo, 16);
  79. if (_dataBuffer.Length != _dataBufferSize)
  80. {
  81. throw new ArgumentException("Missing image data.");
  82. }
  83. return;
  84. }
  85. /// <summary>
  86. /// 保存到文件
  87. /// </summary>
  88. /// <param name="filePath"></param>
  89. /// <returns></returns>
  90. public void SaveIntoFile(string filePath)
  91. {
  92. FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
  93. byte[] width = System.BitConverter.GetBytes(_width);
  94. byte[] height = System.BitConverter.GetBytes(_height);
  95. byte[] channel = System.BitConverter.GetBytes(_channel);
  96. byte[] stride = System.BitConverter.GetBytes(_stride);
  97. byte[] dataSize = System.BitConverter.GetBytes(_dataBufferSize);
  98. fs.Write(width, 0, width.Length);
  99. fs.Write(height, 0, height.Length);
  100. fs.Write(channel, 0, channel.Length);
  101. fs.Write(stride, 0, stride.Length);
  102. fs.Write(dataSize, 0, dataSize.Length);
  103. fs.Write(_dataBuffer, 0, _dataBuffer.Length);
  104. fs.Close();
  105. return;
  106. }
  107. /// <summary>
  108. /// 销毁资源
  109. /// </summary>
  110. public void Dispose()
  111. {
  112. DoDispose();
  113. GC.SuppressFinalize(this);
  114. LogHelper.InfoLog("RawImage.Disposed manually.");
  115. }
  116. /// <summary>
  117. /// 析构函数
  118. /// </summary>
  119. ~RawImage()
  120. {
  121. DoDispose();
  122. LogHelper.InfoLog("RawImage.Disposed by destructor.");
  123. }
  124. #endregion
  125. #region constructor
  126. /// <summary>
  127. /// 构造函数
  128. /// </summary>
  129. public RawImage()
  130. {
  131. _dataBuffer = null;
  132. _width = 0;
  133. _height = 0;
  134. _channel = 0;
  135. _stride = 0;
  136. _dataBufferSize = 0;
  137. }
  138. /// <summary>
  139. /// 构造函数
  140. /// </summary>
  141. /// <param name="dataBuffer">数据区,长度=stride*height</param>
  142. /// <param name="width">图像宽</param>
  143. /// <param name="height">图像高</param>
  144. /// <param name="channel">图像通道数</param>
  145. /// <param name="stride">图像一行的步长(行尾没有pad,则stride=width*channel,行尾有pad,则stride=ceil(width*channel/4.0)*4)</param>
  146. /// <param name="copy">在创建图像时是否拷贝整个数据区</param>
  147. public RawImage(byte[] dataBuffer, int width, int height, int channel, int stride, bool copy = false)
  148. {
  149. if (width < 0)
  150. {
  151. throw new ArgumentOutOfRangeException("width", "The expected image width is not less than 0, but got:" + width + ".");
  152. }
  153. if (height < 0)
  154. {
  155. throw new ArgumentOutOfRangeException("height", "The expected image height is not less than 0, but got:" + height + ".");
  156. }
  157. if (channel != 0 && channel != 1 && channel != 3 && channel != 4)
  158. {
  159. throw new ArgumentOutOfRangeException("channel", "The expected image channel is 0,1,3 or 4, but got:" + channel + ".");
  160. }
  161. if (stride != width * channel && stride != Convert.ToInt32(Math.Ceiling(width * channel / 4.0) * 4))
  162. {
  163. throw new ArgumentOutOfRangeException("stride", "Unexpected stride:" + stride + " while width=" + width + " and channel=" + channel + ".");
  164. }
  165. if (dataBuffer == null)
  166. {
  167. if (width * height * channel != 0)
  168. {
  169. throw new ArgumentNullException("data", "The image data buffer is null while width height and channel are not zero");
  170. }
  171. _dataBuffer = null;
  172. _width = 0;
  173. _height = 0;
  174. _channel = 0;
  175. _stride = 0;
  176. _dataBufferSize = 0;
  177. return;
  178. }
  179. if (dataBuffer.Length != stride * height)
  180. {
  181. throw new ArgumentException("data", "The expected data length is equal to stride * height, but got:" + dataBuffer.Length + ".");
  182. }
  183. if (stride == width * channel)
  184. {
  185. if (copy)
  186. {
  187. _dataBuffer = new byte[stride * height];
  188. Buffer.BlockCopy(dataBuffer, 0, _dataBuffer, 0, stride * height);
  189. }
  190. else
  191. {
  192. _dataBuffer = dataBuffer;
  193. }
  194. _width = width;
  195. _height = height;
  196. _channel = channel;
  197. _stride = stride;
  198. _dataBufferSize = stride * height;
  199. return;
  200. }
  201. // 不管输入数据是否在行尾有pad,在这里全部将其转成紧凑排列的形式
  202. _stride = width * channel;
  203. _width = width;
  204. _height = height;
  205. _channel = channel;
  206. _dataBufferSize = stride * height;
  207. _dataBuffer = new byte[_dataBufferSize];
  208. for (int nh = 0; nh < height; nh++)
  209. {
  210. Buffer.BlockCopy(dataBuffer, nh * stride, _dataBuffer, nh * _stride, _stride);
  211. }
  212. }
  213. #endregion
  214. #region public funcs
  215. /// <summary>
  216. /// 重新设置图像尺寸
  217. /// </summary>
  218. /// <param name="newWidth"></param>
  219. /// <param name="newHeight"></param>
  220. /// <param name="newChannel"></param>
  221. public void SetDataBufferSize(int newSize)
  222. {
  223. Array.Resize(ref _dataBuffer, newSize);
  224. }
  225. /// <summary>
  226. /// 从原图复制出一幅图,尺寸和通道数均与原图保持一致
  227. /// </summary>
  228. /// <returns></returns>
  229. public IImage Clone()
  230. {
  231. if (_dataBuffer == null)
  232. {
  233. return new RawImage();
  234. }
  235. byte[] clonedData = new byte[_dataBufferSize];
  236. Buffer.BlockCopy(_dataBuffer, 0, clonedData, 0, _dataBufferSize);
  237. return new RawImage(clonedData, _width, _height, _channel, _stride);
  238. }
  239. /// <summary>
  240. /// 从原图复制出一幅图,尺寸和原图一致,指定被复制后的图像通道数
  241. /// </summary>
  242. /// <param name="channel"></param>
  243. /// <returns></returns>
  244. public IImage Clone(int channel)
  245. {
  246. if (_dataBuffer == null)
  247. {
  248. return new RawImage();
  249. }
  250. int imageSize = _width * _height;
  251. byte[] clonedData = new byte[imageSize * channel];
  252. if (channel == _channel)
  253. {
  254. Buffer.BlockCopy(_dataBuffer, 0, clonedData, 0, _dataBufferSize);
  255. }
  256. if (channel < _channel)
  257. {
  258. for (int ni = 0; ni < imageSize; ni++)
  259. {
  260. Buffer.BlockCopy(_dataBuffer, ni * _channel, clonedData, ni * channel, channel);
  261. }
  262. }
  263. if (channel > _channel)
  264. {
  265. for (int ni = 0; ni < imageSize; ni++)
  266. {
  267. int pixelCopyOffsetSrc = ni * _channel;
  268. int pixelCopyOffsetDst = ni * channel;
  269. for (int nj = 0; nj < channel; nj++)
  270. {
  271. clonedData[pixelCopyOffsetDst + nj] = _dataBuffer[pixelCopyOffsetSrc];
  272. }
  273. }
  274. }
  275. return new RawImage(clonedData, _width, _height, channel, _width * channel);
  276. }
  277. /// <summary>
  278. /// 将图像数据复制到指定数组
  279. /// </summary>
  280. /// <param name="data"></param>
  281. public void CopyTo(ref byte[] data)
  282. {
  283. if (_dataBuffer == null)
  284. {
  285. return;
  286. }
  287. // 如果目标数组长度不够,resize一下
  288. if (data.Length < _dataBufferSize)
  289. {
  290. Array.Resize(ref data, _dataBufferSize);
  291. }
  292. Buffer.BlockCopy(_dataBuffer, 0, data, 0, _dataBufferSize);
  293. }
  294. /// <summary>
  295. /// 从指定byte数组
  296. /// </summary>
  297. /// <param name="data"></param>
  298. public void CopyFrom(byte[] data, int width, int height, int channel)
  299. {
  300. if (_dataBuffer == null || _width != width || _height != height || _channel != channel)
  301. {
  302. _width = width;
  303. _height = height;
  304. _channel = channel;
  305. _stride = _width * _channel;
  306. _dataBufferSize = _stride * _height;
  307. Array.Resize(ref _dataBuffer, _dataBufferSize);
  308. }
  309. if (data == null)
  310. {
  311. _dataBuffer = null;
  312. }
  313. else
  314. {
  315. Buffer.BlockCopy(data, 0, _dataBuffer, 0, _dataBufferSize);
  316. }
  317. }
  318. #endregion
  319. #region private funcs
  320. /// <summary>
  321. /// 销毁
  322. /// </summary>
  323. public void DoDispose()
  324. {
  325. if (_dataBuffer != null)
  326. {
  327. Array.Clear(_dataBuffer, 0, _dataBuffer.Length);
  328. _dataBuffer = null;
  329. }
  330. }
  331. #endregion
  332. }
  333. }