- 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>
677 lines
32 KiB
C#
677 lines
32 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using AR;
|
|
#if EMGU
|
|
using Emgu.CV;
|
|
using Emgu.CV.Structure;
|
|
#endif
|
|
#if V22
|
|
using Euresys.Open_eVision_22_12;
|
|
#else
|
|
using Euresys.Open_eVision_2_11;
|
|
#endif
|
|
|
|
namespace Project
|
|
{
|
|
public static class Util_Vision
|
|
{
|
|
public struct SCodeData
|
|
{
|
|
public Point[] corner;
|
|
public string data;
|
|
public string model;
|
|
public string version;
|
|
public string level;
|
|
public string sid;
|
|
public void SetSID(string sid_) { sid = sid_; }
|
|
public Rectangle rect
|
|
{
|
|
get
|
|
{
|
|
if (corner == null || corner.Length != 4) return Rectangle.Empty;
|
|
var minx = corner.Min(t => t.X);
|
|
var maxx = corner.Max(t => t.X);
|
|
var miny = corner.Min(t => t.Y);
|
|
var maxy = corner.Max(t => t.Y);
|
|
return new Rectangle((int)minx, (int)miny, (int)(maxx - minx), (int)(maxy - miny));
|
|
}
|
|
}
|
|
public float intersectPerc(Rectangle r)
|
|
{
|
|
//입력한 영역이 얼마나 겹쳐있는지
|
|
if (rect.IsEmpty) return 0f;
|
|
|
|
//현재 영역이랑 겹치는 영역이 없다면 0f
|
|
if (rect.IntersectsWith(r) == false) return 0f;
|
|
|
|
var cx = r.Left + r.Width / 2f;
|
|
var cy = r.Top + r.Height / 2f;
|
|
if (rect.Contains((int)cx, (int)cy)) return 1f;
|
|
if (rect.Contains(r)) return 1f;
|
|
|
|
return 0f;
|
|
}
|
|
}
|
|
|
|
public static void DisplayQRData(List<SCodeData> DataArr, Rectangle roi, arCtl.ImageBoxEvision iv)
|
|
{
|
|
iv.Shapes.Clear();
|
|
foreach (var item in DataArr)
|
|
{
|
|
var p = new PointF[4];
|
|
p[0] = new PointF(item.corner[0].X + roi.Left, item.corner[0].Y + roi.Top);
|
|
p[1] = new PointF(item.corner[1].X + roi.Left, item.corner[1].Y + roi.Top);
|
|
p[2] = new PointF(item.corner[2].X + roi.Left, item.corner[2].Y + roi.Top);
|
|
p[3] = new PointF(item.corner[3].X + roi.Left, item.corner[3].Y + roi.Top);
|
|
|
|
iv.Shapes.AddLine(p[0], p[1], Color.Gold, 5);
|
|
iv.Shapes.AddLine(p[1], p[2], Color.Gold, 5);
|
|
iv.Shapes.AddLine(p[2], p[3], Color.Gold, 5);
|
|
iv.Shapes.AddLine(p[3], p[0], Color.Gold, 5);
|
|
|
|
if (item.data.isEmpty() == false)
|
|
{
|
|
iv.Shapes.AddText(item.corner[1], item.data, Color.Black, 200f);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static List<System.Drawing.PointF> GetGainOffsetList(string gainstr)
|
|
{
|
|
var retval = new List<System.Drawing.PointF>();
|
|
var list = gainstr.Split(';');
|
|
foreach (var item in list)
|
|
{
|
|
var ptitem = item.Split(',');
|
|
if (ptitem.Length == 2)
|
|
{
|
|
retval.Add(new System.Drawing.PointF(float.Parse(ptitem[0]), float.Parse(ptitem[1])));
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
// static SoftekBarcodeNet.BarcodeReader barcode = null;// new SoftekBarcodeNet.BarcodeReader();
|
|
|
|
static List<Util_Vision.SCodeData> ReadQR_EVision(EImageBW8 TargetImage, EQRCodeReader EQRCode1, RectangleF rect)
|
|
{
|
|
var retval = new System.Collections.Generic.List<Util_Vision.SCodeData>();
|
|
EQRCode1.SearchField = TargetImage;
|
|
var EQRCode2Result = EQRCode1.Read();
|
|
for (int j = 0; j < EQRCode2Result.Length; j++)
|
|
{
|
|
var QrData = EQRCode2Result[j];
|
|
if (QrData.IsDecodingReliable)
|
|
{
|
|
var geo = QrData.Geometry;
|
|
var pos = geo.Position;
|
|
var cornous = pos.Corners;
|
|
|
|
var resultData = new Util_Vision.SCodeData();
|
|
|
|
//테두리좌표 읽기
|
|
var resultcorns = new List<Point>();
|
|
for (int k = 0; k < cornous.Length; k++)
|
|
{
|
|
var con = cornous[k];
|
|
resultcorns.Add(new Point((int)(con.X + rect.X), (int)(con.Y + rect.Y)));
|
|
con.Dispose();
|
|
}
|
|
resultData.corner = resultcorns.ToArray();
|
|
|
|
//데이터읽기
|
|
resultData.model = QrData.Model.ToString();
|
|
resultData.version = QrData.Version.ToString();
|
|
resultData.level = QrData.Level.ToString();
|
|
resultData.sid = string.Empty;
|
|
|
|
//바코드데이터확인
|
|
var decodestr = QrData.DecodedStream;
|
|
resultData.data = string.Empty;
|
|
foreach (var item in decodestr.DecodedStreamParts)
|
|
{
|
|
resultData.data += System.Text.Encoding.Default.GetString(item.DecodedData);
|
|
item.Dispose();
|
|
}
|
|
|
|
//var c = new Class.CAmkorSTDBarcode(resultData.data);
|
|
//if (c.isValid) resultData.sid = c.SID;
|
|
//else resultData.sid = string.Empty;
|
|
//if (c.isValid) break;
|
|
//else resultData.data = string.Empty;
|
|
|
|
//결과데이터 추가
|
|
if (resultData.data.isEmpty() == false)
|
|
{
|
|
if (retval.Where(t => t.data == resultData.data).Any() == false)
|
|
{
|
|
retval.Add(resultData);
|
|
}
|
|
}
|
|
|
|
decodestr.Dispose();
|
|
decodestr = null;
|
|
|
|
cornous = null;
|
|
pos.Dispose();
|
|
geo.Dispose();
|
|
}
|
|
QrData.Dispose();
|
|
}
|
|
return retval;
|
|
}
|
|
//static List<Util_Vision.SCodeData> ReadQR_Softtek(EImageBW8 Image, RectangleF roi, Boolean useMedianfilter = false, int timeout = 50)
|
|
//{
|
|
|
|
// if (barcode == null)
|
|
// {
|
|
// barcode = new SoftekBarcodeNet.BarcodeReader();
|
|
// barcode.LicenseKey = "PC6q6K38G6bG9EWMlQxDr4O8aQzJWPSB";
|
|
// Pub.log.Add("softtek barcode init");
|
|
|
|
// // Turn on the barcode types you want to read.
|
|
// // Turn off the barcode types you don't want to read (this will increase the speed of your application)
|
|
// barcode.ReadCode128 = false;
|
|
// barcode.ReadCode39 = false;
|
|
// barcode.ReadCode25 = false;
|
|
// barcode.ReadEAN13 = false;
|
|
// barcode.ReadEAN8 = false;
|
|
// barcode.ReadUPCA = false;
|
|
// barcode.ReadUPCE = false;
|
|
// barcode.ReadCodabar = false;
|
|
// barcode.ReadPDF417 = false;
|
|
// barcode.ReadDataMatrix = true;
|
|
// barcode.ReadDatabar = false;
|
|
// barcode.ReadMicroPDF417 = false;
|
|
// barcode.ReadQRCode = true;
|
|
|
|
// // If you want to read more than one barcode then set Multiple Read to 1
|
|
// // Setting MutlipleRead to False will make the recognition faster
|
|
// barcode.MultipleRead = false;
|
|
// barcode.MaxBarcodesPerPage = 1;
|
|
// barcode.UseFastScan = true;
|
|
|
|
// // You may need to set a small quiet zone if your barcodes are close to text and pictures in the image.
|
|
// // A value of zero uses the default.
|
|
// barcode.QuietZoneSize = 0; //사용하면 느려짐
|
|
|
|
// // LineJump controls the frequency at which scan lines in an image are sampled.
|
|
// // The default is 9 - decrease this for difficult barcodes.
|
|
// barcode.LineJump = 3; //속도가 빨라지나 결과 검출 영향 많이 줌
|
|
// // The value is a mask where 1 = Left to Right, 2 = Top to Bottom, 4 = Right To Left, 8 = Bottom to Top
|
|
// barcode.ScanDirection = 15; //방향을 조정해주면 속도 가 빨라짐
|
|
|
|
// barcode.ColorProcessingLevel = 2;
|
|
// barcode.MinLength = 4;
|
|
// barcode.MaxLength = 9999;
|
|
// }
|
|
|
|
// barcode.MedianFilter = useMedianfilter;//Pub.setting.CameraMeanFilter;
|
|
// barcode.TimeOut = timeout;// 50;// Pub.setting.CameraTimeOut;
|
|
|
|
// int nBarCode;
|
|
// var retval = new List<Util_Vision.SCodeData>();
|
|
|
|
// var Scan0 = Image.GetImagePtr();
|
|
// using (var bmp = new Bitmap(Image.Width, Image.Height, Image.RowPitch, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, Scan0))
|
|
// {
|
|
// //비트맵 개체로 데이터를 읽어본다
|
|
// nBarCode = barcode.ScanBarCodeFromBitmap(bmp);
|
|
|
|
// if (nBarCode <= -6)
|
|
// {
|
|
// //Result.Text += "License key error: either an evaluation key has expired or the license key is not valid for processing pdf documents\r\n";
|
|
// }
|
|
// else if (nBarCode < 0)
|
|
// {
|
|
// //Result.Text += "ScanBarCode returned error number ";
|
|
// //Result.Text += nBarCode.ToString();
|
|
// //Result.Text += "\r\n";
|
|
// //Result.Text += "Last Softek Error Number = ";
|
|
// //Result.Text += barcode.GetLastError().ToString();
|
|
// //Result.Text += "\r\n";
|
|
// //Result.Text += "Last Windows Error Number = ";
|
|
// //Result.Text += barcode.GetLastWinError().ToString();
|
|
// //Result.Text += "\r\n";
|
|
// }
|
|
// else if (nBarCode == 0)
|
|
// {
|
|
// //Result.Text += "No barcode found on this image\r\n";
|
|
// }
|
|
// else
|
|
// {
|
|
// //Result.Text += "\r\n";
|
|
// for (int i = 1; i <= nBarCode; i++)
|
|
// {
|
|
// var rect = barcode.GetBarStringRect(i);
|
|
|
|
// var resultData = new SCodeData()
|
|
// {
|
|
// corner = new Point[] {
|
|
// new Point((int)(rect.Left+roi.X),(int)(rect.Top + roi.Y)),
|
|
// new Point((int)(rect.Right+roi.X),(int)(rect.Top+roi.Y)),
|
|
// new Point((int)(rect.Left+roi.X),(int)(rect.Bottom+roi.Y)),
|
|
// new Point((int)(rect.Right+roi.X),(int)(rect.Bottom+roi.Y))
|
|
// },
|
|
// data = barcode.GetBarString(i),
|
|
// level = string.Empty,
|
|
// model = string.Empty,
|
|
// sid = string.Empty,
|
|
// version = string.Empty,
|
|
// };
|
|
|
|
// //결과데이터 추가
|
|
// if (resultData.data.isEmpty() == false)
|
|
// {
|
|
// if (retval.Where(t => t.data == resultData.data).Any() == false)
|
|
// {
|
|
// retval.Add(resultData);
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// return retval;
|
|
// }
|
|
//}
|
|
|
|
public static Tuple<List<SCodeData>, List<Rectangle>, List<Rectangle>, double> DetectQR(
|
|
EImageBW8 EBW8Image4,
|
|
arCtl.ImageBoxEvision iv1, int idx,
|
|
out string Message,
|
|
string erodevaluestr = "3,1",
|
|
string gainoffsetlist = "2,1",
|
|
uint blob_area_min = 20000,
|
|
uint blob_area_max = 70000,
|
|
float blob_sigmaxy = 500f,
|
|
float blob_sigmayy = 500f,
|
|
float blob_sigmaxx = 5000f,
|
|
float blob_minw = 50,
|
|
float blob_maxw = 350,
|
|
float blob_minh = 50,
|
|
float blob_maxh = 350,
|
|
//bool addSofttekRead = false,
|
|
string maskfile = "",
|
|
string finddata = ""//,
|
|
// Image<Bgr, byte> DispImage = null
|
|
)
|
|
{
|
|
Message = string.Empty;
|
|
var pts = new System.Collections.Generic.List<Util_Vision.SCodeData>();
|
|
System.Diagnostics.Stopwatch wat = new System.Diagnostics.Stopwatch();
|
|
wat.Restart();
|
|
|
|
List<RectangleF> ros = new List<RectangleF>();
|
|
List<Rectangle> whiterects = new List<Rectangle>();
|
|
|
|
uint objectCountT = 0;
|
|
//Blob 으로 바코드영역을 찾는다
|
|
using (ECodedImage2 codedImage4 = new ECodedImage2()) // ECodedImage2 instance
|
|
{
|
|
using (EImageEncoder codedImage4Encoder = new EImageEncoder()) // EIma
|
|
{
|
|
using (EObjectSelection codedImage4ObjectSelection = new EObjectSelection())
|
|
{
|
|
codedImage4ObjectSelection.FeretAngle = 0.00f;
|
|
|
|
//기본이미지에서 흰색영역을 찾아서 해당 영역만 처리한다.
|
|
using (var psegment = codedImage4Encoder.GrayscaleSingleThresholdSegmenter) //.BlackLayerEncoded = true;
|
|
{
|
|
psegment.BlackLayerEncoded = false;
|
|
psegment.WhiteLayerEncoded = true;
|
|
psegment.Mode = EGrayscaleSingleThreshold.MaxEntropy;
|
|
}
|
|
|
|
//마스크적용 - 210209
|
|
if (maskfile.isEmpty() == false && System.IO.File.Exists(maskfile))
|
|
{
|
|
using (var maskmig = new EImageBW8())
|
|
{
|
|
maskmig.Load(maskfile);//이미지불러오지
|
|
EasyImage.Oper(EArithmeticLogicOperation.BitwiseAnd, EBW8Image4, maskmig, EBW8Image4);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//흰색데이터강조
|
|
using (var deilimage = new EImageBW8(EBW8Image4.Width, EBW8Image4.Height))
|
|
{
|
|
EasyImage.DilateBox(EBW8Image4, deilimage, 30);
|
|
codedImage4Encoder.Encode(deilimage, codedImage4);
|
|
codedImage4ObjectSelection.Clear();
|
|
codedImage4ObjectSelection.AddObjects(codedImage4);
|
|
codedImage4ObjectSelection.RemoveUsingUnsignedIntegerFeature(EFeature.Area, 50000, ESingleThresholdMode.LessEqual);
|
|
for (uint i = 0; i < codedImage4ObjectSelection.ElementCount; i++)
|
|
{
|
|
var elm = codedImage4ObjectSelection.GetElement(i);
|
|
var x = elm.BoundingBoxCenterX - elm.BoundingBoxWidth / 2f;
|
|
var y = elm.BoundingBoxCenterY - elm.BoundingBoxHeight / 2f;
|
|
var w = elm.BoundingBoxWidth;
|
|
var h = elm.BoundingBoxHeight;
|
|
whiterects.Add(new Rectangle((int)x, (int)y, (int)w, (int)h));
|
|
elm.Dispose();
|
|
}
|
|
}
|
|
|
|
//침식해서 바코드영역이 뭉치도록 한다. (바코드는 검은색 영역이 된다)
|
|
List<uint> erodevalues = new List<uint>();
|
|
var erodebuffer = erodevaluestr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
|
foreach (var erbuf in erodebuffer) erodevalues.Add(uint.Parse(erbuf));
|
|
using (var psegment = codedImage4Encoder.GrayscaleSingleThresholdSegmenter) //.BlackLayerEncoded = true;
|
|
{
|
|
psegment.BlackLayerEncoded = true;
|
|
psegment.WhiteLayerEncoded = false;
|
|
}
|
|
|
|
//QR코드예상위치를 저장할 영역변수
|
|
|
|
//찾은 흰색영역에서 작업을 진행한다
|
|
foreach (var roi in whiterects)
|
|
{
|
|
//각영역을 erod 처리하여 추가 영역을 찾는다
|
|
using (EROIBW8 roimage = new EROIBW8())
|
|
{
|
|
roimage.Attach(EBW8Image4);
|
|
roimage.SetPlacement(roi.X, roi.Y, roi.Width, roi.Height);
|
|
|
|
for (int maxtype = 0; maxtype < 2; maxtype++)
|
|
{
|
|
//침식데이터도 여러개를 사용한다.
|
|
foreach (var erodevalue in erodevalues)
|
|
{
|
|
//Erode image
|
|
using (var ErodeImageBW8 = new EImageBW8(roimage.Width, roimage.Height))
|
|
{
|
|
EasyImage.ErodeBox(roimage, ErodeImageBW8, erodevalue);
|
|
|
|
|
|
using (var psegment = codedImage4Encoder.GrayscaleSingleThresholdSegmenter)
|
|
{
|
|
if (maxtype == 0)
|
|
psegment.Mode = EGrayscaleSingleThreshold.MinResidue;
|
|
else if (maxtype == 1)
|
|
psegment.Mode = EGrayscaleSingleThreshold.MaxEntropy;
|
|
else if (maxtype == 2)
|
|
psegment.Mode = EGrayscaleSingleThreshold.IsoData;
|
|
}
|
|
|
|
codedImage4Encoder.Encode(ErodeImageBW8, codedImage4);
|
|
codedImage4ObjectSelection.Clear();
|
|
codedImage4ObjectSelection.AddObjects(codedImage4);
|
|
codedImage4ObjectSelection.AttachedImage = ErodeImageBW8;
|
|
|
|
//너무큰 개체를 제거한다.
|
|
codedImage4ObjectSelection.RemoveUsingUnsignedIntegerFeature(EFeature.Area, blob_area_min, ESingleThresholdMode.LessEqual);
|
|
codedImage4ObjectSelection.RemoveUsingUnsignedIntegerFeature(EFeature.Area, blob_area_max, ESingleThresholdMode.GreaterEqual);
|
|
|
|
codedImage4ObjectSelection.RemoveUsingFloatFeature(EFeature.BoundingBoxWidth, blob_minw, ESingleThresholdMode.LessEqual);
|
|
codedImage4ObjectSelection.RemoveUsingFloatFeature(EFeature.BoundingBoxWidth, blob_maxw, ESingleThresholdMode.GreaterEqual);
|
|
|
|
codedImage4ObjectSelection.RemoveUsingFloatFeature(EFeature.BoundingBoxHeight, blob_minh, ESingleThresholdMode.LessEqual);
|
|
codedImage4ObjectSelection.RemoveUsingFloatFeature(EFeature.BoundingBoxHeight, blob_maxh, ESingleThresholdMode.GreaterEqual);
|
|
|
|
//개체제거
|
|
codedImage4ObjectSelection.RemoveUsingFloatFeature(EFeature.SigmaXY, blob_sigmaxy, ESingleThresholdMode.GreaterEqual);
|
|
//codedImage4ObjectSelection.RemoveUsingFloatFeature(EFeature.SigmaYY, blob_sigmayy, ESingleThresholdMode.LessEqual);
|
|
codedImage4ObjectSelection.RemoveUsingFloatFeature(EFeature.SigmaXX, blob_sigmaxx, ESingleThresholdMode.GreaterEqual);
|
|
|
|
//찾은데이터수량
|
|
var objectCount = codedImage4ObjectSelection.ElementCount;
|
|
|
|
objectCountT += objectCount;
|
|
|
|
//데이터표시
|
|
//찾은영역을 표시한다.
|
|
for (uint i = 0; i < objectCount; i++)
|
|
{
|
|
//각 요소를 가져와서 처리한다.
|
|
using (var elm = codedImage4ObjectSelection.GetElement(i))
|
|
{
|
|
var x = elm.BoundingBoxCenterX - elm.BoundingBoxWidth / 2f;
|
|
var y = elm.BoundingBoxCenterY - elm.BoundingBoxHeight / 2f;
|
|
var w = elm.BoundingBoxWidth;
|
|
var h = elm.BoundingBoxHeight;
|
|
|
|
//절대좌표로 변경(
|
|
x += roimage.TotalOrgX;
|
|
y += roimage.TotalOrgY;
|
|
|
|
var rect = new RectangleF(x, y, w, h);
|
|
|
|
//이전 ROS에 겹치는 영역이 있다면 해당 ROS값을 확장해준다
|
|
bool find = false;
|
|
for (int j = 0; j < ros.Count; j++)
|
|
{
|
|
if (ros[j].IntersectsWith(rect))
|
|
{
|
|
//겹쳐있으니 영역을 확장해준다.
|
|
var x1 = Math.Min(ros[j].X, rect.X);
|
|
var y1 = Math.Min(ros[j].Y, rect.Y);
|
|
var w1 = Math.Max(ros[j].Right, rect.Right) - x1;
|
|
var h1 = Math.Max(ros[j].Bottom, rect.Bottom) - y1;
|
|
ros[j] = new RectangleF(x1, y1, w1, h1);
|
|
find = true;
|
|
break;
|
|
}
|
|
}
|
|
if (find == false) ros.Add(rect); //겹치는 영역이 없으니 추가한다.
|
|
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//whitelist 에서 QR을 검색한다.(밝기조정없음)
|
|
var find2 = false;
|
|
|
|
//ROS에서 QR을 검색한다(밝기조정함)
|
|
if (find2 == false)
|
|
{
|
|
foreach (var roi in ros)
|
|
{
|
|
//대상자료를 찾았다면 멈춘다
|
|
if (ReadQRData(EBW8Image4, roi.toRect(), gainoffsetlist, ref pts, finddata))
|
|
{
|
|
find2 = true;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (find2 == false)
|
|
{
|
|
foreach (var roi in whiterects)
|
|
{
|
|
//대상자료를 찾았다면 멈춘다
|
|
if (ReadQRData(EBW8Image4, roi, "1,0", ref pts, finddata))
|
|
{
|
|
find2 = true; //대상을 찾았다면 더 진행하지 않는다
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
wat.Stop();
|
|
|
|
//검사시간 저장
|
|
var rosrect = ros.Select(t => new Rectangle((int)t.X, (int)t.Y, (int)t.Width, (int)t.Height)).ToList();
|
|
return new Tuple<List<SCodeData>, List<Rectangle>, List<Rectangle>, double>(pts, whiterects, rosrect, wat.ElapsedMilliseconds);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 지정한 영역에서 QR코드를 검색합니다.
|
|
/// </summary>
|
|
/// <param name="EBW8Image4"></param>
|
|
/// <param name="rect">검색영역</param>
|
|
/// <param name="gainoffsetlist">밝기변경값</param>
|
|
/// <param name="pts">결과저장소</param>
|
|
/// <param name="finddata">특정검색데이터</param>
|
|
/// <returns></returns>
|
|
static bool ReadQRData(EImageBW8 EBW8Image4, Rectangle rect, string gainoffsetlist, ref List<SCodeData> pts, string finddata = "")
|
|
{
|
|
var retval = false;
|
|
var GainOffsetList = GetGainOffsetList(gainoffsetlist);
|
|
|
|
//해당영역을 ROI로 잡고 이미지를 검색한다
|
|
var RoiImage2 = new EROIBW8();
|
|
RoiImage2.Attach(EBW8Image4);
|
|
|
|
//ROI로 사용할 영역의 오류를 체크해야한다
|
|
var rLeft = (int)rect.Left;
|
|
var rTop = (int)rect.Top;
|
|
if (rLeft < 0) rLeft = 0;
|
|
if (rTop < 0) rTop = 0;
|
|
|
|
var rWid = (int)rect.Width;
|
|
var rHei = (int)rect.Height;
|
|
|
|
//roi 오류수정 210621
|
|
if (rLeft + rWid > EBW8Image4.Width) rWid = EBW8Image4.Width - rLeft - 1;
|
|
if (rTop + rHei > EBW8Image4.Height) rHei = EBW8Image4.Height - rTop - 1;
|
|
|
|
var rourect = new Rectangle(rLeft, rTop, rWid, rHei);
|
|
RoiImage2.SetPlacement(rourect.Left, rourect.Top, rourect.Width, rourect.Height); //ROI적용
|
|
|
|
var TargetImage = new EImageBW8(RoiImage2.Width, RoiImage2.Height);
|
|
|
|
//밝기를 변경해서 처리해야한다
|
|
//int processCount = 9;
|
|
|
|
foreach (var param in GainOffsetList) //원본, gain +-, offset +- 5가지 색상처리함
|
|
{
|
|
//크기를 동일하게 맞춰야 한다
|
|
EasyImage.ScaleRotate(RoiImage2,
|
|
RoiImage2.Width / 2f, RoiImage2.Height / 2f,
|
|
TargetImage.Width / 2f, TargetImage.Height / 2f,
|
|
1.0f, 1.0f, 0f, TargetImage);
|
|
//EasyImage.Copy(RoiImage, TargetImage);
|
|
|
|
//밝기를 변경해서 사용할 것이므로 해당 변경된 밝기를 저장할 이미지를 생성한다. 210128
|
|
//var roiimg = new EImageBW8(TargetImage);
|
|
//var param = Util_Vision.GetGainOffset(bright);
|
|
if (param.X != 1.0f || param.Y != 0.0f) EasyImage.GainOffset(TargetImage, TargetImage, param.X, param.Y);
|
|
//else RoiImage.CopyTo(TargetImage); ;// TargetImage.CopyTo(roiimg); //변경하지 않고 그대로 사용한다
|
|
|
|
using (EQRCodeReader EQRCode1 = new EQRCodeReader())
|
|
{
|
|
//EQRCode1.DetectionMethod = 15; //모든방법으로 데이터를 찾는다
|
|
EQRCode1.TimeOut = 1000 * 1000; //timeout (1초)
|
|
|
|
if (TargetImage.Width < 500 || TargetImage.Height < 500)
|
|
EQRCode1.ForegroundDetectionThreshold = 3;
|
|
|
|
var datas = ReadQR_EVision(TargetImage, EQRCode1, rect);
|
|
if (datas.Any())
|
|
{
|
|
//중복데이터는 제거한다 211211
|
|
foreach (var dataitem in datas)
|
|
{
|
|
if (pts.Where(t => t.data == dataitem.data).Any() == false)
|
|
pts.Add(dataitem);
|
|
else if (pts.Where(t => t.intersectPerc(dataitem.rect) > 0f).Any() == false)
|
|
pts.Add(dataitem);
|
|
|
|
//해당 데이터가 찾는 데이터라면 진행을 멈춘다
|
|
if (finddata.isEmpty() == false && dataitem.data.Equals(finddata))
|
|
{
|
|
//검색대상 자료이므로 진행을 멈춘다
|
|
retval = true;
|
|
break;
|
|
}
|
|
|
|
//해당데이터가 amkor standard 라면 문제없이 진행한다.
|
|
var splitbuf = dataitem.data.Split(';');
|
|
if (splitbuf.Length > 6 && splitbuf[0].StartsWith("10"))
|
|
{
|
|
//amkor std 라벨이므로 진행하지 않습니다.
|
|
retval = true;
|
|
break;
|
|
}
|
|
}
|
|
//pts.AddRange(datas);
|
|
}
|
|
|
|
//sDisplayQRInfo(datas, iv1);
|
|
}
|
|
if (retval == true) break; //대상자료르 찾았다면 진행을 멈춘다
|
|
}
|
|
RoiImage2.Dispose();
|
|
TargetImage.Dispose();
|
|
TargetImage = null;
|
|
return retval;
|
|
}
|
|
|
|
#if EMGU
|
|
static void DisplayQRInfo(List<Util_Vision.SCodeData> datas, arImageViewer.EVision.UI.CustomControl1 iv1)
|
|
#else
|
|
static void DisplayQRInfo(List<Util_Vision.SCodeData> datas, arCtl.ImageBoxEvision iv1)
|
|
#endif
|
|
{
|
|
if (iv1 == null) return;
|
|
var idx = 0;
|
|
foreach (var resultData in datas)
|
|
{
|
|
//var c = new Class.CAmkorSTDBarcode(resultData.data);
|
|
//if (c.isValid) resultData.SetSID(c.SID); // = c.SID;
|
|
//else resultData.SetSID(string.Empty);
|
|
|
|
//결과데이터 추가
|
|
if (resultData.data.isEmpty() == false)
|
|
{
|
|
|
|
//자료가잇다면 표시한다.
|
|
var dispvalue = $"#{idx}";// resultData.data;
|
|
//if (c.isValid == false) dispvalue += "\n" + c.Message;
|
|
//else if (c.DateError) dispvalue += "\n** Date Error **";
|
|
|
|
iv1.Shapes.AddText(resultData.corner[1].X + 1, resultData.corner[1].Y + 1, dispvalue, Color.Black, 50);
|
|
iv1.Shapes.AddText(resultData.corner[1].X, resultData.corner[1].Y, dispvalue, Color.Yellow, 50);
|
|
|
|
|
|
//if (DispImage != null)
|
|
// CvInvoke.PutText(DispImage,
|
|
// dispvalue,
|
|
// new Point(resultData.corner[1].X, resultData.corner[1].Y), FontFace.HersheyDuplex, 2,
|
|
// new Bgr(Color.Tomato).MCvScalar, 2);
|
|
|
|
//찾은테두리를 화면에 표시한다.
|
|
foreach (var pt in resultData.corner)
|
|
{
|
|
iv1.Shapes.AddPoint(pt, Color.Lime, 20f);
|
|
//if (DispImage != null)
|
|
//{
|
|
// CvInvoke.Line(DispImage,
|
|
// new Point(pt.X - 10, pt.Y - 10),
|
|
// new Point(pt.X + 10, pt.Y + 10),
|
|
// new Bgr(Color.Lime).MCvScalar, 2);
|
|
|
|
// CvInvoke.Line(DispImage,
|
|
// new Point(pt.X + 10, pt.Y - 10),
|
|
// new Point(pt.X - 10, pt.Y + 10),
|
|
// new Bgr(Color.Lime).MCvScalar, 2);
|
|
//}
|
|
}
|
|
}
|
|
idx++;
|
|
}
|
|
}
|
|
}
|
|
}
|