/********************************************************************************
** 类名称: 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();
}
}
}
}