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

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++;
}
}
}
}