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>
This commit is contained in:
		
							
								
								
									
										676
									
								
								QRValidation/Project/Util_Vision.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										676
									
								
								QRValidation/Project/Util_Vision.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,676 @@ | ||||
| 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++; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 atvstdla
					atvstdla