Camera.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  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. // D1-10:相机初始化边界审计埋点(module=相机)。全 try 兜底,镜像 operate 死栈同款 P3b。
  168. try
  169. {
  170. Aivfo.OperationLog.OperationLogger.Log("相机", "初始化",
  171. input: new { index, width, height, exposure },
  172. output: new { result },
  173. result: result == 0 ? "成功" : "失败",
  174. error: result == 0 ? null : $"InitCamera 返回 {result}");
  175. }
  176. catch { }
  177. return result;
  178. }
  179. catch (Exception ex)
  180. {
  181. ExceptionLogEvent?.Invoke(ex, $"{index}号相机初始化", null, LogEnum.RunException);
  182. return -2;
  183. }
  184. }
  185. public bool DisPose()
  186. {
  187. try
  188. {
  189. Marshal.FreeCoTaskMem(capInfoStruct.Buffer);
  190. Marshal.FreeCoTaskMem(pDest);
  191. return true;
  192. }
  193. catch (Exception ex)
  194. {
  195. ExceptionLogEvent?.Invoke(ex, $"{index}号相机释放内存", null, LogEnum.RunException);
  196. return false;
  197. }
  198. }
  199. public int Usb2Start(IntPtr mControlPtr, int left, int top, int width, int height)
  200. {
  201. 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);
  202. return nRetValue;
  203. }
  204. public int Usb2Stop()
  205. {
  206. var nRetValue = MVCAPI.MV_Usb2Stop(hImager);
  207. return nRetValue;
  208. }
  209. public int Usb2StartCapture()
  210. {
  211. try
  212. {
  213. var nRetValue = MVCAPI.MV_Usb2StartCapture(hImager, true);
  214. return nRetValue;
  215. }
  216. catch (Exception)
  217. {
  218. return -1;
  219. }
  220. }
  221. public int Usb2StopCapture()
  222. {
  223. try
  224. {
  225. var nRetValue = MVCAPI.MV_Usb2StartCapture(hImager, false);
  226. return nRetValue;
  227. }
  228. catch (Exception)
  229. {
  230. return -1;
  231. }
  232. }
  233. /// <summary>
  234. /// 多个方法共同锁
  235. /// </summary>
  236. private static readonly object locker = new object();
  237. [HandleProcessCorruptedStateExceptions]
  238. [SecurityCritical]
  239. private int InitCamera(Camera camera)
  240. {
  241. try
  242. {
  243. int result = -1;
  244. lock (locker)
  245. {
  246. //MVC2000
  247. result = MVCAPI.MV_Usb2Init("MVC2000", out camera.index, ref camera.capInfoStruct, out camera.hImager);
  248. }
  249. return result;
  250. }
  251. catch (Exception ex)
  252. {
  253. ExceptionLogEvent?.Invoke(ex, $"{camera.index}号相机初始化", null, LogEnum.RunException);
  254. return -2;
  255. }
  256. }
  257. /// <summary>
  258. /// 卸载相机
  259. /// </summary>
  260. /// <returns></returns>
  261. public int UnInit()
  262. {
  263. try
  264. {
  265. this.IsInit = false;
  266. var result = UnInit(this);
  267. // D1-10:相机卸载边界审计埋点(module=相机)。全 try 兜底。
  268. try
  269. {
  270. Aivfo.OperationLog.OperationLogger.Log("相机", "卸载",
  271. input: new { index },
  272. output: new { result },
  273. result: result == 0 ? "成功" : "失败");
  274. }
  275. catch { }
  276. return result;
  277. }
  278. catch (Exception ex)
  279. {
  280. ExceptionLogEvent?.Invoke(ex, $"{index}号相机卸载", null, LogEnum.RunException);
  281. return -1;
  282. }
  283. }
  284. [HandleProcessCorruptedStateExceptions]
  285. [SecurityCritical]
  286. private int UnInit(Camera camera)
  287. {
  288. try
  289. {
  290. int result = -1;
  291. lock (locker)
  292. {
  293. result = MVCAPI.MV_Usb2Uninit(ref hImager);
  294. }
  295. return result;
  296. }
  297. catch (Exception ex)
  298. {
  299. ExceptionLogEvent?.Invoke(ex, $"{camera.index}号相机卸载", null, LogEnum.RunException);
  300. return -2;
  301. }
  302. }
  303. /// <summary>
  304. /// 设置摄像头的采集模式为连续采集模式
  305. /// </summary>
  306. /// <returns></returns>
  307. public int SetOpMode()
  308. {
  309. try
  310. {
  311. if (this.IsInit == false) return -1;
  312. var result = SetOpMode(this);
  313. this.IsStart = result == 0;
  314. return result;
  315. }
  316. catch (Exception ex)
  317. {
  318. ExceptionLogEvent?.Invoke(ex, $"{index}号相机设置采集模式", null, LogEnum.RunException);
  319. return -1;
  320. }
  321. }
  322. [HandleProcessCorruptedStateExceptions]
  323. [SecurityCritical]
  324. private int SetOpMode(Camera camera)
  325. {
  326. try
  327. {
  328. int result = -1;
  329. lock (locker)
  330. {
  331. result = MVCAPI.MV_Usb2SetOpMode(camera.hImager, 0, false);
  332. }
  333. return result;
  334. }
  335. catch (Exception ex)
  336. {
  337. ExceptionLogEvent?.Invoke(ex, $"{camera.index}号相机设置采集模式", null, LogEnum.RunException);
  338. return -2;
  339. }
  340. }
  341. /// <summary>
  342. /// 抓取一张图像
  343. /// </summary>
  344. /// <returns>返回该图字节数组</returns>
  345. public int GetRgbData()
  346. {
  347. try
  348. {
  349. if (this.IsStart == false) return -1;
  350. return GetRgbData(this);
  351. }
  352. catch (Exception ex)
  353. {
  354. ExceptionLogEvent?.Invoke(ex, $"{index}号相机抓图", null, LogEnum.RunException);
  355. return -2;
  356. }
  357. }
  358. [HandleProcessCorruptedStateExceptions]
  359. [SecurityCritical]
  360. private int GetRgbData(Camera camera)
  361. {
  362. try
  363. {
  364. int result = -1;
  365. lock (locker)
  366. {
  367. result = MVCAPI.MV_Usb2GetRgbData(camera.hImager, ref camera.capInfoStruct, camera.pDest);
  368. }
  369. return result;
  370. }
  371. catch (Exception ex)
  372. {
  373. ExceptionLogEvent?.Invoke(ex, $"{camera.index}号相机抓图", null, LogEnum.RunException);
  374. return -2;
  375. }
  376. }
  377. /// <summary>
  378. /// 抓取一张图像
  379. /// </summary>
  380. /// <returns>返回该图字节数组</returns>
  381. public int GetRawData()
  382. {
  383. if (this.IsStart == false) return -1;
  384. return GetRawData(this);
  385. }
  386. private int GetRawData(Camera camera)
  387. {
  388. try
  389. {
  390. int result = -1;
  391. lock (locker)
  392. {
  393. result = MVCAPI.MV_Usb2GetRawData(camera.hImager, ref camera.capInfoStruct);
  394. }
  395. return result;
  396. }
  397. catch (Exception ex)
  398. {
  399. ExceptionLogEvent?.Invoke(ex, $"{index}号相机抓图", null, LogEnum.RunException);
  400. return -2;
  401. }
  402. }
  403. public int GetCamNum()
  404. {
  405. try
  406. {
  407. if (this.IsStart == false) return -1;
  408. int nRetValue = -1;
  409. nRetValue = MVCAPI.MV_Usb2GetNumberDevicesEX(out camnums);
  410. if (nRetValue == 0) return camnums;
  411. ExceptionLogEvent?.Invoke(new Exception($"{index}号相机获取相机数量失败"), $"{index}号相机获取相机数量", null, LogEnum.RunException);
  412. return nRetValue;
  413. }
  414. catch (Exception ex)
  415. {
  416. ExceptionLogEvent?.Invoke(ex, $"{index}号相机获取相机数量", null, LogEnum.RunException);
  417. return -2;
  418. }
  419. }
  420. /// <summary>
  421. /// 抓取一张图像
  422. /// </summary>
  423. /// <returns>返回该图字节数组</returns>
  424. public int RawToRgb()
  425. {
  426. if (this.IsStart == false) return -1;
  427. return RawToRgb(this);
  428. }
  429. private int RawToRgb(Camera camera)
  430. {
  431. try
  432. {
  433. int result = -1;
  434. lock (locker)
  435. {
  436. result = MVCAPI.MV_Usb2ConvertRawToRgb(camera.hImager, camera.capInfoStruct.Buffer, camera.width, camera.height, camera.pDest);
  437. }
  438. return result;
  439. }
  440. catch (Exception ex)
  441. {
  442. ExceptionLogEvent?.Invoke(ex, $"{index}号相机RawToRgb", null, LogEnum.RunException);
  443. return -2;
  444. }
  445. }
  446. /// <summary>
  447. /// 设置相机参数
  448. /// </summary>
  449. /// <param name="model"></param>
  450. /// <returns></returns>
  451. public int SetPartOfCapInfo(int Exposure)
  452. {
  453. return SetPartOfCapInfo(this, Exposure);
  454. }
  455. [HandleProcessCorruptedStateExceptions]
  456. [SecurityCritical]
  457. public int SetPartOfCapInfo(Camera camera, int Exposure)
  458. {
  459. try
  460. {
  461. int result;
  462. capInfoStruct.Exposure = Exposure;
  463. //this.width = model.Width;
  464. //this.height = model.Height;
  465. //capInfoStruct.Gain[0] = Convert.ToByte(model.Red);
  466. //capInfoStruct.Gain[1] = Convert.ToByte(model.Green);
  467. //capInfoStruct.Gain[2] = Convert.ToByte(model.Blue);
  468. //capInfoStruct.HorizontalOffset = model.HorizontalOffset;
  469. //capInfoStruct.VerticalOffset = model.VerticalOffset;
  470. //capInfoStruct.Exposure = model.Exposure;
  471. //capInfoStruct.Width = this.width;
  472. //capInfoStruct.Height = this.height;
  473. //capInfoStruct.Buffer = Marshal.AllocCoTaskMem(this.width * this.height);
  474. //pDest = Marshal.AllocCoTaskMem(this.width * this.height * 3);
  475. lock (locker)
  476. {
  477. result = MVCAPI.MV_Usb2SetPartOfCapInfo(hImager, ref capInfoStruct);
  478. }
  479. return result;
  480. }
  481. catch (Exception ex)
  482. {
  483. ExceptionLogEvent?.Invoke(ex, $"{camera.index}号相机设置参数", null, LogEnum.RunException);
  484. return -2;
  485. }
  486. }
  487. /// <summary>
  488. /// 保存当前缓存中的原图
  489. /// </summary>
  490. /// <param name="fullName"></param>
  491. /// <returns></returns>
  492. public bool SaveBmpPic(string fullName)
  493. {
  494. bool result = false;
  495. try
  496. {
  497. //位图对象
  498. System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(
  499. this.width,
  500. this.height,
  501. System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  502. //图像数据
  503. System.Drawing.Imaging.BitmapData bmpData = bitmap.LockBits(
  504. new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
  505. System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat);
  506. Marshal.Copy(this.SourceBuffer, 0, bmpData.Scan0, this.SourceBuffer.Length);
  507. //解锁
  508. bitmap.UnlockBits(bmpData);
  509. //翻转
  510. bitmap.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipY);
  511. //保存
  512. bitmap.Save(fullName);
  513. result = true;
  514. }
  515. catch
  516. {
  517. return result;
  518. }
  519. return result;
  520. }
  521. public bool SaveJPG(string fullName)
  522. {
  523. MemoryStream memoryStream = null;
  524. FileStream fs = null;
  525. bool success = false;
  526. try
  527. {
  528. memoryStream = new MemoryStream(this.SourceBuffer);
  529. fs = new FileStream(fullName, FileMode.OpenOrCreate);
  530. memoryStream.WriteTo(fs);
  531. success = true;
  532. }
  533. catch (Exception ex)
  534. {
  535. success = false;
  536. }
  537. finally
  538. {
  539. if (fs != null)
  540. {
  541. fs.Close();
  542. fs.Dispose();
  543. }
  544. if (memoryStream != null)
  545. {
  546. memoryStream.Close();
  547. memoryStream.Dispose();
  548. }
  549. }
  550. return success;
  551. }
  552. public byte[] LastSourceBufferHash { get; set; }
  553. public void SavePreMem()
  554. {
  555. try
  556. {
  557. LastSourceBufferHash = GetHash(SourceBuffer);
  558. //var aa = SourceBuffer;
  559. //LastSourceBuffer = new byte[aa.Length];
  560. //Buffer.BlockCopy(aa, 0, LastSourceBuffer, 0, aa.Length);
  561. //HouseLogEvent?.Invoke(DateTime.Now, $"{index}号相机保存后的数据比较 [{aa.SequenceEqual(LastSourceBuffer)}]", LogEnum.HouseRunRecord);
  562. //HouseLogEvent?.Invoke(DateTime.Now, $"{index}号相机保存数据记录开始 [{ByteToHexStr(SaveRgbData)}]", LogEnum.HouseRunRecord);
  563. //SaveRgbData[0] = aa[0];
  564. //SaveRgbData[1] = aa[aa.Length / 2];
  565. //SaveRgbData[2] = aa[aa.Length - 1];
  566. //HouseLogEvent?.Invoke(DateTime.Now, $"{index}号相机保存数据记录结束 [{ByteToHexStr(SaveRgbData)}]", LogEnum.HouseRunRecord);
  567. }
  568. catch (Exception ex)
  569. {
  570. ExceptionLogEvent?.Invoke(ex, $"{index}号相机保存数据", null, LogEnum.RunException);
  571. }
  572. }
  573. public bool CheckRgbData()
  574. {
  575. try
  576. {
  577. //var aa = SourceBuffer;
  578. byte[] SourceBufferHash = GetHash(SourceBuffer);
  579. if (LastSourceBufferHash.SequenceEqual(SourceBufferHash))
  580. {
  581. return false;
  582. }
  583. LastSourceBufferHash = new byte[SourceBufferHash.Length];
  584. Buffer.BlockCopy(SourceBufferHash, 0, LastSourceBufferHash, 0, SourceBufferHash.Length);
  585. return true;
  586. //if (SourceBuffer.SequenceEqual(LastSourceBuffer))
  587. //{
  588. // return false;
  589. //}
  590. //return true;
  591. //var aa = SourceBuffer;
  592. //if (SaveRgbData[0] == aa[0] && SaveRgbData[1] == aa[aa.Length / 2] && SaveRgbData[2] == aa[aa.Length - 1])
  593. //{
  594. // return false;
  595. //}
  596. //return true;
  597. }
  598. catch (Exception ex)
  599. {
  600. ExceptionLogEvent?.Invoke(ex, $"{index}号相机校验拍照数据", null, LogEnum.RunException);
  601. return false;
  602. }
  603. }
  604. public string ByteToHexStr(byte[] bytes)
  605. {
  606. string returnStr = "";
  607. if (bytes != null)
  608. {
  609. for (int i = 0; i < bytes.Length; i++)
  610. {
  611. returnStr += bytes[i].ToString("X2") + " ";
  612. }
  613. }
  614. return returnStr;
  615. }
  616. public byte[] GetHash(byte[] bytes)
  617. {
  618. return SHA256.HashData(bytes);
  619. }
  620. }
  621. }