MainWindow.xaml.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. using System.Windows;
  2. using Accord.Video.FFMPEG;
  3. using System.Threading;
  4. using Microsoft.Win32;
  5. using System.Collections.Generic;
  6. using System.Threading.Tasks;
  7. using System;
  8. using System.Drawing;
  9. using System.Windows.Media.Imaging;
  10. using System.Drawing.Imaging;
  11. using System.Runtime.InteropServices;
  12. using VideoStatusInspectorCSLib;
  13. using System.Windows.Forms;
  14. using System.IO;
  15. using MessageBox = System.Windows.MessageBox;
  16. namespace ReadVideoDemo
  17. {
  18. /// <summary>
  19. /// MainWindow.xaml 的交互逻辑
  20. /// </summary>
  21. public partial class MainWindow : Window
  22. {
  23. [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
  24. public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
  25. private Queue<string> _videoReadyForTest1 = new Queue<string>();
  26. private VideoFileReader _reader1 = null;
  27. private readonly object _locker1 = new object();
  28. private ManualResetEvent _readEvent1 = new ManualResetEvent(false);
  29. private VideoStatusInspect _detect1 = new VideoStatusInspect();
  30. private Queue<string> _imagesReadyForTest1 = new Queue<string>();
  31. private int _imageCount = 0;
  32. private Queue<string> _videoReadyForTest2 = new Queue<string>();
  33. private VideoFileReader _reader2 = null;
  34. private readonly object _locker2 = new object();
  35. private ManualResetEvent _readEvent2 = new ManualResetEvent(false);
  36. private VideoStatusInspect _detect2 = new VideoStatusInspect();
  37. bool _useIntptrImage = true;
  38. #region 界面响应
  39. public MainWindow()
  40. {
  41. InitializeComponent();
  42. _detect1.SetWorkingStateDelayFrames(90);
  43. _detect2.SetWorkingStateDelayFrames(90);
  44. #if ENABLE_RAWIMAGE_SAVE
  45. _detect1.EnableDebugImagesWrite(true);
  46. _detect2.EnableDebugImagesWrite(true);
  47. #endif
  48. }
  49. /// <summary>
  50. /// 用户点击了加载视频按钮
  51. /// </summary>
  52. /// <param name="sender"></param>
  53. /// <param name="e"></param>
  54. private void OnLoadVideo1Click(object sender, RoutedEventArgs e)
  55. {
  56. if (_videoReadyForTest1.Count > 0 || _imagesReadyForTest1.Count > 0)
  57. {
  58. _videoReadyForTest1.Clear();
  59. _imagesReadyForTest1.Clear();
  60. }
  61. StopVideoReading1();
  62. Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
  63. openFileDialog.Filter = "视频文件|*.mp4;*.avi";
  64. openFileDialog.Multiselect = true;
  65. openFileDialog.Title = "选择一个或多个视频";
  66. if (openFileDialog.ShowDialog() ?? false)
  67. {
  68. foreach (string filename in openFileDialog.FileNames)
  69. {
  70. _videoReadyForTest1.Enqueue(filename);
  71. }
  72. DoVideoReading1();
  73. }
  74. }
  75. /// <summary>
  76. /// 用户点击了加载图像按钮
  77. /// </summary>
  78. /// <param name="sender"></param>
  79. /// <param name="e"></param>
  80. private void OnLoadImagesClick(object sender, RoutedEventArgs e)
  81. {
  82. if (_videoReadyForTest1.Count > 0 || _imagesReadyForTest1.Count > 0)
  83. {
  84. _videoReadyForTest1.Clear();
  85. _imagesReadyForTest1.Clear();
  86. }
  87. StopVideoReading1();
  88. System.Windows.Forms.FolderBrowserDialog dlg = new System.Windows.Forms.FolderBrowserDialog();
  89. dlg.Description = "请选择需要测试的图片文件夹";
  90. if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
  91. {
  92. string selectedFolder = dlg.SelectedPath;
  93. var files = Directory.GetFiles(selectedFolder);
  94. foreach (var file in files)
  95. {
  96. string extension = System.IO.Path.GetExtension(file);
  97. if (extension == ".jpg" || extension == ".bmp" || extension == ".png" || extension == ".txt")
  98. {
  99. _imagesReadyForTest1.Enqueue(file);
  100. }
  101. }
  102. _imageCount = _imagesReadyForTest1.Count;
  103. if (_imageCount > 0)
  104. {
  105. DoImageReading1();
  106. }
  107. else
  108. {
  109. MessageBox.Show("未加载到有效的图像数据");
  110. }
  111. }
  112. }
  113. /// <summary>
  114. /// 用户点击了解冻按钮
  115. /// </summary>
  116. /// <param name="sender"></param>
  117. /// <param name="e"></param>
  118. private void OnUnfreezeClick(object sender, RoutedEventArgs e)
  119. {
  120. _detect1.ManuallyUnfreeze();
  121. }
  122. /// <summary>
  123. /// 用户点击了停止播放按钮
  124. /// </summary>
  125. /// <param name="sender"></param>
  126. /// <param name="e"></param>
  127. private void OnStopReading1Click(object sender, RoutedEventArgs e)
  128. {
  129. if (_videoReadyForTest1.Count > 0)
  130. {
  131. _videoReadyForTest1.Clear();
  132. }
  133. StopVideoReading1();
  134. }
  135. /// <summary>
  136. /// 用户点击了加载视频按钮
  137. /// </summary>
  138. /// <param name="sender"></param>
  139. /// <param name="e"></param>
  140. private void OnLoadVideo2Click(object sender, RoutedEventArgs e)
  141. {
  142. if (_videoReadyForTest2.Count > 0)
  143. {
  144. _videoReadyForTest2.Clear();
  145. }
  146. StopVideoReading2();
  147. Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
  148. openFileDialog.Filter = "视频文件|*.mp4;*.avi";
  149. openFileDialog.Multiselect = true;
  150. openFileDialog.Title = "选择一个或多个视频";
  151. if (openFileDialog.ShowDialog() ?? false)
  152. {
  153. foreach (string filename in openFileDialog.FileNames)
  154. {
  155. _videoReadyForTest2.Enqueue(filename);
  156. }
  157. DoVideoReading2();
  158. }
  159. }
  160. /// <summary>
  161. /// 用户点击了停止播放按钮
  162. /// </summary>
  163. /// <param name="sender"></param>
  164. /// <param name="e"></param>
  165. private void OnStopReading2Click(object sender, RoutedEventArgs e)
  166. {
  167. if (_videoReadyForTest2.Count > 0)
  168. {
  169. _videoReadyForTest2.Clear();
  170. }
  171. StopVideoReading2();
  172. }
  173. /// <summary>
  174. /// 用户点击了关闭按钮
  175. /// </summary>
  176. /// <param name="sender"></param>
  177. /// <param name="e"></param>
  178. private void OnWindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
  179. {
  180. if (_videoReadyForTest1.Count > 0)
  181. {
  182. _videoReadyForTest1.Clear();
  183. }
  184. StopVideoReading1();
  185. if (_videoReadyForTest2.Count > 0)
  186. {
  187. _videoReadyForTest2.Clear();
  188. }
  189. StopVideoReading2();
  190. }
  191. #endregion
  192. #region 其他私有函数
  193. private void StopVideoReading1()
  194. {
  195. _readEvent1.Set();
  196. lock (_locker1)
  197. {
  198. if (_reader1 != null)
  199. {
  200. _reader1.Close();
  201. _reader1 = null;
  202. }
  203. }
  204. }
  205. private void DoVideoReading1()
  206. {
  207. Task.Run(() =>
  208. {
  209. try
  210. {
  211. if (_videoReadyForTest1.Count <= 0)
  212. {
  213. return;
  214. }
  215. string videoFilePath = _videoReadyForTest1.Dequeue();
  216. _readEvent1.Set();
  217. int frameCount = 0;
  218. int sleepTime = 0;
  219. lock (_locker1)
  220. {
  221. _reader1 = new VideoFileReader();
  222. _reader1.Open(videoFilePath);
  223. var frameRate = _reader1.FrameRate;
  224. frameCount = (int)_reader1.FrameCount;
  225. sleepTime = (int)(1000 / frameRate.ToDouble());
  226. }
  227. _readEvent1.Reset();
  228. for (int ni = 0; ni < frameCount; ni++)
  229. {
  230. if (_readEvent1.WaitOne(1))
  231. {
  232. break;
  233. }
  234. Bitmap img = null;
  235. lock (_locker1)
  236. {
  237. img = _reader1.ReadVideoFrame(ni);
  238. }
  239. if (img != null)
  240. {
  241. // 测试图像
  242. var detectStartTime = Environment.TickCount;
  243. CurrentVideoState nAuto = CurrentVideoState.Notjudged;
  244. var rawImage = BitmapToRawImage(img);
  245. if (_useIntptrImage)
  246. {
  247. GCHandle hObject = GCHandle.Alloc(rawImage.DataBuffer, GCHandleType.Pinned);
  248. IntPtr pPbject = hObject.AddrOfPinnedObject();
  249. IntptrRawImage intptrImage = new IntptrRawImage(pPbject, rawImage.Width, rawImage.Height, rawImage.ColorType);
  250. nAuto = _detect1.ImgDataCalculateCS(intptrImage);
  251. if (hObject.IsAllocated)
  252. {
  253. hObject.Free();
  254. }
  255. }
  256. else
  257. {
  258. nAuto = _detect1.ImgDataCalculateCS(rawImage);
  259. }
  260. rawImage.Dispose();
  261. var detectTimeUsed = Environment.TickCount - detectStartTime;
  262. // 显示图像
  263. Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
  264. {
  265. TestImage1.Source = BitmapToBitmapImage(img);
  266. VideoProgressBar1.Value = Convert.ToDouble(ni) / frameCount * 100;
  267. if (nAuto == CurrentVideoState.Stationary )
  268. {
  269. StatusText1.Text = "静置";
  270. }
  271. else if (nAuto == CurrentVideoState.Moving)
  272. {
  273. StatusText1.Text = "运行";
  274. }
  275. else if (nAuto == CurrentVideoState.Error)
  276. {
  277. StatusText1.Text = "error";
  278. }
  279. else
  280. {
  281. StatusText1.Text = "不能判断";
  282. }
  283. }));
  284. // sleep
  285. var finalSleepTime = sleepTime - detectTimeUsed;
  286. if (finalSleepTime < 0)
  287. {
  288. finalSleepTime = 0;
  289. }
  290. if (_readEvent1.WaitOne(finalSleepTime))
  291. {
  292. break;
  293. }
  294. }
  295. }
  296. DoVideoReading1();
  297. }
  298. catch (Exception excep)
  299. {
  300. System.Windows.MessageBox.Show("读取视频出错!:" + excep.Message);
  301. }
  302. });
  303. }
  304. private void DoImageReading1()
  305. {
  306. Task.Run(() =>
  307. {
  308. try
  309. {
  310. if (_imagesReadyForTest1.Count <= 0)
  311. {
  312. return;
  313. }
  314. double frameRate = 20;
  315. int sleepTime = (int)(1000 / frameRate);
  316. string imageFilePath = _imagesReadyForTest1.Dequeue();
  317. int ni = _imageCount - _imagesReadyForTest1.Count;
  318. _readEvent1.Reset();
  319. string extension = System.IO.Path.GetExtension(imageFilePath);
  320. Bitmap img = null;
  321. if (extension == ".txt")
  322. {
  323. var rawImage = RawImage.ReadRawImageFromFile(imageFilePath);
  324. img = RawImageToBitmap(rawImage);
  325. }
  326. else
  327. {
  328. img = new Bitmap(imageFilePath);
  329. }
  330. if(img!=null)
  331. {
  332. // 测试图像
  333. var detectStartTime = Environment.TickCount;
  334. CurrentVideoState nAuto = CurrentVideoState.Notjudged;
  335. var rawImage = BitmapToRawImage(img);
  336. if (_useIntptrImage)
  337. {
  338. GCHandle hObject = GCHandle.Alloc(rawImage.DataBuffer, GCHandleType.Pinned);
  339. IntPtr pPbject = hObject.AddrOfPinnedObject();
  340. IntptrRawImage intptrImage = new IntptrRawImage(pPbject, rawImage.Width, rawImage.Height, rawImage.ColorType);
  341. nAuto = _detect1.ImgDataCalculateCS(intptrImage);
  342. if (hObject.IsAllocated)
  343. {
  344. hObject.Free();
  345. }
  346. }
  347. else
  348. {
  349. nAuto = _detect1.ImgDataCalculateCS(rawImage);
  350. }
  351. rawImage.Dispose();
  352. var detectTimeUsed = Environment.TickCount - detectStartTime;
  353. // 显示图像
  354. Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
  355. {
  356. TestImage1.Source = BitmapToBitmapImage(img);
  357. VideoProgressBar1.Value = Convert.ToDouble(ni) / _imageCount * 100;
  358. if (nAuto == CurrentVideoState.Stationary)
  359. {
  360. StatusText1.Text = "静置";
  361. }
  362. else if (nAuto == CurrentVideoState.Moving)
  363. {
  364. StatusText1.Text = "运行";
  365. }
  366. else if (nAuto == CurrentVideoState.Error)
  367. {
  368. StatusText1.Text = "error";
  369. }
  370. else
  371. {
  372. StatusText1.Text = "不能判断";
  373. }
  374. }));
  375. // sleep
  376. var finalSleepTime = sleepTime - detectTimeUsed;
  377. if (finalSleepTime < 0)
  378. {
  379. finalSleepTime = 1;
  380. }
  381. _readEvent1.WaitOne(finalSleepTime);
  382. }
  383. DoImageReading1();
  384. }
  385. catch (Exception excep)
  386. {
  387. System.Windows.MessageBox.Show("读取图像出错!:" + excep.Message);
  388. }
  389. });
  390. }
  391. private void StopVideoReading2()
  392. {
  393. _readEvent2.Set();
  394. lock (_locker2)
  395. {
  396. if (_reader2 != null)
  397. {
  398. _reader2.Close();
  399. _reader2 = null;
  400. }
  401. }
  402. }
  403. private void DoVideoReading2()
  404. {
  405. Task.Run(() =>
  406. {
  407. try
  408. {
  409. if (_videoReadyForTest2.Count <= 0)
  410. {
  411. return;
  412. }
  413. string videoFilePath = _videoReadyForTest2.Dequeue();
  414. _readEvent2.Set();
  415. int frameCount = 0;
  416. int sleepTime = 0;
  417. lock (_locker2)
  418. {
  419. _reader2 = new VideoFileReader();
  420. _reader2.Open(videoFilePath);
  421. var frameRate = _reader2.FrameRate;
  422. frameCount = (int)_reader2.FrameCount;
  423. sleepTime = (int)(1000 / frameRate.ToDouble());
  424. }
  425. _readEvent2.Reset();
  426. for (int ni = 0; ni < frameCount; ni++)
  427. {
  428. if (_readEvent2.WaitOne(1))
  429. {
  430. break;
  431. }
  432. Bitmap img = null;
  433. lock (_locker2)
  434. {
  435. img = _reader2.ReadVideoFrame(ni);
  436. }
  437. if (img != null)
  438. {
  439. // 测试图像
  440. var detectStartTime = Environment.TickCount;
  441. CurrentVideoState nAuto = CurrentVideoState.Notjudged;
  442. var rawImage = BitmapToRawImage(img);
  443. if (_useIntptrImage)
  444. {
  445. GCHandle hObject = GCHandle.Alloc(rawImage.DataBuffer, GCHandleType.Pinned);
  446. IntPtr pPbject = hObject.AddrOfPinnedObject();
  447. IntptrRawImage intptrImage = new IntptrRawImage(pPbject, rawImage.Width, rawImage.Height, rawImage.ColorType);
  448. nAuto = _detect2.ImgDataCalculateCS(intptrImage);
  449. if (hObject.IsAllocated)
  450. {
  451. hObject.Free();
  452. }
  453. }
  454. else
  455. {
  456. nAuto = _detect2.ImgDataCalculateCS(rawImage);
  457. }
  458. rawImage.Dispose();
  459. var detectTimeUsed = Environment.TickCount - detectStartTime;
  460. // 显示图像
  461. Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
  462. {
  463. TestImage2.Source = BitmapToBitmapImage(img);
  464. VideoProgressBar2.Value = Convert.ToDouble(ni) / frameCount * 100;
  465. if (nAuto == CurrentVideoState.Stationary)
  466. {
  467. StatusText2.Text = "静置";
  468. }
  469. else if (nAuto == CurrentVideoState.Moving)
  470. {
  471. StatusText2.Text = "运行";
  472. }
  473. else if (nAuto == CurrentVideoState.Error)
  474. {
  475. StatusText2.Text = "error";
  476. }
  477. else
  478. {
  479. StatusText2.Text = "不能判断";
  480. }
  481. }));
  482. // sleep
  483. var finalSleepTime = sleepTime - detectTimeUsed;
  484. if (finalSleepTime < 0)
  485. {
  486. finalSleepTime = 0;
  487. }
  488. if (_readEvent2.WaitOne(finalSleepTime))
  489. {
  490. break;
  491. }
  492. }
  493. }
  494. DoVideoReading2();
  495. }
  496. catch (Exception excep)
  497. {
  498. System.Windows.MessageBox.Show("读取视频出错!:" + excep.Message);
  499. }
  500. });
  501. }
  502. /// <summary>
  503. /// 将Bitmap转换为BitmapImage
  504. /// </summary>
  505. /// <param name="img"></param>
  506. /// <returns></returns>
  507. private BitmapImage BitmapToBitmapImage(Bitmap img)
  508. {
  509. BitmapImage bmpimg = new BitmapImage();
  510. using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
  511. {
  512. img.Save(ms, ImageFormat.Png);
  513. bmpimg.BeginInit();
  514. bmpimg.StreamSource = ms;
  515. bmpimg.CacheOption = BitmapCacheOption.OnLoad;
  516. bmpimg.EndInit();
  517. bmpimg.Freeze();
  518. ms.Dispose();
  519. }
  520. return bmpimg;
  521. }
  522. /// <summary>
  523. /// 将System.Drawimg.Bitmap转为RawImage
  524. /// </summary>
  525. /// <param name="image"></param>
  526. /// <param name="keepChannel"></param>
  527. /// <returns></returns>
  528. public static RawImage BitmapToRawImage(Bitmap image, bool keepColorType = false)
  529. {
  530. int width = image.Width;
  531. int height = image.Height;
  532. PixelFormat pixelFormat = image.PixelFormat;
  533. if (pixelFormat != PixelFormat.Format24bppRgb && pixelFormat != PixelFormat.Format32bppArgb
  534. && pixelFormat != PixelFormat.Format8bppIndexed && pixelFormat != PixelFormat.Format16bppGrayScale)
  535. {
  536. throw new Exception("Unexpected image pixel format:" + pixelFormat);
  537. }
  538. EnumColorType origColorType = EnumColorType.Gray8;
  539. int origBytesPerPixel = 1;
  540. if (pixelFormat == PixelFormat.Format8bppIndexed)
  541. {
  542. origColorType = EnumColorType.Gray8;
  543. origBytesPerPixel = 1;
  544. }
  545. else if (pixelFormat == PixelFormat.Format16bppGrayScale)
  546. {
  547. origColorType = EnumColorType.Gray16;
  548. origBytesPerPixel = 2;
  549. }
  550. else if (pixelFormat == PixelFormat.Format24bppRgb)
  551. {
  552. // 注意Bitmap里的24bppRgb其实通道顺序是BGR
  553. origColorType = EnumColorType.Bgr;
  554. origBytesPerPixel = 3;
  555. }
  556. else
  557. {
  558. // 注意Bitmap里的32Argb其实通道顺序是Bgra
  559. origColorType = EnumColorType.Bgra;
  560. origBytesPerPixel = 4;
  561. }
  562. EnumColorType dstColorType;
  563. int dstBytesPerPixel;
  564. if (keepColorType)
  565. {
  566. dstColorType = origColorType;
  567. dstBytesPerPixel = origBytesPerPixel;
  568. }
  569. else
  570. {
  571. // 如果没有指定要keepColorType的话,默认都转成BGR
  572. dstColorType = EnumColorType.Bgr;
  573. dstBytesPerPixel = 3;
  574. }
  575. var bmData = image.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, pixelFormat);
  576. byte[] dstDataArray = new byte[width * height * dstBytesPerPixel];
  577. unsafe
  578. {
  579. int stride = bmData.Stride;
  580. int dstStride = width * dstBytesPerPixel;
  581. IntPtr ptr = bmData.Scan0;
  582. IntPtr ptrH, ptrW;
  583. // 原图和目标图的ColorType相同
  584. if (origColorType == dstColorType)
  585. {
  586. for (int nh = 0; nh < height; nh++)
  587. {
  588. ptrH = IntPtr.Add(ptr, nh * stride);
  589. Marshal.Copy(ptrH, dstDataArray, nh * dstStride, dstStride);
  590. }
  591. }
  592. // 原图和目标图的ColorType不同
  593. else
  594. {
  595. // 如果原图是8位灰度图
  596. if (origColorType == EnumColorType.Gray8)
  597. {
  598. if (dstColorType == EnumColorType.Gray16)
  599. {
  600. byte gray;
  601. int dstOffset;
  602. for (int nh = 0; nh < height; nh++)
  603. {
  604. ptrH = IntPtr.Add(ptr, nh * stride);
  605. for (int nw = 0; nw < width; nw++)
  606. {
  607. ptrW = IntPtr.Add(ptrH, nw * origBytesPerPixel);
  608. gray = Marshal.ReadByte(ptrW);
  609. dstOffset = nh * dstStride + nw * dstBytesPerPixel;
  610. dstDataArray[dstOffset] = gray;
  611. // 高位为0,因此不用赋值
  612. }
  613. }
  614. }
  615. else
  616. {
  617. byte gray;
  618. int dstOffset;
  619. for (int nh = 0; nh < height; nh++)
  620. {
  621. ptrH = IntPtr.Add(ptr, nh * stride);
  622. for (int nw = 0; nw < width; nw++)
  623. {
  624. ptrW = IntPtr.Add(ptrH, nw * origBytesPerPixel);
  625. gray = Marshal.ReadByte(ptrW);
  626. dstOffset = nh * dstStride + nw * dstBytesPerPixel;
  627. dstDataArray[dstOffset] = gray;
  628. dstDataArray[dstOffset + 1] = gray;
  629. dstDataArray[dstOffset + 2] = gray;
  630. }
  631. }
  632. if (dstColorType == EnumColorType.Bgra)
  633. {
  634. for (int nh = 0; nh < height; nh++)
  635. {
  636. for (int nw = 0; nw < width; nw++)
  637. {
  638. dstOffset = nh * dstStride + nw * dstBytesPerPixel;
  639. dstDataArray[dstOffset + 3] = 255;
  640. }
  641. }
  642. }
  643. }
  644. }
  645. // 如果原图是BGR彩色图
  646. if (origColorType == EnumColorType.Bgr)
  647. {
  648. if (dstColorType == EnumColorType.Gray8 || dstColorType == EnumColorType.Gray16)
  649. {
  650. byte red, green, blue, gray;
  651. int dstOffset;
  652. for (int nh = 0; nh < height; nh++)
  653. {
  654. ptrH = IntPtr.Add(ptr, nh * stride);
  655. for (int nw = 0; nw < width; nw++)
  656. {
  657. ptrW = IntPtr.Add(ptrH, nw * origBytesPerPixel);
  658. blue = Marshal.ReadByte(ptrW);
  659. ptrW = IntPtr.Add(ptrW, 1);
  660. green = Marshal.ReadByte(ptrW);
  661. ptrW = IntPtr.Add(ptrW, 1);
  662. red = Marshal.ReadByte(ptrW);
  663. gray = RawImage.PixelRGBToGray(red, green, blue);
  664. dstOffset = nh * dstStride + nw * dstBytesPerPixel;
  665. dstDataArray[dstOffset] = gray;
  666. }
  667. }
  668. }
  669. if (dstColorType == EnumColorType.Bgra)
  670. {
  671. int dstOffset;
  672. for (int nh = 0; nh < height; nh++)
  673. {
  674. ptrH = IntPtr.Add(ptr, nh * stride);
  675. for (int nw = 0; nw < width; nw++)
  676. {
  677. ptrW = IntPtr.Add(ptrH, nw * origBytesPerPixel);
  678. dstOffset = nh * dstStride + nw * dstBytesPerPixel;
  679. Marshal.Copy(ptrW, dstDataArray, dstOffset, 3);
  680. dstDataArray[dstOffset + 3] = 255;
  681. }
  682. }
  683. }
  684. }
  685. // 如果原图是BGRA彩色图
  686. if (origColorType == EnumColorType.Bgra)
  687. {
  688. if (dstColorType == EnumColorType.Gray8 || dstColorType == EnumColorType.Gray16)
  689. {
  690. byte red, green, blue, gray;
  691. int dstOffset;
  692. for (int nh = 0; nh < height; nh++)
  693. {
  694. ptrH = IntPtr.Add(ptr, nh * stride);
  695. for (int nw = 0; nw < width; nw++)
  696. {
  697. ptrW = IntPtr.Add(ptrH, nw * origBytesPerPixel);
  698. blue = Marshal.ReadByte(ptrW);
  699. ptrW = IntPtr.Add(ptrW, 1);
  700. green = Marshal.ReadByte(ptrW);
  701. ptrW = IntPtr.Add(ptrW, 1);
  702. red = Marshal.ReadByte(ptrW);
  703. gray = RawImage.PixelRGBToGray(red, green, blue);
  704. dstOffset = nh * dstStride + nw * dstBytesPerPixel;
  705. dstDataArray[dstOffset] = gray;
  706. }
  707. }
  708. }
  709. if (dstColorType == EnumColorType.Bgr)
  710. {
  711. int dstOffset;
  712. for (int nh = 0; nh < height; nh++)
  713. {
  714. ptrH = IntPtr.Add(ptr, nh * stride);
  715. for (int nw = 0; nw < width; nw++)
  716. {
  717. ptrW = IntPtr.Add(ptrH, nw * origBytesPerPixel);
  718. dstOffset = nh * dstStride + nw * dstBytesPerPixel;
  719. Marshal.Copy(ptrW, dstDataArray, dstOffset, 3);
  720. }
  721. }
  722. }
  723. }
  724. }
  725. }
  726. image.UnlockBits(bmData);
  727. return new RawImage(dstDataArray, width, height, dstColorType);
  728. }
  729. /// <summary>
  730. /// 将RawImage转为System.Drawing.Bitmap
  731. /// </summary>
  732. /// <param name="image"></param>
  733. /// <returns></returns>
  734. public static Bitmap RawImageToBitmap(RawImage image)
  735. {
  736. int width = image.Width;
  737. int height = image.Height;
  738. EnumColorType colorType = image.ColorType;
  739. PixelFormat pixelFormat;
  740. EnumColorType dstColorType;
  741. RawImage clonedImage;
  742. switch (colorType)
  743. {
  744. case EnumColorType.Gray8:
  745. clonedImage = image;
  746. pixelFormat = PixelFormat.Format8bppIndexed;
  747. dstColorType = EnumColorType.Gray8;
  748. break;
  749. case EnumColorType.Gray16:
  750. clonedImage = image;
  751. pixelFormat = PixelFormat.Format16bppGrayScale;
  752. dstColorType = EnumColorType.Gray16;
  753. break;
  754. case EnumColorType.GrayF32:
  755. clonedImage = image.Clone(EnumColorType.Gray8);
  756. pixelFormat = PixelFormat.Format8bppIndexed;
  757. dstColorType = EnumColorType.Gray8;
  758. break;
  759. case EnumColorType.Bgr:
  760. clonedImage = image;
  761. pixelFormat = PixelFormat.Format24bppRgb;
  762. dstColorType = EnumColorType.Bgr;
  763. break;
  764. case EnumColorType.Rgb:
  765. clonedImage = image.Clone(EnumColorType.Bgr);
  766. pixelFormat = PixelFormat.Format24bppRgb;
  767. dstColorType = EnumColorType.Bgr;
  768. break;
  769. case EnumColorType.Bgra:
  770. clonedImage = image;
  771. pixelFormat = PixelFormat.Format32bppArgb;
  772. dstColorType = EnumColorType.Bgra;
  773. break;
  774. case EnumColorType.Rgba:
  775. clonedImage = image.Clone(EnumColorType.Bgra);
  776. pixelFormat = PixelFormat.Format32bppArgb;
  777. dstColorType = EnumColorType.Bgra;
  778. break;
  779. default:
  780. throw new ArgumentOutOfRangeException("Unexpected image.colorType.");
  781. }
  782. Bitmap dstBmp = new Bitmap(width, height, pixelFormat);
  783. var bmData = dstBmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, pixelFormat);
  784. unsafe
  785. {
  786. int stride = bmData.Stride;
  787. IntPtr ptr = bmData.Scan0;
  788. byte[] dataBuffer = clonedImage.DataBuffer;
  789. int bytePerPixel = clonedImage.BytesPerPixel;
  790. if (stride == width * bytePerPixel)
  791. {
  792. Marshal.Copy(dataBuffer, 0, ptr, width * height * bytePerPixel);
  793. }
  794. else
  795. {
  796. IntPtr ptrDst;
  797. for (int ni = 0; ni < height; ni++)
  798. {
  799. ptrDst = IntPtr.Add(ptr, ni * stride);
  800. Marshal.Copy(dataBuffer, ni * width * bytePerPixel, ptrDst, width * bytePerPixel);
  801. }
  802. }
  803. }
  804. dstBmp.UnlockBits(bmData);
  805. // 灰度图像需要写调色板
  806. if (dstColorType == EnumColorType.Gray8)
  807. {
  808. var palette = dstBmp.Palette;
  809. for (int ni = 0; ni < 256; ni++)
  810. {
  811. palette.Entries[ni] = Color.FromArgb(ni, ni, ni);
  812. }
  813. dstBmp.Palette = palette;
  814. }
  815. return dstBmp;
  816. }
  817. #endregion
  818. }
  819. }