Files
atvstdla dc66158497 Add QRValidation project to repository
- Added QRValidation vision control system
- Includes CapCleaningControl UI components
- WebSocket-based barcode validation system
- Support for Crevis PLC integration
- Test projects for PLC emulator, motion, IO panel, and Modbus

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-02 11:38:38 +09:00

1143 lines
45 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Management;
using System.Data.SqlClient;
using System.Data;
using System.Threading.Tasks;
using System.Net.NetworkInformation;
using System.Windows.Forms;
using System.Net;
using WatsonWebsocket;
using System.Runtime.CompilerServices;
using System.Threading;
using Euresys.Open_eVision_22_12;
using Crevis.VirtualFG40Library;
using AR;
namespace Project
{
public enum eTarget
{
Left = 0,
Right,
None = 9,
}
public enum remotelist
{
barcodeupdate,
}
public class remoteargs : EventArgs
{
public string strdata { get; set; }
public int CamIdx { get; set; }
public remotelist Command { get; set; }
public remoteargs(remotelist _cmd, int _camidx, string _strdata)
{
this.strdata = _strdata;
this.CamIdx = _camidx;
this.Command = _cmd;
}
}
public static class PUB
{
public static Class.WebSocket[] wsock_ = new Class.WebSocket[2];
public static AR.Log[] log_ = new AR.Log[2];
public static DateTime LastInputTime = DateTime.Now;
public static CSetting setting;
public static Boolean VisionLicense;
public static DateTime parsetime = DateTime.Now;
public static Flag flag;
public static bool[] DetectReel = new bool[] { false, false };
public static bool[] DetectConv = new bool[] { false, false };
public static int[] DetectReelValue = new int[] { 0, 0 };
public static int[] DetectConvValue = new int[] { 0, 0 };
public static double[] ProcessTime = new double[] { 0, 0 };
public static string[] lastguid = new string[] { string.Empty, string.Empty };
public static string[] lastdata = new string[] { string.Empty, string.Empty };
public static string[] lastcmd = new string[] { string.Empty, string.Empty };
public static string[] lastip = new string[] { string.Empty, string.Empty };
public static DateTime[] lastsend = new DateTime[] { DateTime.Now, DateTime.Now };
public static DateTime[] lastsendStatus = new DateTime[] { DateTime.Now, DateTime.Now };
public static Stack<string> imgque = new Stack<string>();
public static Boolean[] _isCrevisOpen = new bool[] { false, false, false };
public static Boolean[] _isCrevisACQ = new bool[] { false, false, false };
public static bool[] IsLive = new bool[] { false, false };
public static eTarget GetTarget(int camidx)
{
if (camidx < 0 || camidx > 900) return eTarget.None;
if (camidx == PUB.setting.CameraIndexL) return eTarget.Left;
else if (camidx == PUB.setting.CameraIndexR && camidx != PUB.setting.CameraIndexL) return eTarget.Right;
else return eTarget.None;
}
// public static System.Windows.Forms.Panel pIvLeft, pIvRight;
public static event EventHandler<remoteargs> RemoteCommand;
public static void RaiseRemoteCommand(remotelist cmd, int camidx, string data)
{
RemoteCommand?.Invoke(null, new remoteargs(cmd, camidx, data));
}
public static void initCore()
{
//setting
setting = new CSetting();
setting.Load();
//log
log_[0] = new AR.Log();
log_[0].FileNameFormat = "{yyyyMMdd}_L";
log_[0].TimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
log_[1] = new AR.Log();
log_[1].FileNameFormat = "{yyyyMMdd}_R";
log_[1].TimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
flag = new Flag();
}
public static void LogFlush()
{
PUB.log_[0].Flush();
PUB.log_[1].Flush();
}
public static string GetStackTraceInfo(
[CallerFilePath] string filenpath = null,
[CallerLineNumber] int linenumer = -1,
[CallerMemberName] string callMember = null)
{
var stackFrame = new System.Diagnostics.StackTrace(1).GetFrame(1);
string fileName = stackFrame.GetFileName();
if (fileName.isEmpty()) fileName = filenpath;
string methodName = stackFrame.GetMethod().ToString();
if (methodName.isEmpty()) methodName = callMember;
int lineNumber = stackFrame.GetFileLineNumber();
if (linenumer != -1) lineNumber = linenumer;
var TraceInfo = stackFrame.ToString();
return $"File:{fileName},Line:{lineNumber}\nMethod:{methodName}\n{TraceInfo}";
}
public static Dictionary<string, string> ComputerInfo()
{
string ip = "";
string mac = "";
// string prgmName = Application.ProductName;
var nif = NetworkInterface.GetAllNetworkInterfaces();
var host = Dns.GetHostEntry(Dns.GetHostName());
string fullname = System.Net.Dns.GetHostEntry("").HostName;
foreach (IPAddress r in host.AddressList)
{
string str = r.ToString();
if (str != "" && str.Substring(0, 3) == "10.")
{
ip = str;
break;
}
}
string rtn = string.Empty;
ObjectQuery oq = new System.Management.ObjectQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled='TRUE'");
ManagementObjectSearcher query1 = new ManagementObjectSearcher(oq);
foreach (ManagementObject mo in query1.Get())
{
string[] address = (string[])mo["IPAddress"];
if (address[0] == ip && mo["MACAddress"] != null)
{
mac = mo["MACAddress"].ToString();
break;
}
}
var username = System.Environment.UserName;
var retval = new Dictionary<string, string>();
retval.Add("IP", ip);
retval.Add("MAC", mac);
retval.Add("USER", username);
retval.Add("HOST", fullname);
return retval;
}
public static Rectangle GetVisionOrientSearchArea(
Rectangle baserect,
int offsetX,
int offsetY,
out string VisionOrientMessage)
{
VisionOrientMessage = "";
var newORectW = baserect.Width + offsetX;
var newORectH = baserect.Height + offsetY;
var newORectX = baserect.X - ((newORectW - baserect.Width) / 2.0);
var newORectY = baserect.Y - ((newORectH - baserect.Height) / 2.0);
if (newORectX < 1)
{
newORectW += (int)newORectY;
newORectX = 1;
}
if (newORectY < 1)
{
newORectH += (int)newORectY;
newORectY = 1;
}
if (newORectW < 4) newORectW = 0;
if (newORectH < 4) newORectH = 0;
var newORect = new Rectangle((int)newORectX, (int)newORectY, (int)newORectW, (int)newORectH);
if (newORect.Width < 1 || newORect.Height < 1)
{
VisionOrientMessage = string.Format("Reference area size error({0},{1},{2},{3})", newORect.Left, newORect.Top, newORect.Width, newORect.Height);
return Rectangle.Empty;
}
else return newORect;
}
public static double GetFreeSpace(string driveletter)
{
try
{
var di = new System.IO.DriveInfo(driveletter);
var freespace = di.TotalFreeSpace;
var totalspace = di.TotalSize;
var freeSpaceRate = (freespace * 1.0 / totalspace) * 100.0;
return freeSpaceRate;
}
catch
{
return 100.0;
}
}
public static string getSavePath(out double freespace)
{
Boolean path1Exist = false;
double freespace1 = 100.0;
string savePath1 = "";
freespace = 100.0;
savePath1 = System.IO.Path.Combine(PUB.setting.Path_Data, "Images");
if (savePath1 != "" && System.IO.Directory.Exists(savePath1))
{
path1Exist = true;
//이폴더를 사용
if (savePath1.StartsWith("\\")) return savePath1;
//남은잔량을 체크한다.
return savePath1;
}
if (path1Exist)
{
freespace = freespace1;
return savePath1;
}
//이제 문제가 좀 심각? (폴더가 없다)
var savePath = System.IO.Path.Combine(Util.CurrentPath, "Images");
if (System.IO.Directory.Exists(savePath) == false)
System.IO.Directory.CreateDirectory(savePath);
freespace = GetFreeSpace(savePath.Substring(0, 1));
return savePath;
}
public static double ChangeValuePopup(double value, string title)
{
var f = AR.UTIL.InputBox(title, value.ToString());
if (f.Item1)
{
var val = double.Parse(f.Item2);
return val;
}
else return value;
}
public static VirtualFG40Library _virtualFG40;
public static DateTime[] _CrevisRunTime = new DateTime[] { DateTime.Now, DateTime.Now };
public static DateTime[] _CrevisGrabTime = new DateTime[] { DateTime.Now, DateTime.Now };
static System.Threading.ManualResetEvent[] mre_grab = new System.Threading.ManualResetEvent[] {
new System.Threading.ManualResetEvent(true),
new System.Threading.ManualResetEvent(true)
};
public static EImageBW8[] OrgImage = new EImageBW8[] { null, null };
public static Int32[] _hDevice = new Int32[] { -1, -1 };
public static Int32[] _width = new Int32[] { 0, 0, 0 };
public static Int32[] _height = new Int32[] { 0, 0, 0 };
public static Int32[] _stride = new Int32[] { 0, 0, 0 };
public static Int32[] _bufferSize = new Int32[] { 0, 0, 0 };
public static IntPtr[] camPtr = new IntPtr[] { IntPtr.Zero, IntPtr.Zero };
public static bool[] IsProcess = new bool[] { false, false };
/// <summary>
/// 카메라버퍼에서 이미지를 읽는다
/// </summary>
/// <param name="camIdx"></param>
/// <param name="DisplayImage"></param>
/// <returns></returns>
public static Boolean CrevisGrab(int camIdx, Boolean DisplayImage, Panel Piv)
{
// 1. Excute Acquisition Start command
// 2. Grab Image using GrabImage
// 3. Image Display
// 4. Excute Acquisition Stop command
var camTarget = PUB.GetTarget(camIdx);// = eTarget.Left ? PUB.setting.CameraIndexL : PUB.setting.CameraIndexR;
if (camTarget == eTarget.None) return false;
var logIdx = camTarget == eTarget.Left ? 0 : 1;
//작업가능여부확인
if (mre_grab[camIdx].WaitOne(100) == false) return false;
//너무빨리 실행되지 않게 한다
var ts = DateTime.Now - _CrevisGrabTime[camIdx];
var fpsterm = (int)(1000f / 12f);
if (ts.TotalMilliseconds < fpsterm)
{
System.Threading.Thread.Sleep((int)(fpsterm - ts.TotalMilliseconds));
return false;
}
_CrevisGrabTime[camIdx] = DateTime.Now;
Int32 status = VirtualFG40Library.MCAM_ERR_SUCCESS;
try
{
mre_grab[camIdx].Reset();
//데이터수집확인
if (PUB._isCrevisACQ[camIdx] == false)
{
// Acqusition Start
status = _virtualFG40.AcqStart(_hDevice[camIdx]);
if (status == VirtualFG40Library.MCAM_ERR_RESOURCE_IN_USE)
{
if (_hDevice[camIdx] > 0)
_virtualFG40.AcqStop(_hDevice[camIdx]);
PUB._isCrevisACQ[camIdx] = false;
}
else if (status != VirtualFG40Library.MCAM_ERR_SUCCESS)
{
PUB.log_[logIdx].AddE(String.Format("Camera ACQ failed : {0}", status));
if (_hDevice[camIdx] > 0) _virtualFG40.AcqStop(_hDevice[camIdx]); //실패하면 멈춘다
PUB._isCrevisACQ[camIdx] = false;
}
else
{
PUB._isCrevisACQ[camIdx] = true;
PUB.log_[logIdx].AddI("Camera ACQ start");
}
//이미지수집에 실패했다면 진행하지 않는다.
if (PUB._isCrevisACQ[camIdx] == false) return false;
}
//이미지 수집
status = _virtualFG40.GrabImage(_hDevice[camIdx], camPtr[camIdx], (UInt32)_bufferSize[camIdx]);
if (status != VirtualFG40Library.MCAM_ERR_SUCCESS)
{
PUB.log_[logIdx].AddE($"Camera capture({camIdx}) error : {status}");
if (_hDevice[camIdx] > 0) _virtualFG40.AcqStop(_hDevice[camIdx]); //실패하면 멈춘다
PUB._isCrevisACQ[camIdx] = false;
PUB._isCrevisOpen[camIdx] = false; //연결여부도 끊는다
_virtualFG40.CloseDevice(_hDevice[camIdx]);
return false;
}
else _CrevisGrabTime[camIdx] = DateTime.Now;
//이미지생성 확인
if (mre[camIdx].WaitOne(100))
{
mre[camIdx].Reset();
if (OrgImage[camIdx] == null || OrgImage[camIdx].IsVoid)
{
OrgImage[camIdx] = new EImageBW8(_width[camIdx], _height[camIdx]);
}
//생성된 이미지 복사
using (var grabimg = new EImageBW8())
{
grabimg.SetImagePtr(_width[camIdx], _height[camIdx], camPtr[camIdx]);
grabimg.CopyTo(OrgImage[camIdx]);
//this.iv[camIdx].Invalidate(); //image update
DrawImage(camTarget, Piv, grabimg);
}
mre[camIdx].Set();
}
return true;
}
catch (Exception ex)
{
if (_hDevice[camIdx] > 0) _virtualFG40.AcqStop(_hDevice[camIdx]); //실패하면 멈춘다
PUB._isCrevisACQ[camIdx] = false;
//var stackFrame = new System.Diagnostics.StackTrace(1).GetFrame(1);
//string fileName = stackFrame.GetFileName();
//int lineNumber = stackFrame.GetFileLineNumber();
//var TraceInfo = stackFrame.ToString();
//var tracemsg = $"File:{fileName},Line:{lineNumber}\n{TraceInfo}";
PUB.log_[logIdx].AddE($"Crevis Grab({camIdx}):{ex.Message}");
return false;
}
finally
{
mre_grab[camIdx].Set();
}
}
public static string lastlogbarcode = string.Empty;
public static string[] lastbcd = new string[] { string.Empty, string.Empty };
public static Boolean RequestNewRead = false;
public static ManualResetEvent[] mre = new ManualResetEvent[2];
static string[] prebarcodedata = new string[] { "", "" };
/// <summary>
/// 이미지를 처리합니다
/// 트리거가 없는 경우에는 릴존재여부와/컨베이어확인을 합니다.
/// 트리거가 있다면 릴 영역을 찾아서 ID를 스캔합니다
/// </summary>
/// <param name="camIdx"></param>
/// <returns></returns>
public static bool CreavisProcess(int camIdx, bool isTrigger, Panel Piv)
{
var camTarget = PUB.GetTarget(camIdx);
if (camTarget == eTarget.None) return false;
var logIdx = camTarget == eTarget.Left ? 0 : 1;
//이미지사용여부확인
if (mre[camIdx].WaitOne(100) == false) return false;
mre[camIdx].Reset();
//이미지가 유효한 경우 처리한다
if (OrgImage[camIdx] == null || OrgImage[camIdx].IsVoid)
{
mre[camIdx].Set();
return false;
}
mre[camIdx].Reset();
System.Diagnostics.Stopwatch wat = new System.Diagnostics.Stopwatch();
wat.Restart();
//검사영역확인
var rect_reeldetect = camIdx == PUB.setting.CameraIndexL ? PUB.setting.ROI_ReelDetect_L : PUB.setting.ROI_ReelDetect_R;
var rect_convdetect = camIdx == PUB.setting.CameraIndexL ? PUB.setting.ROI_ConvDetect_L : PUB.setting.ROI_ConvDetect_R;
try
{
//
//iv[camIdx].Shapes.Clear();
string msg;
string bcdlist = string.Empty;
int DataCount = 0;// data1.Count;
Util_Vision.SCodeData codedata = new Util_Vision.SCodeData();
List<string> datalist = new List<string>();
List<Point[]> ptlist = new List<Point[]>();
var prccnt = 0;
string barcodeMessage = string.Empty;
//erode 값이 1과 3일때 차이가 발생함, 어두운 녹색라벨혹은, QR이 border에 붙은경우에 erode 3 은 서로 붙게되어서 필터링 되버림
//CvInvoke.CvtColor(OrgImage, OrgCImage, ColorConversion.Gray2Bgr);
//릴을 확인 한다
//if (IsProcess[camidx])
//{
using (EImageEncoder enc = new EImageEncoder())
{
using (var seg = enc.GrayscaleSingleThresholdSegmenter)
{
seg.WhiteLayerEncoded = true;
seg.BlackLayerEncoded = false;
seg.Mode = EGrayscaleSingleThreshold.Absolute;
seg.AbsoluteThreshold = 50;
}
using (ECodedImage2 encimg = new ECodedImage2())
{
using (EROIBW8 roiimge = new EROIBW8())
{
roiimge.Attach(OrgImage[camIdx]);
roiimge.SetPlacement(500, 70, 3008, 2640); //컨베이어전체영역이ㄴ
enc.Encode(roiimge, encimg);
using (EObjectSelection selection = new EObjectSelection())
{
selection.Clear();
selection.AddObjects(encimg);
selection.RemoveUsingUnsignedIntegerFeature(EFeature.Area, 1000, ESingleThresholdMode.LessEqual);
PUB.DetectReelValue[camIdx] = (int)selection.ElementCount;
PUB.DetectReel[camIdx] = selection.ElementCount > 1;
}
}
}
}
//
//else Pub.DetectReel = false;
//컨베이어 확인여부 체크필요
var roi_conv = camIdx == PUB.setting.CameraIndexL ? PUB.setting.ROI_ConvDetect_L : PUB.setting.ROI_ConvDetect_R;
if (roi_conv.IsEmpty == false)
{
using (EImageBW8 thimage = new EImageBW8(OrgImage[camIdx].Width, OrgImage[camIdx].Height))
{
EasyImage.Copy(OrgImage[camIdx], thimage);
var minresidu = EasyImage.AutoThreshold(thimage, EThresholdMode.MinResidue);
EasyImage.Threshold(thimage, thimage, minresidu.Value);
using (EROIBW8 roimage = new EROIBW8())
{
roimage.Attach(thimage);
roimage.SetPlacement(roi_conv.X, roi_conv.Y, roi_conv.Width, roi_conv.Height);
EasyImage.PixelCount(roimage, new EBW8(64), new EBW8(86), out int val_below,
out int val_between, out int val_above);
PUB.DetectConvValue[camIdx] = val_below;
var det_value = camIdx == PUB.setting.CameraIndexL ? PUB.setting.ConvDetectValueL : PUB.setting.ConvDetectValueR;
PUB.DetectConv[camIdx] = val_below < det_value;
}
}
}
else PUB.DetectConv[camIdx] = false;
//QR코드를 읽는다
List<Util_Vision.SCodeData> qrdataList = new List<Util_Vision.SCodeData>();
if (isTrigger)
{
var qrrlt = Util_Vision.DetectQR(OrgImage[camIdx],
null, prccnt++, out msg,
PUB.setting.erodevaluestr,
PUB.setting.GainOffsetListStr,
PUB.setting.blob_area_min,
PUB.setting.blob_area_max,
PUB.setting.blob_sigmaxy,
PUB.setting.blob_sigmayy,
PUB.setting.blob_sigmaxx,
PUB.setting.blob_minw,
PUB.setting.blob_maxw,
PUB.setting.blob_minh,
PUB.setting.blob_maxh, finddata: PUB.lastdata[camIdx]);
qrdataList = qrrlt.Item1;
PUB.ProcessTime[camIdx] = qrrlt.Item4;
var target = camIdx == PUB.setting.CameraIndexL ? eTarget.Left : eTarget.Right;
// var pan = target == eTarget.Left ? pIvLeft : pIvRight;
DrawImage(target, Piv, OrgImage[camIdx], qrrlt.Item1, qrrlt.Item2, qrrlt.Item3);
DataCount = qrdataList.Count;
}
else DataCount = 0;
//데이터가 확인되었다면 읽은 경우이다
if (DataCount > 0)
{
var bidx = 0;
foreach (var item in qrdataList.OrderByDescending(t => t.sid))
{
datalist.Add(item.data);
ptlist.Add(item.corner);
codedata = item;
if (bcdlist.isEmpty() == false) bcdlist += "\n";
bcdlist += $"[#{bidx}] {item.data}";
bidx += 1;
}
}
var tsrun = DateTime.Now - _CrevisRunTime[camIdx];
var dispMessage = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " (" + tsrun.TotalMilliseconds.ToString("N0") + "ms)";
if (barcodeMessage.isEmpty() == false) dispMessage += "\n" + barcodeMessage;
if (bcdlist.isEmpty() == false && lastlogbarcode != bcdlist)
{
if(bcdlist.Equals(prebarcodedata[camIdx])==false)
{
PUB.log_[logIdx].Add("BARCODE", "New recognition:" + bcdlist);
prebarcodedata[camIdx] = bcdlist;
}
lastlogbarcode = bcdlist;
RaiseRemoteCommand(remotelist.barcodeupdate, camIdx, bcdlist); //값이 변경되었으니 표시해준다
}
else if (bcdlist.isEmpty() && lastlogbarcode.isEmpty() == false)
{
RaiseRemoteCommand(remotelist.barcodeupdate, camIdx, string.Empty);
lastlogbarcode = string.Empty;
}
var tsparse = DateTime.Now - parsetime;
if (tsparse.TotalMilliseconds >= PUB.setting.GrabDelaySlow)
{
//var data = codedata.data;//: String.Empty;
if (PUB.RequestNewRead)
{
//신규 요청받고 처음들어온 데이터는 처리하지 말자 - 211213
PUB.RequestNewRead = false;
}
else
{
if (PUB.setting.SendRawData) //211210
{
if (PUB.BarcodeParsing(camIdx, qrdataList, "CREVIS"))
parsetime = DateTime.Now;
else
parsetime = DateTime.Now.AddMilliseconds(50);
}
else
{
if (PUB.BarcodeParsing(camIdx, datalist, "CREVIS"))
parsetime = DateTime.Now;
else
parsetime = DateTime.Now.AddMilliseconds(50);
}
}
}
else //이떄에는 용량을 체크한다. 210805
{
try
{
if (PUB.setting.AutoDeleteSeconds > 0 && PUB.setting.AutoDeleteSeconds < 99)
{
var di = new System.IO.DirectoryInfo(PUB.setting.ImageSavePath);
var ttime = DateTime.Now.AddSeconds(-PUB.setting.AutoDeleteSeconds);
var dellist = di.GetFiles().Where(t => t.CreationTime <= ttime).FirstOrDefault();
if (dellist != null) dellist.Delete();
}
}
catch { }
}
//iv[camIdx].Invalidate();
wat.Stop();
PUB.ProcessTime[camIdx] = wat.ElapsedMilliseconds;
_CrevisRunTime[camIdx] = DateTime.Now;
return true;
}
catch (Exception ex)
{
//var tracemsg = $"File:{fileName},Line:{lineNumber}\n{TraceInfo}";
PUB.log_[logIdx].AddE($"Crevis Process({camIdx}):" + ex.Message);
return false;
}
finally
{
wat.Stop();
mre[camIdx].Set();
}
}
/// <summary>
/// 판넬이미지 변경
/// </summary>
/// <param name="target"></param>
/// <param name="p"></param>
/// <param name="grabimg"></param>
/// <param name="qrdata">확인된 qr이 있다면 표시합니다.</param>
/// <param name="rect_area">흰색영역이 마킹된 영역</param>
/// <param name="rect_reel">QR로 추정되는 영역</param>
public static void DrawImage(eTarget target, Panel p, EImageBW8 grabimg,
List<Util_Vision.SCodeData> qrdata = null,
List<Rectangle> rect_area = null,
List<Rectangle> rect_reel = null)
{
var roi_reel = target == eTarget.Left ? PUB.setting.ROI_ReelDetect_L : PUB.setting.ROI_ReelDetect_R;
var roi_conv = target == eTarget.Left ? PUB.setting.ROI_ConvDetect_L : PUB.setting.ROI_ConvDetect_R;
var camIdx = target == eTarget.Left ? PUB.setting.CameraIndexL : PUB.setting.CameraIndexR;
var detect_reel = PUB.DetectReel[camIdx];
var detect_conv = PUB.DetectConv[camIdx];
var zoomx = (p.Width * 1f) / grabimg.Width;
var zoomy = (p.Height * 1f) / grabimg.Height;
using (var g = p.CreateGraphics())
{
grabimg.Draw(g, zoomx, zoomy);
//이미지의 중앙부분으 포커스를 계산한다.
float focus = 0f;
if (OrgImage[camIdx].IsVoid == false)
{
var fw = (int)(OrgImage[camIdx].Width * 0.4f);
var fh = (int)(OrgImage[camIdx].Height * 0.4f);
var fx = (int)((OrgImage[camIdx].Width - fw) / 2f);
var fy = (int)((OrgImage[camIdx].Height - fw) / 2f);
//var frect = new Rectangle(fx, fy, fw, fh);
g.DrawRectangle(Pens.Gold, fx * zoomx, fy * zoomy, fw * zoomx, fh * zoomy);
using (var img = new EROIBW8())
{
img.Attach(OrgImage[camIdx]);
img.SetPlacement(fx, fy, fw, fh);
focus = EasyImage.Focusing(img);
}
}
using (Font f = new Font("Consolas", 10, FontStyle.Bold))
{
var msg = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") +
$"\ncam:{camIdx},focus:{focus}" +
$"\nReel:{detect_reel},Value={PUB.DetectReelValue[camIdx]}" +
$"\nConv:{detect_conv},Value={PUB.DetectConvValue[camIdx]}";
g.DrawString(msg, f,
Brushes.White, 10, 10);
}
if (roi_reel.IsEmpty == false)
{
var rect = roi_reel;
var x = rect.X * zoomx;
var y = rect.Y * zoomy;
var w = rect.Width * zoomx;
var h = rect.Height * zoomy;
g.DrawRectangle(Pens.Lime, x, y, w, h);
}
if (roi_conv.IsEmpty == false)
{
var rect = roi_conv;
var x = rect.X * zoomx;
var y = rect.Y * zoomy;
var w = rect.Width * zoomx;
var h = rect.Height * zoomy;
g.DrawRectangle(Pens.Magenta, x, y, w, h);
}
//border
g.DrawRectangle(Pens.White, p.DisplayRectangle);
//검색영역표시(영역검사)
if (rect_area != null && rect_area.Any())
{
foreach (var item in rect_area)
{
var x = item.X * zoomx;
var y = item.Y * zoomy;
var w = item.Width * zoomx;
var h = item.Height * zoomy;
g.DrawRectangle(Pens.SkyBlue, x, y, w, h);
}
}
//검색영역표시(QR검사)
if (rect_reel != null && rect_reel.Any())
{
foreach (var item in rect_reel)
{
var x = item.X * zoomx;
var y = item.Y * zoomy;
var w = item.Width * zoomx;
var h = item.Height * zoomy;
g.DrawRectangle(Pens.Blue, x, y, w, h);
}
}
//바코드가 검색되었다면?
if (qrdata != null && qrdata.Any())
{
using (Font f = new Font("Consolas", 10, FontStyle.Bold))
{
foreach (var item in qrdata)
{
//각코너의 점을 표시한다.
var firstX = 0f;
var firstY = 0f;
foreach (var cn in item.corner)
{
var x = cn.X * zoomx;
var y = cn.Y * zoomy;
if (firstX == 0 && firstY == 0)
{
firstX = x;
firstY = y;
}
}
//첫번째 좌표에 데이터를 표시해준다
g.DrawString(item.data, f, Brushes.Lime, firstX, firstY);
}
}
}
g.Dispose();
}
}
public static string[] lastlog = new string[] { string.Empty, string.Empty };
public static DateTime[] logtime = new DateTime[] { DateTime.Now, DateTime.Now };
public static bool[] _trigger = new bool[] { false, false };
public static DateTime[] triggerTime = new DateTime[] { DateTime.Now, DateTime.Now };
public static Boolean[] IsTrigger = new bool[] { false, false };
public static DateTime TriggerStart = DateTime.Now;
public static Boolean BarcodeParsing(int camIdx, List<Util_Vision.SCodeData> data, string source, Boolean force = false)
{
var camTarget = PUB.GetTarget(camIdx);
if (camTarget == eTarget.None) return false;
var logIdx = camTarget == eTarget.Left ? 0 : 1;
var datatagstr = string.Empty;
foreach (var item in data)
if (item.data.isEmpty() == false)
{
if (datatagstr.Length > 0) datatagstr += "\n";
datatagstr += item.data;
}
PUB.lastbcd[camIdx] = datatagstr;
//스트림데이터가 꺼져있다면 처리하지 않는다.
if (force == false && PUB.setting.DisableStreamData)
{
//트리거모드일때 보내는 플래그가 없다면 보내지 않는다.
if (PUB.IsTrigger[camIdx] == false)
{
PUB.log_[logIdx].AddAT($"[SKIP-SEND] No Trigger Signal");
return false;
}
}
//TriggerSend = false;
//통신이 연결되어있지 않다면 처리하지 않는다
if (PUB.wsock_[logIdx].IsListening == false || PUB.wsock_[logIdx].ListClients().Count() < 1)
{
PUB.log_[logIdx].AddAT($"[SKIP-SEND] Disconnected");
return false;
}
//파일을 저장한다.
var path = "";
if (PUB.mre[camIdx].WaitOne(100))
{
try
{
PUB.mre[camIdx].Reset();
path = System.IO.Path.Combine(PUB.setting.ImageSavePath, $"[{camIdx}]barcode_{DateTime.Now.ToString("HHmmssfff")}.jpg");
var fi = new System.IO.FileInfo(path);
if (fi.Directory.Exists == false) fi.Directory.Create();
PUB.OrgImage[camIdx].Save(fi.FullName);
}
catch (Exception ex)
{
PUB.log_[logIdx].AddE($"Save failed {ex.Message}");
}
finally
{
PUB.mre[camIdx].Set();
}
}
else
{
PUB.log_[logIdx].AddE($"Save failed (object is locked)");
}
//데이터 생성
var msg = new
{
guid = PUB.lastguid[camIdx],
command = PUB.lastcmd[camIdx],
data = data,
time = DateTime.Now.ToString(),
file = path
};
var json = Newtonsoft.Json.JsonConvert.SerializeObject(msg);
Boolean sendok = false;
try
{
if (PUB.setting.Log_BarcodeTx)
{
if (lastlog[camIdx] == datatagstr)
{
var tsee = DateTime.Now - logtime[camIdx];
if (tsee.TotalSeconds > 60)
{
PUB.log_[logIdx].AddI(json);
lastlog[camIdx] = datatagstr;
logtime[camIdx] = DateTime.Now;
}
}
else
{
PUB.log_[logIdx].AddI(json);
lastlog[camIdx] = datatagstr;
}
}
//PUB.ws[camIdx].ListClients().ToList().ForEach(t => PUB.ws[camIdx].SendAsync(t, json).Wait());
PUB.lastsend[camIdx] = DateTime.Now;
Send_WSock(camTarget, json);
if (msg.guid.isEmpty() == false)
PUB.log_[logIdx].Add("Tx", json);
sendok = true;
}
catch (Exception ex)
{
PUB.log_[logIdx].AddE($"Send failed {ex.Message}");
sendok = false;
}
if (sendok == false)
{
try
{
PUB.log_[logIdx].AddAT("Closing server due to send failure");
Time_WS_Listen[camIdx] = DateTime.Now;
PUB.wsock_[logIdx].Stop();
}
catch (Exception ex)
{
PUB.log_[logIdx].AddE($"Server shutdown failed:{ex.Message}");
}
return false;
}
else return true;
}
public static ManualResetEvent[] mre_send = new ManualResetEvent[2];
public static bool Send_WSock(eTarget camTarget, string data)
{
if (camTarget == eTarget.None) return false;
var camIdx = camTarget == eTarget.Left ? PUB.setting.CameraIndexL : PUB.setting.CameraIndexR;
var logIdx = camTarget == eTarget.Left ? 0 : 1;
if (PUB.wsock_[logIdx].IsListening == false || PUB.wsock_[logIdx].ListClients().Count() < 1)
{
PUB.log_[logIdx].AddAT($"[IGNORE-SEND] Not Listening or No Clients");
return false;
}
if (mre_send[camIdx].WaitOne(1000) == false)
{
PUB.log_[logIdx].AddE($"send error by mre-lock");
return false;
}
mre_send[camIdx].Reset();
var ws = PUB.wsock_[logIdx];
try
{
ws.ListClients().ToList().ForEach(t => ws.SendAsync(t, data).Wait());
PUB.log_[logIdx].AddI($"send Complete {data}");
return true;
}
catch (Exception ex)
{
PUB.log_[logIdx].AddE($"send error by {ex.Message}");
return false;
}
finally
{
mre_send[camIdx].Set();
}
}
//마지막으로 전송에 사용한 데이터를 임시 저장한다. -211213 // 데이터 missing 현상 관련 처리 작업
public static string[] lastTxGuid = new string[] { string.Empty, string.Empty };
public static string[] lastTxRID = new string[] { string.Empty, string.Empty };
public static DateTime lastTxTime = DateTime.Now;
public static Boolean BarcodeParsing(int camIdx, List<string> data, string source)
{
if (data == null || data.Count < 1) return false;
PUB.lastbcd[camIdx] = string.Join("|", data);
var camTarget = PUB.GetTarget(camIdx);
if (camTarget == eTarget.None) return false;
var logIdx = camTarget == eTarget.Left ? 0 : 1;
//스트림데이터가 꺼져있다면 처리하지 않는다.
if (PUB.setting.DisableStreamData)
{
//트리거모드일때 보내는 플래그가 없다면 보내지 않는다.
if (IsTrigger[camIdx] == false) return false;
}
//통신이 연결되어있지 않다면 처리하지 않는다
if (PUB.wsock_[logIdx].IsListening == false || PUB.wsock_[logIdx].ListClients().Count() < 1) return false;
//파일을 저장한다.
var path = "";
if (PUB.mre[camIdx].WaitOne(100))
{
try
{
path = System.IO.Path.Combine(PUB.setting.ImageSavePath, $"[{camIdx}]barcode_{DateTime.Now.ToString("HHmmssfff")}.jpg");
PUB.mre[camIdx].Reset();
var fi = new System.IO.FileInfo(path);
if (fi.Directory.Exists == false) fi.Directory.Create();
PUB.OrgImage[camIdx].Save(fi.FullName);
}
catch (Exception ex)
{
PUB.log_[logIdx].AddE($"Save failed {ex.Message}");
}
finally
{
PUB.mre[camIdx].Set();
}
}
//데이터 생성
var msg = new
{
guid = PUB.lastguid[camIdx],
command = PUB.lastcmd[camIdx],
data = data,
time = DateTime.Now.ToString(),
file = path
};
//마지막으로전송한 RID값이 동일한경우
if (lastTxRID[camIdx].Trim() == PUB.lastbcd[camIdx].Trim())
{
if (lastTxGuid[camIdx].Trim() != PUB.lastguid[camIdx].Trim())
{
var tsTx = DateTime.Now - lastTxTime;
if (tsTx.TotalSeconds < 5)
{
//GUID가 다른데 rid가 같다 /
//missing data 의 패턴잉ㅆ다. 2113
//이때는 전송하지 않고 그냥 skip하게한다.
PUB.lastguid[camIdx] = string.Empty;
PUB.lastcmd[camIdx] = string.Empty;
PUB.log_[logIdx].Add($"Only GUID of last transmission data differs, processing skip. (within 5 seconds only)");
return false;
}
}
}
//마지막으로 전송한 데이터 값 저장
lastTxGuid[camIdx] = PUB.lastguid[camIdx];
lastTxRID = PUB.lastbcd;
lastTxTime = DateTime.Now;
var json = Newtonsoft.Json.JsonConvert.SerializeObject(msg);
Boolean sendok = false;
try
{
if (PUB.lastbcd[camIdx].isEmpty() == false && PUB.setting.Log_BarcodeTx)
{
if (lastlog[camIdx] == PUB.lastbcd[camIdx])
{
var tsee = DateTime.Now - logtime[camIdx];
if (tsee.TotalSeconds > 60)
{
PUB.log_[logIdx].AddI(json);
lastlog[camIdx] = PUB.lastbcd[camIdx];
logtime[camIdx] = DateTime.Now;
}
}
else
{
PUB.log_[logIdx].AddI(json);
lastlog[camIdx] = PUB.lastbcd[camIdx];
}
}
//PUB.ws[camIdx].ListClients().ToList().ForEach(t => PUB.ws[camIdx].SendAsync(t, json).Wait());
PUB.lastsend[camIdx] = DateTime.Now;
Send_WSock(camTarget, json);
if (msg.guid.isEmpty() == false)
PUB.log_[logIdx].Add("Tx", json);
sendok = true;
}
catch (Exception ex)
{
PUB.log_[logIdx].Add($"Send failed {ex.Message}");
sendok = false;
}
if (sendok == false)
{
try
{
PUB.log_[logIdx].AddAT("Closing server due to send failure");
PUB.Time_WS_Listen[camIdx] = DateTime.Now;
PUB.wsock_[logIdx].Stop();
}
catch (Exception ex)
{
PUB.log_[logIdx].AddE($"Server shutdown failed:{ex.Message}");
}
try
{
PUB.log_[logIdx].AddAT("Closing socket due to send failure");
PUB.wsock_[logIdx].Stop();
}
catch (Exception ex)
{
PUB.log_[logIdx].AddE($"Socket shutdown failed:{ex.Message}");
}
return false;
}
else return true;
}
public static DateTime[] Time_WS_Connected = new DateTime[2];
public static DateTime[] Time_WS_Disconnected = new DateTime[2];
public static DateTime[] Time_WS_Listen = new DateTime[2];
public static DateTime[] Time_WS_Listen_Try = new DateTime[2];
public static DateTime[] Time_WS_Recv = new DateTime[2];
public static string[] WS_LastRecv = new string[] { string.Empty, string.Empty };
public static string[] WS_LastSend = new string[] { string.Empty, string.Empty };
public static void ChangeUIPopup(System.Windows.Forms.NumericUpDown valueCtl)
{
var value = valueCtl.Value.ToString();
var f = AR.UTIL.InputBox("input value", value);// new Dialog.fInput(value);
if(f.Item1 == true)
{
var val = decimal.Parse(f.Item2);
if (val < valueCtl.Minimum)
{
UTIL.MsgE(string.Format("Minimum input value is {0}.", valueCtl.Minimum));
val = valueCtl.Minimum;
}
if (val > valueCtl.Maximum)
{
UTIL.MsgE(string.Format("Maximum input value is {0}.", valueCtl.Maximum));
val = valueCtl.Maximum;
}
valueCtl.Value = val;
}
}
}
}