/******************************************************************************** ** 类名称: CameraBl ** 描述 : 用于相机处理的业务类 ** 作者 : 丁书杰 ** 创建时间:2019/03/26 ** 版权所有 (C) :中科视语(北京)科技有限公司 *********************************************************************************/ using Jai_FactoryDotNET; using OpenCvSharp; using OS.Spin.Common; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Text; using System.Threading; //using TIS.Imaging; namespace OS.Spin.BusinessLayer.SubBusiness { public class CameraBl { #region 变量 /// /// 图像搜集完成 /// /// 相机编号 /// 搜集的图片 public delegate void EventRecivedImg(int cameraId, Modle.Sdk.StructInfos.DATA_IMAGE1 img); // 图像收集完成回调 public EventRecivedImg SendRecivedImg; // 三通道数据 private Mat _threeChannelsMat = null; // 相机编号 private int _cameraId = 0; // 单通道转三通道线程 private Thread _channelMerge; // 单通道数据 private Mat _cameraMat = null; private bool _channelMatOk = false; private const int CacheNo = 100; private bool _isDebug = true; private int SnapCount = 0; private int SavaCount = 0; //当前相机对象 CCamera myCamera = null; Stopwatch s; // ======= #endregion private string _directory = string.Empty; private int _imageId = 0; public CameraBl(int cId) { try { _cameraId = cId; _directory = Path.Combine(System.IO.Directory.GetCurrentDirectory(), string.Format(@"running\camera\{0}", cId)); _dry = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "test-temp"); if (Directory.Exists(_directory)) { Directory.Delete(_directory, true); } Directory.CreateDirectory(_directory); s = new Stopwatch(); if (_isDebug) { return; } // 相机参数及软触发配置 InitCamera(); LogisTrac.WriteLog(string.Format("相机{0}初始化", _cameraId)); } catch (Exception ex) { LogisTrac.WriteLog(string.Format("CameraBl:{0}", ex.Message)); } } public Mat ThreeChannelMat { get { while (!_channelMatOk) { Thread.Sleep(5); } return _threeChannelsMat; } } private CNode _gainNode; private CameraBl() { } private string _dry = @"D:\工作\WeiQ_Mianfang\WeiQ_Mianfang\OS.Spin\OS.Spin\bin\Debug\test-temp"; private List _flaws = new List() { "20200106174905495_{0}.jpg", "20200106174905495_{0}.jpg", "20200106174905495_{0}.jpg" }; private string _noFlaws = "20200106174905495_{0}.jpg"; //private string _noFlaws = "20181029094657_3_{0}ren.jpg"; /// /// 相机图像收集事件 /// /// /// private void MyCamera_NewImageDelegate(ref Jai_FactoryWrapper.ImageInfo ImageInfo) { try { LogisTrac.WriteInfoLog(String.Format("[拍照] 开始 ={0}======", _cameraId)); if (_isDebug) { var file = _noFlaws; //if (_imageId == 15) //{ // file = _flaws[0]; //} //if (_imageId == 43) //{ // file = _flaws[1]; //} //if (_imageId == 85) //{ // file = _flaws[2]; //} //if (_imageId == 115) //{ // file = _flaws[3]; //} //var f = string.Format(file, _cameraId); //string rF = Path.Combine(_dry, f); //_cameraMat = Cv2.ImRead(rF, ImreadModes.Unchanged); //byte[] cData = new byte[_cameraMat.Width * _cameraMat.Height * 3]; //OS.Spin.SdkLayer.SdkMyCode.Flaw_ReadImg(rF, cData); //_cameraMat = new Mat(_cameraMat.Height, _cameraMat.Width, MatType.CV_8UC3, cData); var f = string.Format(file, _cameraId); _cameraMat = Cv2.ImRead(Path.Combine(_dry, f), ImreadModes.Unchanged); } else { var realHeight = (int)ImageInfo.SizeY; var realWidth = (int)ImageInfo.SizeX; var _mat = ((new Mat(realHeight, realWidth, MatType.CV_8UC1, ImageInfo.ImageBuffer))); _cameraMat = new Mat(realHeight, realWidth, MatType.CV_8UC3).Clone(); Cv2.CvtColor(_mat, _cameraMat, ColorConversionCodes.BayerRG2RGB); //_mat.Release(); } _threeChannelsMat = _cameraMat.Clone(); _channelMerge = new Thread(new ParameterizedThreadStart(SingleChannel2ThreeChannels)); _channelMerge.Start(_imageId); s.Stop(); var t = s.ElapsedMilliseconds.ToString(); // 更新当前缓存图片Id OS.Spin.Running.Cache.GetInstance().CacheImgId = _imageId; _imageId++; //Cv2.Split(_cameraMat, out Mat[] mats); Modle.Sdk.StructInfos.DATA_IMAGE1 data = new Modle.Sdk.StructInfos.DATA_IMAGE1 { channel = 3, data = _cameraMat.Data, height = _cameraMat.Height, width = _cameraMat.Width }; SendRecivedImg(_cameraId, data); LogisTrac.WriteInfoLog(String.Format("[拍照] 结束 ={0}======", _cameraId)); //_cameraMat.Release(); } catch (Exception ex) { LogisTrac.WriteLog(string.Format("MyCamera_NewImageDelegate:{0}", ex.Message)); } } /// /// 单通道转三通道处理 /// /// 单通道数据 private void SingleChannel2ThreeChannels(object oId) { try { var id = (int)oId; if (!Directory.Exists(_directory)) { Directory.CreateDirectory(_directory); } _channelMatOk = false; //LogisTrac.WriteInfoLog(String.Format("[合图] 开始 ={0}======", id)); if (_threeChannelsMat.Height * _threeChannelsMat.Width == 0) { _threeChannelsMat = null; _channelMatOk = true; return; } var file = Path.Combine(_directory, string.Format("{0}.jpg", id)); Cv2.ImWrite(file, _threeChannelsMat); //图片缓存成功 SavaCount++; if (id >= CacheNo) { var oldFile = Path.Combine(_directory, string.Format("{0}.jpg", id - CacheNo)); // 判断旧图是否存在 if (File.Exists(oldFile)) { File.Delete(oldFile); } } //LogisTrac.WriteInfoLog(String.Format("[合图] 结束 ={0}======", id)); _channelMatOk = true; } catch (Exception ex) { LogisTrac.WriteLog(string.Format("SingleChannel2ThreeChannels:{0}", ex.Message)); } } /// /// bitmap 位图转为mat类型 /// /// /// private Mat Bitmap2Mat(Bitmap bitmap) { Mat source = null; MemoryStream s2_ms = null; try { using (s2_ms = new MemoryStream()) { bitmap.Save(s2_ms, ImageFormat.Bmp); source = Mat.FromStream(s2_ms, ImreadModes.AnyColor); } } catch (Exception ex) { LogisTrac.WriteLog(string.Format("Bitmap2Mat:{0}", ex.Message)); return null; } finally { if (s2_ms != null) { s2_ms.Close(); s2_ms = null; } GC.Collect(); } return source.Clone(); } /// /// 初始化相机 /// /// public void InitCamera() { try { Jai_FactoryWrapper.EFactoryError error = Jai_FactoryWrapper.EFactoryError.Success; myCamera = OS.Spin.Common.Camera.JaiCamera.GetInstance().GetCameraByChannel(_cameraId); LogisTrac.WriteInfoLog(String.Format("打开相机[{0}] ===========", _cameraId)); if (error == Jai_FactoryWrapper.EFactoryError.Success && null != myCamera) { LogisTrac.WriteInfoLog(String.Format("打开相机[{0}]成功 ===========", _cameraId)); SetFramegrabberPixelFormat(); myCamera.NewImageDelegate += MyCamera_NewImageDelegate; ; error = myCamera.Open(); if (error == Jai_FactoryWrapper.EFactoryError.Success) { if (myCamera.GetNode("TriggerSelector") != null) { myCamera.GetNode("TriggerSelector").Value = "FrameStart"; myCamera.GetNode("TriggerMode").Value = "Off"; } if (myCamera.GetNode("TriggerSelector") != null) { myCamera.GetNode("TriggerSelector").Value = "FrameStart"; myCamera.GetNode("TriggerMode").Value = "On"; myCamera.GetNode("TriggerSource").Value = "Software"; } else { myCamera.GetNode("ExposureMode").Value = "EdgePreSelect"; // Set Line Selector to "Camera Trigger 0" myCamera.GetNode("LineSelector").Value = "CameraTrigger0"; // Set Line Source to "Software Trigger 0" myCamera.GetNode("LineSource").Value = "SoftwareTrigger0"; // .. and finally set the Line Polarity (LineInverter) to "Active High" myCamera.GetNode("LineInverter").Value = "ActiveHigh"; } //SetFramegrabberValue("Gain", 2); myCamera.StartImageAcquisition(false, 1); } } } catch (Exception ex) { LogisTrac.WriteLog(string.Format("InitCamera:{0}", ex.Message)); } } private double _gainValue = -1; public void SetCameraCainValue(double gValue) { if (null == myCamera) { return; } try { SetFramegrabberValue("Gain", gValue); _gainValue = gValue; } catch (Exception ex) { LogisTrac.WriteLog(ex); } finally { //var time = 0; //while(myCamera.StartImageAcquisition(false, 1) == Jai_FactoryWrapper.EFactoryError.Error && time< 3) //{ // Thread.Sleep(1); // time++; //} } } /// /// 相机软触发 /// public void Trigger() { try { LogisTrac.WriteInfoLog(string.Format("Camera_{0}:{1}:{2}", _cameraId, SnapCount, SavaCount)); //拍照执行次数大于保存照片次数 if (SnapCount - SavaCount > 0) { LogisTrac.WriteInfoLog(string.Format("照片保存情况{0}:{1}", SnapCount, SavaCount)); LogisTrac.WriteLog(string.Format("相机{0}重启", _cameraId)); myCamera.Close(); myCamera.Dispose(); InitCamera(); SnapCount = 0; SavaCount = 0; } LogisTrac.WriteInfoLog(String.Format("[触发拍照] ====={0}======", _cameraId)); if (_isDebug) { Jai_FactoryWrapper.ImageInfo imageInfo = new Jai_FactoryWrapper.ImageInfo(); MyCamera_NewImageDelegate(ref imageInfo); SnapCount++; } else { if (null == myCamera) { return; } // But we have 2 ways of sending a software trigger: JAI and GenICam SNC // The GenICam SFNC software trigger is available if a node called // TriggerSoftware is available if (myCamera.GetNode("TriggerSoftware") != null) { myCamera.GetNode("TriggerSelector").Value = "FrameStart"; myCamera.GetNode("TriggerSoftware").ExecuteCommand(); } else { // We need to "pulse" the Software Trigger feature in order to trigger the camera! myCamera.GetNode("SoftwareTrigger0").Value = 0; myCamera.GetNode("SoftwareTrigger0").Value = 1; myCamera.GetNode("SoftwareTrigger0").Value = 0; } if (myCamera.GetNode("TriggerSoftware") != null) { myCamera.GetNode("TriggerSelector").Value = "FrameStart"; myCamera.GetNode("TriggerSoftware").ExecuteCommand(); } else { // We need to "pulse" the Software Trigger feature in order to trigger the camera! myCamera.GetNode("SoftwareTrigger0").Value = 0; myCamera.GetNode("SoftwareTrigger0").Value = 1; myCamera.GetNode("SoftwareTrigger0").Value = 0; } //调用相机触发拍照 SnapCount++; s.Start(); } } catch (Exception ex) { LogisTrac.WriteLog(string.Format("Trigger:{0}", ex.Message)); } } /// /// 根据节点名称设置属性 /// /// /// private void SetFramegrabberValue(String nodeName, Int64 int64Val) { try { if (null == myCamera || int64Val == _gainValue) { return; } IntPtr hDevice = IntPtr.Zero; Jai_FactoryWrapper.EFactoryError error = Jai_FactoryWrapper.J_Camera_GetLocalDeviceHandle(myCamera.CameraHandle, ref hDevice); if (Jai_FactoryWrapper.EFactoryError.Success != error) { return; } if (IntPtr.Zero == hDevice) { return; } IntPtr hNode; error = Jai_FactoryWrapper.J_Camera_GetNodeByName(hDevice, nodeName, out hNode); if (Jai_FactoryWrapper.EFactoryError.Success != error) { return; } if (IntPtr.Zero == hNode) { return; } myCamera.GetNode("Gain").Value = int64Val; //error = Jai_FactoryWrapper.J_Node_SetValueInt64(hNode, false, int64Val); //if (Jai_FactoryWrapper.EFactoryError.Success != error) //{ // return; //} //Special handling for Active Silicon CXP boards, which also has nodes prefixed //with "Incoming": if ("Width" == nodeName || "Height" == nodeName) { string strIncoming = "Incoming" + nodeName; IntPtr hNodeIncoming; error = Jai_FactoryWrapper.J_Camera_GetNodeByName(hDevice, strIncoming, out hNodeIncoming); if (Jai_FactoryWrapper.EFactoryError.Success != error) { return; } if (IntPtr.Zero == hNodeIncoming) { return; } error = Jai_FactoryWrapper.J_Node_SetValueInt64(hNodeIncoming, false, int64Val); } } catch (Exception ex) { LogisTrac.WriteLog(string.Format("SetFramegrabberValue(String nodeName, Int64 int64Val):{0}", ex.Message)); } } /// /// 设置增益值 /// /// /// private void SetFramegrabberValue(String nodeName, double doubleVal) { if (null == myCamera) { return; } try { if (null != myCamera.GetNode("Gain")) { myCamera.GetNode("Gain").Value = doubleVal; } } catch (Exception) { try { var gainRaw = myCamera.GetNode("Gain"); if (null != gainRaw) { gainRaw.Value = doubleVal; } } catch (Exception ex) { LogisTrac.WriteInfoLog(String.Format("[增益设置失败] ====={0}======", ex.Message)); return; } LogisTrac.WriteInfoLog(String.Format("[Gain增益写入] =====[{0}]======", doubleVal)); } LogisTrac.WriteInfoLog(String.Format("[增益写入] =====[{0}]======", doubleVal)); return; //Special handling for Active Silicon CXP boards, which also has nodes prefixed //with "Incoming": //if ("Width" == nodeName || "Height" == nodeName) //{ // string strIncoming = "Incoming" + nodeName; // IntPtr hNodeIncoming; // error = Jai_FactoryWrapper.J_Camera_GetNodeByName(hDevice, strIncoming, out hNodeIncoming); // if (Jai_FactoryWrapper.EFactoryError.Success != error) // { // return; // } // if (IntPtr.Zero == hNodeIncoming) // { // return; // } // error = Jai_FactoryWrapper.J_Node_SetValueDouble(hNodeIncoming, false, doubleVal); //} } private void SetFramegrabberPixelFormat() { try { String nodeName = "PixelFormat"; if (null == myCamera) { return; } IntPtr hDevice = IntPtr.Zero; Jai_FactoryWrapper.EFactoryError error = Jai_FactoryWrapper.J_Camera_GetLocalDeviceHandle(myCamera.CameraHandle, ref hDevice); if (Jai_FactoryWrapper.EFactoryError.Success != error) { return; } if (IntPtr.Zero == hDevice) { return; } long pf = 0; error = Jai_FactoryWrapper.J_Camera_GetValueInt64(myCamera.CameraHandle, nodeName, ref pf); if (Jai_FactoryWrapper.EFactoryError.Success != error) { return; } UInt64 pixelFormat = (UInt64)pf; UInt64 jaiPixelFormat = 0; error = Jai_FactoryWrapper.J_Image_Get_PixelFormat(myCamera.CameraHandle, pixelFormat, ref jaiPixelFormat); if (Jai_FactoryWrapper.EFactoryError.Success != error) { return; } StringBuilder sbJaiPixelFormatName = new StringBuilder(512); uint iSize = (uint)sbJaiPixelFormatName.Capacity; error = Jai_FactoryWrapper.J_Image_Get_PixelFormatName(myCamera.CameraHandle, jaiPixelFormat, sbJaiPixelFormatName, iSize); if (Jai_FactoryWrapper.EFactoryError.Success != error) { return; } IntPtr hNode; error = Jai_FactoryWrapper.J_Camera_GetNodeByName(hDevice, nodeName, out hNode); if (Jai_FactoryWrapper.EFactoryError.Success != error) { return; } if (IntPtr.Zero == hNode) { return; } error = Jai_FactoryWrapper.J_Node_SetValueString(hNode, false, sbJaiPixelFormatName.ToString()); if (Jai_FactoryWrapper.EFactoryError.Success != error) { return; } //Special handling for Active Silicon CXP boards, which also has nodes prefixed //with "Incoming": string strIncoming = "Incoming" + nodeName; IntPtr hNodeIncoming; error = Jai_FactoryWrapper.J_Camera_GetNodeByName(hDevice, strIncoming, out hNodeIncoming); if (Jai_FactoryWrapper.EFactoryError.Success != error) { return; } if (IntPtr.Zero == hNodeIncoming) { return; } error = Jai_FactoryWrapper.J_Node_SetValueString(hNodeIncoming, false, sbJaiPixelFormatName.ToString()); } catch (Exception ex) { LogisTrac.WriteLog(string.Format("SetFramegrabberPixelFormat:{0}", ex.Message)); } } /// /// 释放相机资源 /// public void Dispose() { if (myCamera != null) { myCamera.StopImageAcquisition(); } if (null != _channelMerge && _channelMerge.IsAlive) { _channelMerge.Abort(); } } } }