protected void CheckCancelAndImageProcess() { // 종료 검사 CheckCancel(); // 반드시 새로운 이미지 프로세싱이 필요한 경우 _last = _turretService.ImageProcess(_last); // 이미지 프로세싱 결과 lock (_turretService.ImageProcessorLock) { _result = _turretService.ImageProcessorResult; } }
public ImageProcessorResult Process(Bitmap bitmap, bool rgb) { var result = new ImageProcessorResult(); _viewConfig = _configService.ViewConfig; _imageProcessorConfig = _configService.ImageProcessorConfig; new Blur().ApplyInPlace(bitmap); Bitmap overlay = bitmap; if (_viewConfig.BackgroundImage == ViewConfigBackgroundImage.CameraRaw) { // 카메라 원본 overlay = bitmap; } // 그레이 스케일 var grayscale = Grayscale.CommonAlgorithms.BT709.Apply(bitmap); // 경계 검출 var edges = new DifferenceEdgeDetector().Apply(grayscale); if (_viewConfig.BackgroundImage == ViewConfigBackgroundImage.Edge) { overlay = new GrayscaleToRGB().Apply(edges); } // 이진화 // var threshold = new Threshold(_imageProcessorConfig.Threshold).Apply(edges); var threshold = new OtsuThreshold().Apply(edges); if (_viewConfig.BackgroundImage == ViewConfigBackgroundImage.Binary) { overlay = new GrayscaleToRGB().Apply(threshold); } // 오버레이 복제 overlay = overlay.CloneBitmap(); // 오버레이 데이터 var overlayData = overlay.LockBits(overlay.GetRectangle(), ImageLockMode.ReadWrite, overlay.PixelFormat); _blobCounter = new BlobCounter(); _blobCounter.MinHeight = _imageProcessorConfig.BlobMinHeight; _blobCounter.MinHeight = _imageProcessorConfig.BlobMinWidth; _blobCounter.FilterBlobs = true; _blobCounter.ObjectsOrder = ObjectsOrder.XY; _blobCounter.ProcessImage(threshold); var blobs = _blobCounter.GetObjectsInformation(); var shapeChecker = new SimpleShapeChecker(); // 각 영역에 대해 처리 수행 foreach (var blob in blobs) { // 현재 시도하는 마커 Marker marker = new Marker(); var edgePoints = _blobCounter.GetBlobsEdgePoints(blob); // 사각형 판정 var points = new List <IntPoint>(); if (shapeChecker.IsQuadrilateral(edgePoints, out points)) { marker.Points = points; List <IntPoint> leftEdge, rightEdge; _blobCounter.GetBlobsLeftAndRightEdges(blob, out leftEdge, out rightEdge); // 각도와 길이 판정 if (MoreQuadTest(blob, marker, leftEdge, rightEdge)) { // 검은색 테두리 판정 if (BorderTest(blob, marker, grayscale, leftEdge, rightEdge)) { // 판정 완료 result.Markers.Add(marker); // 무게 중심 좌표 marker.X = (int)(blob.CenterOfGravity.X - (threshold.Width / 2)); marker.Y = (int)(-(blob.CenterOfGravity.Y - (threshold.Height / 2))); // 프레임워크에서 계산한 넓이 marker.FrameworkArea = blob.Area; // 오버레이 ApplyOverlay(overlayData, marker.Points); } } } } overlay.UnlockBits(overlayData); foreach (var marker in result.Markers) { var points = marker.Points; // 방향 보정 var sideLength = points[0].DistanceTo(points[1]); if (points[2].Y - points[1].Y < sideLength / 1.6) { points = new List <IntPoint>( new IntPoint[] { points[1], points[2], points[3], points[0] }); marker.Points = points; } // 변형 복구 var quadrilateralTransformation = new QuadrilateralTransformation(points, _imageProcessorConfig.QuadrilateralTransformationWidth, _imageProcessorConfig.QuadrilateralTransformationHeight); var transformed = quadrilateralTransformation.Apply(bitmap); // 회전 및 색상 판정 시작 int halfWidth = _imageProcessorConfig.QuadrilateralTransformationWidth / 2, halfHeight = _imageProcessorConfig.QuadrilateralTransformationHeight / 2; // x => x + 1 사분면 var crops = new[] { new Crop(new Rectangle(halfWidth, 0, halfWidth, halfHeight)), new Crop(new Rectangle(0, 0, halfWidth, halfHeight)), new Crop(new Rectangle(0, halfHeight, halfWidth, halfHeight)), new Crop(new Rectangle(halfWidth, halfHeight, halfWidth, halfHeight)) }; var quadImage = new[] { crops[0].Apply(transformed), crops[1].Apply(transformed), crops[2].Apply(transformed), crops[3].Apply(transformed) }; var filteredResult = new[] { new { Img = quadImage[0], Red = Filter(quadImage[0], MarkerColor.Red).Luminance(), Green = Filter(quadImage[0], MarkerColor.Green).Luminance(), Blue = Filter(quadImage[0], MarkerColor.Blue).Luminance(), White = Filter(quadImage[0], MarkerColor.White).Luminance() }, new { Img = quadImage[1], Red = Filter(quadImage[1], MarkerColor.Red).Luminance(), Green = Filter(quadImage[1], MarkerColor.Green).Luminance(), Blue = Filter(quadImage[1], MarkerColor.Blue).Luminance(), White = Filter(quadImage[1], MarkerColor.White).Luminance() }, new { Img = quadImage[2], Red = Filter(quadImage[2], MarkerColor.Red).Luminance(), Green = Filter(quadImage[2], MarkerColor.Green).Luminance(), Blue = Filter(quadImage[2], MarkerColor.Blue).Luminance(), White = Filter(quadImage[2], MarkerColor.White).Luminance() }, new { Img = quadImage[3], Red = Filter(quadImage[3], MarkerColor.Red).Luminance(), Green = Filter(quadImage[3], MarkerColor.Green).Luminance(), Blue = Filter(quadImage[3], MarkerColor.Blue).Luminance(), White = Filter(quadImage[3], MarkerColor.White).Luminance() } }; var whiteDesc = filteredResult.OrderByDescending(a => a.White).ToArray(); if (rgb) { // RGB 색상 판별 var colorQuad = whiteDesc.Skip(1); var red = colorQuad.Sum(a => a.Red); var green = colorQuad.Sum(a => a.Green); var blue = colorQuad.Sum(a => a.Blue); Console.WriteLine("{0}: {1} {2} {3}", colorQuad.Count(), red, green, blue); var max = Math.Max(red, Math.Max(green, blue)); if (red == max) { marker.Color = MarkerColor.Red; } else if (green == max) { marker.Color = MarkerColor.Green; } else if (blue == max) { marker.Color = MarkerColor.Blue; } } else { // 흑백 색상 판별 var whiteMax = whiteDesc[0].White; var whiteRest = (whiteDesc[1].White + whiteDesc[2].White + whiteDesc[3].White) / 3; if (whiteMax - whiteRest < _imageProcessorConfig.ColorTestWhite) { // White marker.Color = MarkerColor.White; } else { // Black marker.Color = MarkerColor.Black; } } // 회전 판별 for (int i = 0; i < 4; i++) { if (filteredResult[i].White == whiteDesc.First().White) { marker.Rotate = (MarkerRotate)(i + 1); break; } } // 백색 마커에는 회전 방향이 없습니다. if (marker.Color == MarkerColor.White) { // 지정되지 않습니다. marker.Rotate = MarkerRotate.None; } // 화상 중심으로 좌표 변환 for (int i = 0; i < marker.Points.Count; i++) { marker.Points[i] = new IntPoint { X = marker.Points[i].X - _configService.DeviceConfig.PixelWidth / 2, Y = marker.Points[i].Y - _configService.DeviceConfig.PixelHeight / 2 }; } // 코어 서비스에서 기하학적 방법으로 거리 계산 var coreResult = _coreService.Query(marker.Points, _imageProcessorConfig.MarkerSize); marker.EuclideanDistance = coreResult.Distance; marker.TiltAngle = Math.Asin(coreResult.TranslationVector[1] / marker.EuclideanDistance); marker.PanAngle = Math.Asin(coreResult.TranslationVector[0] / marker.EuclideanDistance); if (marker.PanAngle > Math.PI) { // 음수 marker.PanAngle = 2 * Math.PI - marker.PanAngle; } marker.TransX = coreResult.TranslationVector[0]; marker.TransY = coreResult.TranslationVector[1]; marker.TransZ = coreResult.TranslationVector[2]; } BackgroundBitmap = overlay; Console.WriteLine(); foreach (var marker in result.Markers) { Console.WriteLine(marker.Color); } return(result); }