public static Bitmap ConvertToBitmap(FastBitmapHSV bitmap) { Bitmap bmp = new Bitmap(bitmap.Width, bitmap.Height); unsafe { BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); int bytesPerPixel = Image.GetPixelFormatSize(bmp.PixelFormat) / 8; int bytesPerRow = bitmapData.Width * bytesPerPixel; for (int IdxY = 0; IdxY < bmp.Height; IdxY++) { byte *pixels = (byte *)bitmapData.Scan0 + (IdxY * bitmapData.Stride); for (int IdxByte = 0; IdxByte < bytesPerRow; IdxByte += bytesPerPixel) { FastPixelHSV writePx = bitmap.GetPixel(IdxByte / bytesPerPixel, IdxY); Color writeColor = Color.FromArgb(writePx.Monochrome, writePx.Monochrome, writePx.Monochrome); pixels[IdxByte + 3] = writeColor.A; pixels[IdxByte + 2] = writeColor.R; pixels[IdxByte + 1] = writeColor.G; pixels[IdxByte + 0] = writeColor.B; } } bmp.UnlockBits(bitmapData); } return(bmp); }
public static bool TraceLine(FastBitmapHSV bitmap, int posX, int posY, int incX, int incY, int traceLen, FastPixelMatch colorMatch, out Point posHit, bool bDebugMode = false) { if (bDebugMode) { Logger.WriteLine("TraceLine [" + posX + ", " + posY + "] -> [" + (posX + (incX * traceLen)) + ", " + (posY + (incY * traceLen)) + "]"); } for (int stepIdx = 0; stepIdx < traceLen; stepIdx++) { int scanX = posX + (stepIdx * incX); int scanY = posY + (stepIdx * incY); FastPixelHSV testPx = bitmap.GetPixel(scanX, scanY); bool bIsMatching = colorMatch.IsMatching(testPx); if (bDebugMode) { Logger.WriteLine(" [" + scanX + ", " + scanY + "] " + testPx + " => match:" + bIsMatching); } if (bIsMatching) { posHit = new Point(scanX, scanY); return(true); } } if (bDebugMode) { Logger.WriteLine(" >> failed"); } posHit = new Point(posX + (traceLen * incX), posY + (traceLen * incY)); return(false); }
public static Color GetColorFromHSV(FastPixelHSV pixel) { int R = 0, G = 0, B = 0; HsvToRgb(pixel.GetHue(), pixel.GetSaturation() / 100.0, pixel.GetValue() / 100.0, out R, out G, out B); return(Color.FromArgb(R, G, B)); }
public static float GetPixelFeaturesM2V2(FastPixelHSV testPx) { float monoV = testPx.GetMonochrome() / 255.0f; float valV = testPx.GetValue() / 100.0f; float pixelV = monoV * monoV * valV * valV; return(pixelV); }
public static Bitmap CreateBitmapWithShapes(FastBitmapHSV bitmap, List <Rectangle> listBounds, List <FastBitmapHash> listHashes) { Bitmap bmp = new Bitmap(bitmap.Width, bitmap.Height); unsafe { BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); int bytesPerPixel = Image.GetPixelFormatSize(bmp.PixelFormat) / 8; int bytesPerRow = bitmapData.Width * bytesPerPixel; for (int IdxY = 0; IdxY < bmp.Height; IdxY++) { byte *pixels = (byte *)bitmapData.Scan0 + (IdxY * bitmapData.Stride); for (int IdxByte = 0; IdxByte < bytesPerRow; IdxByte += bytesPerPixel) { FastPixelHSV writePx = bitmap.GetPixel(IdxByte / bytesPerPixel, IdxY); Color writeColor = Color.FromArgb(writePx.Monochrome, writePx.Monochrome, writePx.Monochrome); pixels[IdxByte + 3] = writeColor.A; pixels[IdxByte + 2] = writeColor.R; pixels[IdxByte + 1] = writeColor.G; pixels[IdxByte + 0] = writeColor.B; } } bmp.UnlockBits(bitmapData); } using (Graphics gBmp = Graphics.FromImage(bmp)) { if (listBounds.Count > 0) { Pen boundsPen = new Pen(Color.Cyan); gBmp.DrawRectangles(boundsPen, listBounds.ToArray()); } Pen hashPen = new Pen(Color.Magenta); foreach (FastBitmapHash hashData in listHashes) { gBmp.DrawRectangle(hashPen, hashData.SourceBounds); if (hashData.Pixels != null) { for (int HashX = 0; HashX < hashData.Width; HashX++) { for (int HashY = 0; HashY < hashData.Height; HashY++) { byte writeValue = hashData.Pixels[HashX + (HashY * hashData.Width)]; int writeValueInt = Math.Min(255, writeValue * 16); Color writeColor = Color.FromArgb(writeValueInt, 0, 0); bmp.SetPixel(HashX + hashData.DrawPos.X, HashY + hashData.DrawPos.Y, writeColor); } } } } } return(bmp); }
public static List <Point> TraceSpansH(FastBitmapHSV bitmap, Rectangle box, FastPixelMatch colorMatch, int minSize, bool bDebugMode = false) { List <Point> result = new List <Point>(); int lastX = -1; bool bHasMatch = false; for (int IdxX = box.Left; IdxX <= box.Right; IdxX++) { bHasMatch = false; for (int IdxY = box.Top; IdxY <= box.Bottom; IdxY++) { FastPixelHSV testPx = bitmap.GetPixel(IdxX, IdxY); bHasMatch = colorMatch.IsMatching(testPx); if (bHasMatch) { if (bDebugMode) { Logger.WriteLine("[" + IdxX + ", " + IdxY + "] " + testPx + " => match!"); } break; } } if (lastX == -1 && bHasMatch) { lastX = IdxX; } else if (lastX >= 0 && !bHasMatch) { int spanSize = IdxX - lastX; if (spanSize > minSize) { if (bDebugMode) { Logger.WriteLine(">> adding span: " + lastX + ", size:" + spanSize); } result.Add(new Point(lastX, spanSize)); } lastX = -1; } } if (lastX >= 0 && bHasMatch) { int spanSize = box.Right - lastX + 1; if (spanSize > minSize) { if (bDebugMode) { Logger.WriteLine(">> adding span: " + lastX + ", size:" + spanSize); } result.Add(new Point(lastX, spanSize)); } } return(result); }
public override bool IsMatching(FastPixelHSV pixel) { int Hue = pixel.GetHue(); int Saturation = pixel.GetSaturation(); return((Hue >= HueMin) && (Hue <= HueMax) && (Saturation >= SaturationMin) && (Saturation <= SaturationMax) && (pixel.Value >= ValueMin) && (pixel.Value <= ValueMax)); }
public override bool IsMatching(FastPixelHSV pixel) { if ((pixel.Monochrome >= MonoMin) && (pixel.Monochrome <= MonoMax)) { int Hue = pixel.GetHue(); return((Hue >= HueMin) && (Hue <= HueMax)); } return(false); }
public static void FindColorRange(FastBitmapHSV bitmap, Rectangle box, out int minMono, out int maxMono) { minMono = 255; maxMono = 0; for (int IdxY = box.Top; IdxY <= box.Bottom; IdxY++) { for (int IdxX = box.Left; IdxX <= box.Right; IdxX++) { FastPixelHSV testPx = bitmap.GetPixel(IdxX, IdxY); minMono = Math.Min(minMono, testPx.Monochrome); maxMono = Math.Max(maxMono, testPx.Monochrome); } } }
public static float GetPixelFeaturesHueMono(FastPixelHSV testPx) { const int hueSteps = 16; const int monoSteps = 16; const float monoScale = 1.0f / monoSteps; const float hueScale = monoScale / hueSteps; int hueV = testPx.GetHue() / (360 / hueSteps); int monoV = testPx.GetMonochrome() / (256 / monoSteps); float pixelV = (hueV * hueScale) + (monoV * monoScale); return(pixelV); }
public static float CountFillPct(FastBitmapHSV bitmap, Rectangle box, FastPixelMatch colorMatch) { int totalPixels = (box.Width + 1) * (box.Height + 1); int matchPixels = 0; for (int IdxY = box.Top; IdxY <= box.Bottom; IdxY++) { for (int IdxX = box.Left; IdxX <= box.Right; IdxX++) { FastPixelHSV testPx = bitmap.GetPixel(IdxX, IdxY); matchPixels += colorMatch.IsMatching(testPx) ? 1 : 0; } } return((float)matchPixels / totalPixels); }
public static FastPixelHSV GetAverageColor(FastBitmapHSV bitmap, Rectangle bounds) { float scale = 1.0f / (bounds.Width * bounds.Height); float accR = 0.0f; float accG = 0.0f; float accB = 0.0f; for (int idxY = 0; idxY < bounds.Height; idxY++) { for (int idxX = 0; idxX < bounds.Width; idxX++) { FastPixelHSV testPx = bitmap.GetPixelRaw(bounds.X + idxX, bounds.Y + idxY); accR += testPx.RawR; accG += testPx.RawG; accB += testPx.RawB; } } FastPixelHSV avgPx = new FastPixelHSV((byte)(accR * scale), (byte)(accG * scale), (byte)(accB * scale)); avgPx.ExpandHSV(); return(avgPx); }
public override bool IsMatching(FastPixelHSV pixel) { return((pixel.Monochrome >= MonoMin) && (pixel.Monochrome <= MonoMax)); }
public static Point TraceBoundsH(FastBitmapHSV bitmap, Rectangle box, FastPixelMatch colorMatch, int maxGapSize, bool bDebugMode = false) { int boxCenter = (box.Right + box.Left) / 2; int minX = -1; int gapStart = -1; bool bPrevMatch = false; for (int IdxX = box.Left; IdxX < boxCenter; IdxX++) { bool bHasMatch = false; for (int IdxY = box.Top; IdxY <= box.Bottom; IdxY++) { FastPixelHSV testPx = bitmap.GetPixel(IdxX, IdxY); bHasMatch = colorMatch.IsMatching(testPx); if (bHasMatch) { if (bDebugMode) { Logger.WriteLine("[" + IdxX + ", " + IdxY + "] " + testPx + " => match!"); } break; } } if (bHasMatch) { int gapSize = IdxX - gapStart; if ((gapSize > maxGapSize && gapStart > 0) || (minX < 0)) { minX = IdxX; gapStart = -1; } if (bDebugMode) { Logger.WriteLine(">> gapSize:" + gapSize + ", gapStart:" + gapStart + ", bPrevMatch:" + bPrevMatch + " => minX:" + minX); } } else { if (bPrevMatch) { gapStart = IdxX; if (bDebugMode) { Logger.WriteLine(">> gapStart:" + gapStart); } } } bPrevMatch = bHasMatch; } if (minX >= 0) { int maxX = -1; gapStart = -1; bPrevMatch = false; for (int IdxX = box.Right; IdxX > boxCenter; IdxX--) { bool bHasMatch = false; for (int IdxY = box.Top; IdxY <= box.Bottom; IdxY++) { FastPixelHSV testPx = bitmap.GetPixel(IdxX, IdxY); bHasMatch = colorMatch.IsMatching(testPx); if (bHasMatch) { if (bDebugMode) { Logger.WriteLine("[" + IdxX + ", " + IdxY + "] " + testPx + " => match!"); } break; } } if (bHasMatch) { int gapSize = gapStart - IdxX; if ((gapSize > maxGapSize && gapStart > 0) || (maxX < 0)) { maxX = IdxX; gapStart = -1; } if (bDebugMode) { Logger.WriteLine(">> gapSize:" + gapSize + ", gapStart:" + gapStart + ", bPrevMatch:" + bPrevMatch + " => maxX:" + maxX); } } else { if (bPrevMatch) { gapStart = IdxX; if (bDebugMode) { Logger.WriteLine(">> gapStart:" + gapStart); } } } bPrevMatch = bHasMatch; } if (maxX > minX) { return(new Point(minX, maxX - minX)); } else { if (bDebugMode) { Logger.WriteLine(">> TraceBoundsH: no match on right side!"); } } } else { if (bDebugMode) { Logger.WriteLine(">> TraceBoundsH: no match on left side!"); } } return(new Point()); }
public abstract bool IsMatching(FastPixelHSV pixel);
public static float GetPixelFeaturesMono(FastPixelHSV testPx) { return(testPx.GetMonochrome() / 255.0f); }
public static float GetPixelFeaturesHue(FastPixelHSV testPx) { return(testPx.GetHue() / 360.0f); }
public static List <int> TraceLineSegments(FastBitmapHSV bitmap, int posX, int posY, int incX, int incY, int traceLen, FastPixelMatch colorMatch, int minSegSize, int segLimit, bool bDebugMode = false) { FastPixelHSV[] streakBuffer = new FastPixelHSV[minSegSize]; int bufferIdx = 0; for (int Idx = 0; Idx < streakBuffer.Length; Idx++) { streakBuffer[Idx] = new FastPixelHSV(255, 255, 255); } List <int> result = new List <int>(); bool bWasMatch = false; if (bDebugMode) { Logger.WriteLine("TraceLineSegments [" + posX + ", " + posY + "] -> [" + (posX + (incX * traceLen)) + ", " + (posY + (incY * traceLen)) + "]"); } for (int stepIdx = 0; stepIdx < traceLen; stepIdx++) { int scanX = posX + (stepIdx * incX); int scanY = posY + (stepIdx * incY); FastPixelHSV testPx = bitmap.GetPixel(scanX, scanY); streakBuffer[bufferIdx] = testPx; bufferIdx = (bufferIdx + 1) % minSegSize; bool bBufferMatching = true; for (int Idx = 0; Idx < streakBuffer.Length; Idx++) { bBufferMatching = bBufferMatching && colorMatch.IsMatching(streakBuffer[Idx]); } if (bDebugMode) { Logger.WriteLine(" [" + scanX + ", " + scanY + "] " + testPx + " => match:" + colorMatch.IsMatching(testPx) + ", buffer:" + bBufferMatching); } if (bBufferMatching != bWasMatch) { bWasMatch = bBufferMatching; int segPos = bBufferMatching ? (incX != 0) ? (scanX - (incX * minSegSize)) : (scanY - (incY * minSegSize)) : (incX != 0) ? scanX : scanY; result.Add(segPos); if (bDebugMode) { Logger.WriteLine(" >> mark segment:" + segPos); } if (result.Count >= segLimit && segLimit > 0) { break; } } } return(result); }
public static float[] ExtractImageFeaturesScaled(FastBitmapHSV bitmap, Rectangle bounds, int destWidth, int destHeight, Func <FastPixelHSV, float> pxFunc) { float[] values = new float[destWidth * destHeight]; // scale to requested size float scaleX = (float)destWidth / bounds.Width; float scaleY = (float)destHeight / bounds.Height; float endY = 0.0f; for (int hashY = 0; hashY < destHeight; hashY++) { float startY = endY; endY = (hashY + 1) / scaleY; if (endY >= bounds.Height) { endY = bounds.Height - 0.00001f; } float endX = 0.0f; for (int hashX = 0; hashX < destWidth; hashX++) { float startX = endX; endX = (hashX + 1) / scaleX; if (endX >= bounds.Width) { endX = bounds.Width - 0.00001f; } float sum = 0.0f; float sumDiv = 0.00001f; for (int srcY = (int)startY; srcY <= (int)endY; srcY++) { float partY = 1.0f; if (srcY == (int)startY) { partY -= startY - srcY; } if (srcY == (int)endY) { partY -= srcY + 1 - endY; } for (int srcX = (int)startX; srcX <= (int)endX; srcX++) { float partX = 1.0f; if (srcX == (int)startX) { partX -= startX - srcX; } if (srcX == (int)endX) { partX -= srcX + 1 - endX; } FastPixelHSV testPx = bitmap.GetPixel(bounds.Left + srcX, bounds.Top + srcY); float testPxValue = pxFunc(testPx); sum += testPxValue * partY * partX; sumDiv += partY * partX; } } values[hashX + (hashY * destWidth)] = sum / sumDiv; } } return(values); }
public void SetPixel(int X, int Y, FastPixelHSV pixel) { Pixels[X + (Y * Width)] = pixel; }
private bool HasCactpotCircleEdgeV(FastBitmapHSV bitmap, int posX, int posY, int sideX, bool bDebugDetection = false) { const int spreadY = 2; const int offsetDeepX = 5; FastPixelHSV testPx = bitmap.GetPixel(posX, posY); if (!colorMatchCircleOut.IsMatching(testPx) && !colorMatchCircleOutH.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("HasCactpotCircleEdgeV[" + posX + "," + posY + "] failed: edge center " + testPx); } return(false); } testPx = bitmap.GetPixel(posX - (sideX * offsetDeepX), posY); if (!colorMatchCircleOut.IsMatching(testPx) && !colorMatchCircleOutH.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("HasCactpotCircleEdgeV[" + posX + "," + posY + "] failed: deep center " + testPx); } return(false); } testPx = bitmap.GetPixel(posX, posY - spreadY); if (!colorMatchCircleOut.IsMatching(testPx) && !colorMatchCircleOutH.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("HasCactpotCircleEdgeV[" + posX + "," + posY + "] failed: edge top " + testPx); } return(false); } testPx = bitmap.GetPixel(posX, posY + spreadY); if (!colorMatchCircleOut.IsMatching(testPx) && !colorMatchCircleOutH.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("HasCactpotCircleEdgeV[" + posX + "," + posY + "] failed: edge bottom " + testPx); } return(false); } testPx = bitmap.GetPixel(posX + sideX, posY); if (!colorMatchBack.IsMatching(testPx) && !colorMatchCircleFade.IsMatching(testPx) && !colorMatchCircleFadeH.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("HasCactpotCircleEdgeV[" + posX + "," + posY + "] failed: edge center prev " + testPx); } return(false); } testPx = bitmap.GetPixel(posX + sideX, posY - spreadY); if (!colorMatchBack.IsMatching(testPx) && !colorMatchCircleFade.IsMatching(testPx) && !colorMatchCircleFadeH.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("HasCactpotCircleEdgeV[" + posX + "," + posY + "] failed: edge top prev " + testPx); } return(false); } testPx = bitmap.GetPixel(posX + sideX, posY + spreadY); if (!colorMatchBack.IsMatching(testPx) && !colorMatchCircleFade.IsMatching(testPx) && !colorMatchCircleFadeH.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("HasCactpotCircleEdgeV[" + posX + "," + posY + "] failed: edge bottom prev " + testPx); } return(false); } return(true); }
public void SetPixel(int Idx, FastPixelHSV pixel) { Pixels[Idx] = pixel; }
public static bool CreateFloodFillBitmap(FastBitmapHSV srcBitmap, Point floodOrigin, Size floodExtent, FastPixelMatch colorMatch, out FastBitmapHSV floodBitmap, out Rectangle floodBounds, bool bDebugMode = false) { List <Point> floodPoints = new List <Point>(); int minX = floodOrigin.X; int maxX = floodOrigin.X; int minY = floodOrigin.Y; int maxY = floodOrigin.Y; Rectangle boundRect = new Rectangle(floodOrigin.X - floodExtent.Width, floodOrigin.Y - floodExtent.Height, floodExtent.Width * 2, floodExtent.Height * 2); Stack <Point> openList = new Stack <Point>(); openList.Push(floodOrigin); while (openList.Count > 0) { Point testPoint = openList.Pop(); if (floodPoints.Contains(testPoint)) { continue; } FastPixelHSV testPx = srcBitmap.GetPixel(testPoint.X, testPoint.Y); if (bDebugMode) { Logger.WriteLine("[" + testPoint.X + ", " + testPoint.Y + "] " + testPx + ", match:" + colorMatch.IsMatching(testPx) + ", inBounds:" + boundRect.Contains(testPoint)); } if (colorMatch.IsMatching(testPx) && boundRect.Contains(testPoint)) { floodPoints.Add(testPoint); minX = Math.Min(minX, testPoint.X); maxX = Math.Max(maxX, testPoint.X); minY = Math.Min(minY, testPoint.Y); maxY = Math.Max(maxY, testPoint.Y); openList.Push(new Point(testPoint.X - 1, testPoint.Y)); openList.Push(new Point(testPoint.X + 1, testPoint.Y)); openList.Push(new Point(testPoint.X, testPoint.Y - 1)); openList.Push(new Point(testPoint.X, testPoint.Y + 1)); openList.Push(new Point(testPoint.X - 1, testPoint.Y - 1)); openList.Push(new Point(testPoint.X + 1, testPoint.Y - 1)); openList.Push(new Point(testPoint.X - 1, testPoint.Y + 1)); openList.Push(new Point(testPoint.X + 1, testPoint.Y + 1)); } } floodBounds = new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1); if (floodPoints.Count > 0) { FastPixelHSV[] bitmapPixels = new FastPixelHSV[floodBounds.Width * floodBounds.Height]; for (int Idx = 0; Idx < bitmapPixels.Length; Idx++) { bitmapPixels[Idx] = new FastPixelHSV(false); } foreach (Point p in floodPoints) { int Idx = (p.X - minX) + ((p.Y - minY) * floodBounds.Width); bitmapPixels[Idx] = new FastPixelHSV(true); } floodBitmap = new FastBitmapHSV() { Pixels = bitmapPixels, Width = floodBounds.Width, Height = floodBounds.Height, }; } else { floodBitmap = null; } return(floodBitmap != null); }
public static int FindPatternMatch(FastBitmapHSV bitmap, Point pos, FastPixelMatch colorMatch, List <ImagePatternDigit> patterns, out ImageDataDigit digitData, bool bDebugMode = false) { int bestValue = 0; int bestValueExact = 0; float totalBestScore = 0; float totalBestScoreExact = 0; const int offsetSize = 5; const int cacheWidth = offsetSize + 10 + offsetSize; const int cacheHeight = offsetSize + 8 + offsetSize; byte[] PixelMatch = new byte[cacheWidth * cacheHeight]; int bestPatternMatchX = 0; int bestPatternExactX = 0; int bestPatternMatchY = 0; int bestPatternExactY = 0; foreach (ImagePatternDigit pattern in patterns) { float bestScore = 0; float bestScoreExact = 0; int bestPosX = 0; int bestPosXExact = 0; int bestPosY = 0; int bestPosYExact = 0; int ByteIdx = 0; for (int IdxY = 0; IdxY < cacheHeight; IdxY++) { for (int IdxX = 0; IdxX < cacheWidth; IdxX++) { FastPixelHSV testPx = bitmap.GetPixel(pos.X + IdxX - offsetSize, pos.Y + IdxY - offsetSize); PixelMatch[ByteIdx] = colorMatch.IsMatching(testPx) ? (byte)1 : (byte)0; ByteIdx++; } } /*if (bDebugMode) * { * bestPosX = 894; * bestPosY = 615; * bestScore = HasPatternMatch(PixelMatch, bestPosX - pos.X + offsetSize, bestPosY - pos.Y + offsetSize, cacheWidth, * pattern, pattern.Value == 3 || pattern.Value == 5 || pattern.Value == 8); * } * else*/ { for (int offsetX = -offsetSize; offsetX <= offsetSize; offsetX++) { for (int offsetY = -offsetSize; offsetY <= offsetSize; offsetY++) { float testScore = HasPatternMatch(PixelMatch, offsetX + offsetSize, offsetY + offsetSize, cacheWidth, false, pattern); if (testScore > bestScore) { bestPosX = pos.X + offsetX; bestPosY = pos.Y + offsetY; bestScore = testScore; } float testScoreExact = HasPatternMatch(PixelMatch, offsetX + offsetSize, offsetY + offsetSize, cacheWidth, true, pattern); if (testScoreExact > bestScoreExact) { bestPosXExact = pos.X + offsetX; bestPosYExact = pos.Y + offsetY; bestScoreExact = testScoreExact; } } } } if (bestScore > totalBestScore) { totalBestScore = bestScore; bestValue = pattern.Value; bestPatternMatchX = bestPosX - pos.X + offsetSize; bestPatternMatchY = bestPosY - pos.Y + offsetSize; } if (bestScoreExact > totalBestScoreExact) { totalBestScoreExact = bestScoreExact; bestValueExact = pattern.Value; bestPatternExactX = bestPosXExact - pos.X + offsetSize; bestPatternExactY = bestPosYExact - pos.Y + offsetSize; } if (bDebugMode) { Logger.WriteLine("FindPatternMatch: " + pattern.Value + " best at (" + bestPosX + ", " + bestPosY + ") = " + (int)(100 * bestScore) + "%," + " exact at (" + bestPosXExact + ", " + bestPosYExact + ") = " + (int)(100 * bestScoreExact) + "%"); } } { byte[] digitDataPixels = new byte[10]; for (int IdxX = 0; IdxX < 10; IdxX++) { int Value = 0; int ByteIdx = (bestPatternMatchY * cacheWidth) + bestPatternMatchX + IdxX; for (int IdxY = 0; IdxY < 8; IdxY++) { Value |= (PixelMatch[ByteIdx + (IdxY * cacheWidth)] != 0) ? (1 << IdxY) : 0; } digitDataPixels[IdxX] = (byte)Value; } digitData = new ImageDataDigit(digitDataPixels); if (bDebugMode) { for (int IdxY = 0; IdxY < 8; IdxY++) { string debugDesc = ""; for (int IdxX = 0; IdxX < 10; IdxX++) { byte ColValue = digitDataPixels[IdxX]; byte RowMask = (byte)(1 << IdxY); debugDesc += ((ColValue & RowMask) != 0 ? "#" : ".") + " "; } Logger.WriteLine(debugDesc); } } } return((totalBestScoreExact > 0.95) ? bestValueExact : (totalBestScore > 0.8) ? bestValue : 0); }
public static FastBitmapHash CalculateImageHash(FastBitmapHSV bitmap, Rectangle box, Rectangle contextBox, FastPixelMatch colorMatch, int hashWidth, int hashHeight, bool bNormalizeColors = false) { byte[] hashImage = new byte[hashWidth * hashHeight]; // scale to requested size float scaleX = (float)hashWidth / box.Width; float scaleY = (float)hashHeight / box.Height; float endY = 0.0f; for (int hashY = 0; hashY < hashHeight; hashY++) { float startY = endY; endY = (hashY + 1) / scaleY; if (endY >= box.Height) { endY = box.Height - 0.00001f; } float endX = 0.0f; for (int hashX = 0; hashX < hashWidth; hashX++) { float startX = endX; endX = (hashX + 1) / scaleX; if (endX >= box.Width) { endX = box.Width - 0.00001f; } float sum = 0.0f; int sumDivNum = 0; for (int srcY = (int)startY; srcY <= (int)endY; srcY++) { float partY = 1.0f; if (srcY == (int)startY) { partY -= startY - srcY; } if (srcY == (int)endY) { partY -= srcY + 1 - endY; } for (int srcX = (int)startX; srcX <= (int)endX; srcX++) { float partX = 1.0f; if (srcX == (int)startX) { partX -= startX - srcX; } if (srcX == (int)endX) { partX -= srcX + 1 - endX; } FastPixelHSV valuePx = bitmap.GetPixel(box.Left + srcX, box.Top + srcY); float srcValueNorm = colorMatch.IsMatching(valuePx) ? (bNormalizeColors ? 1.0f : (valuePx.Monochrome / 255.0f)) : 0.0f; sum += srcValueNorm * partY * partX; sumDivNum++; } } float storeValueNorm = sum / sumDivNum; hashImage[hashX + (hashY * hashWidth)] = (byte)Math.Min(15, 15 * storeValueNorm); } } TlshBuilder hashBuilder = new TlshBuilder(); hashBuilder.Update(hashImage); TlshHash complexHash = hashBuilder.IsValid(false) ? hashBuilder.GetHash(false) : null; ScanLineHash simpleHash = ScanLineHash.CreateFromImage(hashImage, hashWidth, hashHeight); HashCollection hashCollection = new HashCollection(complexHash, simpleHash); return(new FastBitmapHash { Hash = hashCollection, Height = hashHeight, Width = hashWidth, Pixels = hashImage, SourceBounds = box, ContextBounds = contextBox, DrawPos = new Point(box.Right + 1, box.Top), }); }
private bool HasCactpotCircleMatch(FastBitmapHSV bitmap, int posX, int posY, int cellSize, int offsetIn, bool bDebugDetection = false) { int sizeA = cellSize; int offsetB = Math.Max(5, offsetIn - 2); int sizeB = sizeA - (offsetB * 2); Point[] testPoints = new Point[4]; int numHighlights = 0; // 4 points: corners of cell => dark background { testPoints[0].X = posX; testPoints[0].Y = posY; testPoints[1].X = posX + sizeA; testPoints[1].Y = posY; testPoints[2].X = posX; testPoints[2].Y = posY + sizeA; testPoints[3].X = posX + sizeA; testPoints[3].Y = posY + sizeA; for (int Idx = 0; Idx < 4; Idx++) { FastPixelHSV testPx = bitmap.GetPixel(testPoints[Idx].X, testPoints[Idx].Y); //if (bDebugDetection) { Logger.WriteLine("[" + posX + ", " + posY + "] testing A[" + testPoints[Idx].X + "," + testPoints[Idx].Y + "]: " + testPx); } if (!colorMatchBack.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("[" + posX + ", " + posY + "] failed, not background: A[" + testPoints[Idx].X + "," + testPoints[Idx].Y + "]: " + testPx); } return(false); } } } // 4 points: corners with offset B => dark background { testPoints[0].X = posX + offsetB; testPoints[0].Y = posY + offsetB; testPoints[1].X = posX + sizeA - offsetB; testPoints[1].Y = posY + offsetB; testPoints[2].X = posX + offsetB; testPoints[2].Y = posY + sizeA - offsetB; testPoints[3].X = posX + sizeA - offsetB; testPoints[3].Y = posY + sizeA - offsetB; for (int Idx = 0; Idx < 4; Idx++) { FastPixelHSV testPx = bitmap.GetPixel(testPoints[Idx].X, testPoints[Idx].Y); //if (bDebugDetection) { Logger.WriteLine("[" + posX + ", " + posY + "] testing B1[" + testPoints[Idx].X + "," + testPoints[Idx].Y + "]: " + testPx); } if (!colorMatchBack.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("[" + posX + ", " + posY + "] failed, not background: B1[" + testPoints[Idx].X + "," + testPoints[Idx].Y + "]: " + testPx); } return(false); } } } Point[] testPointCloser = new Point[4]; // 4 points: midpoints with offset B => yellow/white { testPoints[0].X = posX + offsetB; testPoints[0].Y = posY + (sizeA / 2); testPoints[1].X = posX + sizeA - offsetB; testPoints[1].Y = posY + (sizeA / 2); testPoints[2].X = posX + (sizeA / 2); testPoints[2].Y = posY + offsetB; testPoints[3].X = posX + (sizeA / 2); testPoints[3].Y = posY + sizeA - offsetB; for (int Idx = 0; Idx < 4; Idx++) { FastPixelHSV testPx = bitmap.GetPixel(testPoints[Idx].X, testPoints[Idx].Y); //if (bDebugDetection) { Logger.WriteLine("[" + posX + ", " + posY + "] testing B2[" + testPoints[Idx].X + "," + testPoints[Idx].Y + "]: " + testPx); } if (colorMatchCircleOutH.IsMatching(testPx)) { numHighlights++; } else if (!colorMatchCircleOut.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("[" + posX + ", " + posY + "] failed, not circle: B2[" + testPoints[Idx].X + "," + testPoints[Idx].Y + "]: " + testPx); } return(false); } } } // 4 points: midpoints of diagonal lines between midpoints B (C) => yellow/white { testPoints[0].X = posX + offsetB + (sizeB / 4); testPoints[0].Y = posY + offsetB + (sizeB / 4); testPoints[1].X = posX + sizeA - offsetB - (sizeB / 4); testPoints[1].Y = posY + offsetB + (sizeB / 4); testPoints[2].X = posX + offsetB + (sizeB / 4); testPoints[2].Y = posY + sizeA - offsetB - (sizeB / 4); testPoints[3].X = posX + sizeA - offsetB - (sizeB / 4); testPoints[3].Y = posY + sizeA - offsetB - (sizeB / 4); for (int Idx = 0; Idx < 4; Idx++) { FastPixelHSV testPx = bitmap.GetPixel(testPoints[Idx].X, testPoints[Idx].Y); //if (bDebugDetection) { Logger.WriteLine("[" + posX + ", " + posY + "] testing B3[" + testPoints[Idx].X + "," + testPoints[Idx].Y + "]: " + testPx); } if (!colorMatchCircleIn.IsMatching(testPx)) { if (bDebugDetection) { Logger.WriteLine("[" + posX + ", " + posY + "] failed, not circle: B3[" + testPoints[Idx].X + "," + testPoints[Idx].Y + "]: " + testPx); } return(false); } } } return((numHighlights == 0) || (numHighlights == 4)); }