Camera.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. using IvfTl.Control.Entity.GlobalEnums;
  2. using System.Drawing;
  3. using System.Runtime.ExceptionServices;
  4. using System.Runtime.InteropServices;
  5. using System.Security;
  6. using System.Security.Cryptography;
  7. using System.Text;
  8. namespace ivf_tl_CameraHelper
  9. {
  10. /// <summary>
  11. /// 相机助手类
  12. /// </summary>
  13. public class Camera
  14. {
  15. public event Action<Exception, string, string, LogEnum> ExceptionLogEvent;
  16. public event Action<DateTime, string, LogEnum> HouseLogEvent;
  17. private int index = 0;
  18. private int width = 0;
  19. private int height = 0;
  20. private int exposure = 0;
  21. public int camnums = 0;
  22. [MarshalAs(UnmanagedType.LPTStr)]
  23. public string NumBer = "";
  24. /// <summary>
  25. /// MVC数字相机的索引号(从0开始),用于指定要进行初始化操作的相机。
  26. /// </summary>
  27. public int Index { get { return index; } }
  28. /// <summary>
  29. /// 图像宽度
  30. /// </summary>
  31. public int Width { get { return width; } }
  32. /// <summary>
  33. /// 图像高度
  34. /// </summary>
  35. public int Height { get { return height; } }
  36. /// <summary>
  37. /// 曝光时间(单位:100us)
  38. /// </summary>
  39. public int Exposure { get { return exposure; } }
  40. /// <summary>
  41. /// CCD是否加载
  42. /// </summary>
  43. public bool IsInit { get; set; } = false;
  44. /// <summary>
  45. /// CCD是否开启
  46. /// </summary>
  47. public bool IsStart { get; set; } = false;
  48. /// <summary>
  49. /// 图像字节数组
  50. /// </summary>
  51. public byte[] SourceBuffer //{ get; private set; }
  52. {
  53. get
  54. {
  55. byte[] sourceBuffer = new byte[this.width * this.height * 3];
  56. Marshal.Copy(pDest, sourceBuffer, 0, sourceBuffer.Length);
  57. return sourceBuffer;
  58. }
  59. }
  60. public byte[] SaveRgbData = new byte[3];
  61. public void UpdataSourceBuffer()
  62. {
  63. //SourceBuffer = new byte[this.width * this.height * 3];
  64. //Marshal.Copy(pDest, SourceBuffer, 0, SourceBuffer.Length);
  65. }
  66. /// <summary>
  67. /// 获取相机对应得序列号
  68. /// </summary>
  69. /// <returns></returns>
  70. [HandleProcessCorruptedStateExceptions]
  71. [SecurityCritical]
  72. public int GetNumbet()
  73. {
  74. try
  75. {
  76. int result = -1;
  77. lock (locker)
  78. {
  79. StringBuilder strSerial = new StringBuilder(125);
  80. result = MVCAPI.MV_Usb2GetSerial(this.hImager, strSerial);
  81. NumBer = strSerial.ToString();
  82. }
  83. return result;
  84. }
  85. catch (Exception ex)
  86. {
  87. ExceptionLogEvent?.Invoke(ex, "获取序列号", null, LogEnum.RunException);
  88. return -2;
  89. }
  90. }
  91. /// <summary>
  92. /// 获取一张图像
  93. /// </summary>
  94. //public BitmapImage BitmapImage
  95. //{
  96. // get
  97. // {
  98. // Bitmap bitmap = new Bitmap(this.width, this.height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  99. // System.Drawing.Imaging.BitmapData bmpData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat);
  100. // Marshal.Copy(this.SourceBuffer, 0, bmpData.Scan0, this.SourceBuffer.Length);
  101. // bitmap.UnlockBits(bmpData);
  102. // bitmap.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipY);
  103. // BitmapImage bitmapImage = new BitmapImage();
  104. // using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
  105. // {
  106. // bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
  107. // bitmapImage.BeginInit();
  108. // bitmapImage.StreamSource = ms;
  109. // bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
  110. // bitmapImage.EndInit();
  111. // bitmapImage.Freeze();
  112. // }
  113. // return bitmapImage;
  114. // }
  115. //}
  116. /// <summary>
  117. /// 结构体
  118. /// </summary>
  119. private CapInfoStruct capInfoStruct = new CapInfoStruct();
  120. /// <summary>
  121. /// 由MV_Usb2Init返回的MVC设备句柄
  122. /// </summary>
  123. public IntPtr hImager;
  124. /// <summary>
  125. /// 回传的图像字节数组
  126. /// </summary>
  127. private IntPtr pDest;
  128. public Camera(int index, int width, int height, int exposure)
  129. {
  130. this.index = index;
  131. this.width = width;
  132. this.height = height;
  133. this.exposure = exposure;
  134. pDest = Marshal.AllocCoTaskMem(this.width * this.height * 3);
  135. }
  136. public Camera(CameraModel model)
  137. {
  138. this.index = model.Index;
  139. this.width = model.Width;
  140. this.height = model.Height;
  141. this.exposure = model.Exposure;
  142. pDest = Marshal.AllocCoTaskMem(this.width * this.height * 3);
  143. }
  144. /// <summary>
  145. /// 初使化相机[注:执行init()之后立即执行SetOpMode()以开启像捕捉 2021.11.11]
  146. /// </summary>
  147. /// <returns></returns>
  148. public int Init()
  149. {
  150. try
  151. {
  152. byte[] mGain = new byte[3];
  153. mGain[0] = Convert.ToByte(25);
  154. mGain[1] = Convert.ToByte(14);
  155. mGain[2] = Convert.ToByte(25);
  156. byte Control = Convert.ToByte(04);
  157. capInfoStruct.Buffer = Marshal.AllocCoTaskMem(this.width * this.height * 3);
  158. capInfoStruct.Width = this.width;
  159. capInfoStruct.Height = this.height;
  160. capInfoStruct.HorizontalOffset = 0;
  161. capInfoStruct.VerticalOffset = 0;
  162. capInfoStruct.Exposure = this.exposure;
  163. capInfoStruct.Gain = mGain;
  164. capInfoStruct.Control = Control;
  165. var result = InitCamera(this);
  166. if (result == 0) this.IsInit = true;
  167. return result;
  168. }
  169. catch (Exception ex)
  170. {
  171. ExceptionLogEvent?.Invoke(ex, $"{index}号相机初始化", null, LogEnum.RunException);
  172. return -2;
  173. }
  174. }
  175. public bool DisPose()
  176. {
  177. try
  178. {
  179. Marshal.FreeCoTaskMem(capInfoStruct.Buffer);
  180. Marshal.FreeCoTaskMem(pDest);
  181. return true;
  182. }
  183. catch (Exception ex)
  184. {
  185. ExceptionLogEvent?.Invoke(ex, $"{index}号相机释放内存", null, LogEnum.RunException);
  186. return false;
  187. }
  188. }
  189. public int Usb2Start(IntPtr mControlPtr, int left, int top, int width, int height)
  190. {
  191. var nRetValue = MVCAPI.MV_Usb2Start(hImager, "MVC Camera Preview", MVCAPI.WS_CHILD | MVCAPI.WS_VISIBLE, left, top, width, height, mControlPtr, 0, (int)System.Threading.ThreadPriority.Highest, (int)System.Threading.ThreadPriority.Highest);
  192. return nRetValue;
  193. }
  194. public int Usb2Stop()
  195. {
  196. var nRetValue = MVCAPI.MV_Usb2Stop(hImager);
  197. return nRetValue;
  198. }
  199. public int Usb2StartCapture()
  200. {
  201. try
  202. {
  203. var nRetValue = MVCAPI.MV_Usb2StartCapture(hImager, true);
  204. return nRetValue;
  205. }
  206. catch (Exception)
  207. {
  208. return -1;
  209. }
  210. }
  211. public int Usb2StopCapture()
  212. {
  213. try
  214. {
  215. var nRetValue = MVCAPI.MV_Usb2StartCapture(hImager, false);
  216. return nRetValue;
  217. }
  218. catch (Exception)
  219. {
  220. return -1;
  221. }
  222. }
  223. /// <summary>
  224. /// 多个方法共同锁
  225. /// </summary>
  226. private static readonly object locker = new object();
  227. [HandleProcessCorruptedStateExceptions]
  228. [SecurityCritical]
  229. private int InitCamera(Camera camera)
  230. {
  231. try
  232. {
  233. int result = -1;
  234. lock (locker)
  235. {
  236. //MVC2000
  237. result = MVCAPI.MV_Usb2Init("MVC2000", out camera.index, ref camera.capInfoStruct, out camera.hImager);
  238. }
  239. return result;
  240. }
  241. catch (Exception ex)
  242. {
  243. ExceptionLogEvent?.Invoke(ex, $"{camera.index}号相机初始化", null, LogEnum.RunException);
  244. return -2;
  245. }
  246. }
  247. /// <summary>
  248. /// 卸载相机
  249. /// </summary>
  250. /// <returns></returns>
  251. public int UnInit()
  252. {
  253. try
  254. {
  255. this.IsInit = false;
  256. var result = UnInit(this);
  257. return result;
  258. }
  259. catch (Exception ex)
  260. {
  261. ExceptionLogEvent?.Invoke(ex, $"{index}号相机卸载", null, LogEnum.RunException);
  262. return -1;
  263. }
  264. }
  265. [HandleProcessCorruptedStateExceptions]
  266. [SecurityCritical]
  267. private int UnInit(Camera camera)
  268. {
  269. try
  270. {
  271. int result = -1;
  272. lock (locker)
  273. {
  274. result = MVCAPI.MV_Usb2Uninit(ref hImager);
  275. }
  276. return result;
  277. }
  278. catch (Exception ex)
  279. {
  280. ExceptionLogEvent?.Invoke(ex, $"{camera.index}号相机卸载", null, LogEnum.RunException);
  281. return -2;
  282. }
  283. }
  284. /// <summary>
  285. /// 设置摄像头的采集模式为连续采集模式
  286. /// </summary>
  287. /// <returns></returns>
  288. public int SetOpMode()
  289. {
  290. try
  291. {
  292. if (this.IsInit == false) return -1;
  293. var result = SetOpMode(this);
  294. this.IsStart = result == 0;
  295. return result;
  296. }
  297. catch (Exception ex)
  298. {
  299. ExceptionLogEvent?.Invoke(ex, $"{index}号相机设置采集模式", null, LogEnum.RunException);
  300. return -1;
  301. }
  302. }
  303. [HandleProcessCorruptedStateExceptions]
  304. [SecurityCritical]
  305. private int SetOpMode(Camera camera)
  306. {
  307. try
  308. {
  309. int result = -1;
  310. lock (locker)
  311. {
  312. result = MVCAPI.MV_Usb2SetOpMode(camera.hImager, 0, false);
  313. }
  314. return result;
  315. }
  316. catch (Exception ex)
  317. {
  318. ExceptionLogEvent?.Invoke(ex, $"{camera.index}号相机设置采集模式", null, LogEnum.RunException);
  319. return -2;
  320. }
  321. }
  322. /// <summary>
  323. /// 抓取一张图像
  324. /// </summary>
  325. /// <returns>返回该图字节数组</returns>
  326. public int GetRgbData()
  327. {
  328. try
  329. {
  330. if (this.IsStart == false) return -1;
  331. return GetRgbData(this);
  332. }
  333. catch (Exception ex)
  334. {
  335. ExceptionLogEvent?.Invoke(ex, $"{index}号相机抓图", null, LogEnum.RunException);
  336. return -2;
  337. }
  338. }
  339. [HandleProcessCorruptedStateExceptions]
  340. [SecurityCritical]
  341. private int GetRgbData(Camera camera)
  342. {
  343. try
  344. {
  345. int result = -1;
  346. lock (locker)
  347. {
  348. result = MVCAPI.MV_Usb2GetRgbData(camera.hImager, ref camera.capInfoStruct, camera.pDest);
  349. }
  350. return result;
  351. }
  352. catch (Exception ex)
  353. {
  354. ExceptionLogEvent?.Invoke(ex, $"{camera.index}号相机抓图", null, LogEnum.RunException);
  355. return -2;
  356. }
  357. }
  358. /// <summary>
  359. /// 抓取一张图像
  360. /// </summary>
  361. /// <returns>返回该图字节数组</returns>
  362. public int GetRawData()
  363. {
  364. if (this.IsStart == false) return -1;
  365. return GetRawData(this);
  366. }
  367. private int GetRawData(Camera camera)
  368. {
  369. try
  370. {
  371. int result = -1;
  372. lock (locker)
  373. {
  374. result = MVCAPI.MV_Usb2GetRawData(camera.hImager, ref camera.capInfoStruct);
  375. }
  376. return result;
  377. }
  378. catch (Exception ex)
  379. {
  380. ExceptionLogEvent?.Invoke(ex, $"{index}号相机抓图", null, LogEnum.RunException);
  381. return -2;
  382. }
  383. }
  384. public int GetCamNum()
  385. {
  386. try
  387. {
  388. if (this.IsStart == false) return -1;
  389. int nRetValue = -1;
  390. nRetValue = MVCAPI.MV_Usb2GetNumberDevicesEX(out camnums);
  391. if (nRetValue == 0) return camnums;
  392. ExceptionLogEvent?.Invoke(new Exception($"{index}号相机获取相机数量失败"), $"{index}号相机获取相机数量", null, LogEnum.RunException);
  393. return nRetValue;
  394. }
  395. catch (Exception ex)
  396. {
  397. ExceptionLogEvent?.Invoke(ex, $"{index}号相机获取相机数量", null, LogEnum.RunException);
  398. return -2;
  399. }
  400. }
  401. /// <summary>
  402. /// 抓取一张图像
  403. /// </summary>
  404. /// <returns>返回该图字节数组</returns>
  405. public int RawToRgb()
  406. {
  407. if (this.IsStart == false) return -1;
  408. return RawToRgb(this);
  409. }
  410. private int RawToRgb(Camera camera)
  411. {
  412. try
  413. {
  414. int result = -1;
  415. lock (locker)
  416. {
  417. result = MVCAPI.MV_Usb2ConvertRawToRgb(camera.hImager, camera.capInfoStruct.Buffer, camera.width, camera.height, camera.pDest);
  418. }
  419. return result;
  420. }
  421. catch (Exception ex)
  422. {
  423. ExceptionLogEvent?.Invoke(ex, $"{index}号相机RawToRgb", null, LogEnum.RunException);
  424. return -2;
  425. }
  426. }
  427. /// <summary>
  428. /// 设置相机参数
  429. /// </summary>
  430. /// <param name="model"></param>
  431. /// <returns></returns>
  432. public int SetPartOfCapInfo(int Exposure)
  433. {
  434. return SetPartOfCapInfo(this, Exposure);
  435. }
  436. [HandleProcessCorruptedStateExceptions]
  437. [SecurityCritical]
  438. public int SetPartOfCapInfo(Camera camera, int Exposure)
  439. {
  440. try
  441. {
  442. int result;
  443. capInfoStruct.Exposure = Exposure;
  444. //this.width = model.Width;
  445. //this.height = model.Height;
  446. //capInfoStruct.Gain[0] = Convert.ToByte(model.Red);
  447. //capInfoStruct.Gain[1] = Convert.ToByte(model.Green);
  448. //capInfoStruct.Gain[2] = Convert.ToByte(model.Blue);
  449. //capInfoStruct.HorizontalOffset = model.HorizontalOffset;
  450. //capInfoStruct.VerticalOffset = model.VerticalOffset;
  451. //capInfoStruct.Exposure = model.Exposure;
  452. //capInfoStruct.Width = this.width;
  453. //capInfoStruct.Height = this.height;
  454. //capInfoStruct.Buffer = Marshal.AllocCoTaskMem(this.width * this.height);
  455. //pDest = Marshal.AllocCoTaskMem(this.width * this.height * 3);
  456. lock (locker)
  457. {
  458. result = MVCAPI.MV_Usb2SetPartOfCapInfo(hImager, ref capInfoStruct);
  459. }
  460. return result;
  461. }
  462. catch (Exception ex)
  463. {
  464. ExceptionLogEvent?.Invoke(ex, $"{camera.index}号相机设置参数", null, LogEnum.RunException);
  465. return -2;
  466. }
  467. }
  468. /// <summary>
  469. /// 保存当前缓存中的原图
  470. /// </summary>
  471. /// <param name="fullName"></param>
  472. /// <returns></returns>
  473. public bool SaveBmpPic(string fullName)
  474. {
  475. bool result = false;
  476. try
  477. {
  478. //位图对象
  479. System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(
  480. this.width,
  481. this.height,
  482. System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  483. //图像数据
  484. System.Drawing.Imaging.BitmapData bmpData = bitmap.LockBits(
  485. new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
  486. System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat);
  487. Marshal.Copy(this.SourceBuffer, 0, bmpData.Scan0, this.SourceBuffer.Length);
  488. //解锁
  489. bitmap.UnlockBits(bmpData);
  490. //翻转
  491. bitmap.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipY);
  492. //保存
  493. bitmap.Save(fullName);
  494. result = true;
  495. }
  496. catch
  497. {
  498. return result;
  499. }
  500. return result;
  501. }
  502. public bool SaveJPG(string fullName)
  503. {
  504. MemoryStream memoryStream = null;
  505. FileStream fs = null;
  506. bool success = false;
  507. try
  508. {
  509. memoryStream = new MemoryStream(this.SourceBuffer);
  510. fs = new FileStream(fullName, FileMode.OpenOrCreate);
  511. memoryStream.WriteTo(fs);
  512. success = true;
  513. }
  514. catch (Exception ex)
  515. {
  516. success = false;
  517. }
  518. finally
  519. {
  520. if (fs != null)
  521. {
  522. fs.Close();
  523. fs.Dispose();
  524. }
  525. if (memoryStream != null)
  526. {
  527. memoryStream.Close();
  528. memoryStream.Dispose();
  529. }
  530. }
  531. return success;
  532. }
  533. public byte[] LastSourceBufferHash { get; set; }
  534. public void SavePreMem()
  535. {
  536. try
  537. {
  538. LastSourceBufferHash = GetHash(SourceBuffer);
  539. //var aa = SourceBuffer;
  540. //LastSourceBuffer = new byte[aa.Length];
  541. //Buffer.BlockCopy(aa, 0, LastSourceBuffer, 0, aa.Length);
  542. //HouseLogEvent?.Invoke(DateTime.Now, $"{index}号相机保存后的数据比较 [{aa.SequenceEqual(LastSourceBuffer)}]", LogEnum.HouseRunRecord);
  543. //HouseLogEvent?.Invoke(DateTime.Now, $"{index}号相机保存数据记录开始 [{ByteToHexStr(SaveRgbData)}]", LogEnum.HouseRunRecord);
  544. //SaveRgbData[0] = aa[0];
  545. //SaveRgbData[1] = aa[aa.Length / 2];
  546. //SaveRgbData[2] = aa[aa.Length - 1];
  547. //HouseLogEvent?.Invoke(DateTime.Now, $"{index}号相机保存数据记录结束 [{ByteToHexStr(SaveRgbData)}]", LogEnum.HouseRunRecord);
  548. }
  549. catch (Exception ex)
  550. {
  551. ExceptionLogEvent?.Invoke(ex, $"{index}号相机保存数据", null, LogEnum.RunException);
  552. }
  553. }
  554. public bool CheckRgbData()
  555. {
  556. try
  557. {
  558. //var aa = SourceBuffer;
  559. byte[] SourceBufferHash = GetHash(SourceBuffer);
  560. if (LastSourceBufferHash.SequenceEqual(SourceBufferHash))
  561. {
  562. return false;
  563. }
  564. LastSourceBufferHash = new byte[SourceBufferHash.Length];
  565. Buffer.BlockCopy(SourceBufferHash, 0, LastSourceBufferHash, 0, SourceBufferHash.Length);
  566. return true;
  567. //if (SourceBuffer.SequenceEqual(LastSourceBuffer))
  568. //{
  569. // return false;
  570. //}
  571. //return true;
  572. //var aa = SourceBuffer;
  573. //if (SaveRgbData[0] == aa[0] && SaveRgbData[1] == aa[aa.Length / 2] && SaveRgbData[2] == aa[aa.Length - 1])
  574. //{
  575. // return false;
  576. //}
  577. //return true;
  578. }
  579. catch (Exception ex)
  580. {
  581. ExceptionLogEvent?.Invoke(ex, $"{index}号相机校验拍照数据", null, LogEnum.RunException);
  582. return false;
  583. }
  584. }
  585. public string ByteToHexStr(byte[] bytes)
  586. {
  587. string returnStr = "";
  588. if (bytes != null)
  589. {
  590. for (int i = 0; i < bytes.Length; i++)
  591. {
  592. returnStr += bytes[i].ToString("X2") + " ";
  593. }
  594. }
  595. return returnStr;
  596. }
  597. public byte[] GetHash(byte[] bytes)
  598. {
  599. return SHA256.HashData(bytes);
  600. }
  601. }
  602. }