# HG changeset patch # User Jason Maltzen # Date 2016-03-04 05:37:20 # Node ID f2fafa9734f55f72e67c52a595a6563d5d90ee1c # Parent 7fae58ff4646e67433d1d26bf2c0e91647d1ce84 Update code to detect paint swatch - increase the range allowed for papyrus, but by more detailed in looking for the top/left border of the swatch. diff --git a/ReactionRecorder.cs b/ReactionRecorder.cs --- a/ReactionRecorder.cs +++ b/ReactionRecorder.cs @@ -29,24 +29,31 @@ namespace DesertPaintLab { const int COLOR_TOLERANCE = 3; - const int DEFAULT_SWATCH_HEIGHT = 24; + const int DEFAULT_SWATCH_HEIGHT = 24; // including top and bottom borders const int DEFAULT_SWATCH_WIDTH = 260; const int DEFAULT_COLOR_BAR_WIDTH = 306; const int DEFAULT_RED_BAR_SPACING = 32; const int DEFAULT_GREEN_BAR_SPACING = 42; const int DEFAULT_BLUE_BAR_SPACING = 52; + const int DEFAULT_SWATCH_TEST_WIDTH = 26; // width to test on ends of swatch (10% on either end) + static int swatchHeight = DEFAULT_SWATCH_HEIGHT; static int swatchWidth = DEFAULT_SWATCH_WIDTH; + static int swatchTestWidth = DEFAULT_SWATCH_TEST_WIDTH; static int colorBarWidth = DEFAULT_COLOR_BAR_WIDTH; static int redBarSpacing = DEFAULT_RED_BAR_SPACING; static int greenBarSpacing = DEFAULT_GREEN_BAR_SPACING; static int blueBarSpacing = DEFAULT_BLUE_BAR_SPACING; + static int pixelMultiplier = 1; private static bool IsPapyTexture(byte r, byte g, byte b) { - return ((r > 0xD0) && (g >= 0xC4) && (b >= 0x91)) && - ((r < 0xF4) && (g <= 0xED) && (b <= 0xCD)); + // red between 208 and 244 + // green between 192 and 237 + // blue between 145 and 205 + return ((r > 0xD0) && (g >= 0xC0) && (b >= 0x91)) && + ((r < 0xF4) && (g <= 0xED) && (b <= 0xCD)); } public static void SetPixelMultiplier(int pixelMultiplier) @@ -57,6 +64,8 @@ namespace DesertPaintLab redBarSpacing = DEFAULT_RED_BAR_SPACING * pixelMultiplier; greenBarSpacing = DEFAULT_GREEN_BAR_SPACING * pixelMultiplier; blueBarSpacing = DEFAULT_BLUE_BAR_SPACING * pixelMultiplier; + swatchTestWidth = DEFAULT_SWATCH_TEST_WIDTH * pixelMultiplier; + ReactionRecorder.pixelMultiplier = pixelMultiplier; } unsafe private static void ColorAt(byte *pixBytes, int x, int y, int stride, out byte r, out byte g, out byte b) @@ -67,7 +76,19 @@ namespace DesertPaintLab b = pixBytes[pixelStart + 2]; } - unsafe private static bool IsPossibleBorderPixel(byte* pixBytes, int x, int y, int stride) + private static bool IsDarkPixel(int r, int g, int b) + { + return ((r < 0x46) && (g < 0x46) && (b < 0x47)); + } + + private static bool IsColorMatch(byte test_r, byte test_g, byte test_b, byte target_r, byte target_g, byte target_b) + { + return ((Math.Abs(test_r - target_r) <= COLOR_TOLERANCE) && + (Math.Abs(test_g - target_g) <= COLOR_TOLERANCE) && + (Math.Abs(test_b - target_b) <= COLOR_TOLERANCE)); + } + + unsafe private static bool IsPossibleSwatchSlice(byte* pixBytes, int x, int y, int stride) { int testPixelStart = (y * stride) + (x * 3); byte r = pixBytes[testPixelStart]; @@ -77,21 +98,60 @@ namespace DesertPaintLab bool isDarkPixel = false; bool isPapyAbove = false; bool isPapyBelow = false; - // 1.) Check if this is a dark pixel. - isDarkPixel = ((r < 0x46) && (g < 0x46) && (b < 0x46)); + + // 1.) Check if the top pixel is a dark pixel. + isDarkPixel = IsDarkPixel(r, g, b); // ((r < 0x46) && (g < 0x46) && (b < 0x46)); - // 2.) Check the pixel above it, - // to see if it's from the papy texture. + // 2.) Check the pixel above it to see if it's from the papy texture. int otherPixelStart = testPixelStart - stride; isPapyAbove = ((otherPixelStart >= 0) && IsPapyTexture(pixBytes[otherPixelStart++], pixBytes[otherPixelStart++], pixBytes[otherPixelStart])); - // 3.) Check the pixel below where the swatch should be, - // to see if it's also from the papy texture. + // 3.) Check the pixel below where the swatch should be to see if it's also from the papy texture. otherPixelStart = testPixelStart + (stride * swatchHeight); isPapyBelow = (IsPapyTexture(pixBytes[otherPixelStart++], pixBytes[otherPixelStart++], pixBytes[otherPixelStart])); bool result = isDarkPixel && isPapyAbove && isPapyBelow; + + // grab the swatch color + int swatchColorStart = testPixelStart + (2 * pixelMultiplier * stride); // 2 rows below the test pixel, skipping the faded color + r = pixBytes[swatchColorStart]; + g = pixBytes[swatchColorStart+1]; + b = pixBytes[swatchColorStart+2]; + + // scan the column from 2 below the top to 2 above the bottom to ensure the color matches + for (int i = (2*pixelMultiplier); result && (i < swatchHeight-(2*pixelMultiplier)); ++i) + { + otherPixelStart = testPixelStart + (stride * i); + result &= IsColorMatch(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2], r, g, b); + } + + return result; + } + + unsafe private static bool IsPossibleSwatchUpperLeft(byte* pixBytes, int x, int y, int stride) + { + int testPixelStart = (y * stride) + (x * 3); + + bool result = true; + // test the left edge for dark pixels + for (int i = 0; result && (i < swatchHeight-pixelMultiplier); ++i) + { + int otherPixelStart = testPixelStart + (stride * i); + result &= IsDarkPixel(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]); + } + + // test the dark top border and for papyrus below the swatch + for (int i = 0; result && (i < swatchWidth); ++i) + { + int otherPixelStart = testPixelStart + (3 * i); + result &= IsDarkPixel(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]); + otherPixelStart = otherPixelStart - stride; + result &= IsPapyTexture(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]); + otherPixelStart = testPixelStart + (stride * swatchHeight) + (3 * i); + result &= IsPapyTexture(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]); + } + return result; } @@ -102,7 +162,7 @@ namespace DesertPaintLab bool colorMatch = true; for (int x = 0; x < screenshotWidth - colorBarWidth; ++x) { - for (int y = 0; y < (screenshotHeight - 53); ++y) + for (int y = 0; y < (screenshotHeight - (blueBarSpacing + 1) /*53*/); ++y) { // Look for the color swatch. pixelStart = (y * stride) + (x * 3); @@ -110,13 +170,14 @@ namespace DesertPaintLab pixel_g = pixBytes[pixelStart + 1]; pixel_b = pixBytes[pixelStart + 2]; - bool foundSwatch = IsPossibleBorderPixel(pixBytes, x, y, stride); // ((pixel_r < 0x46) && (pixel_g < 0x46) && (pixel_b < 0x46)); + bool foundSwatch = IsPossibleSwatchUpperLeft(pixBytes, x, y, stride); // ((pixel_r < 0x46) && (pixel_g < 0x46) && (pixel_b < 0x46)); if (foundSwatch) { int borderXOffset = 0; - for (borderXOffset = 0; foundSwatch && (borderXOffset < swatchWidth); ++borderXOffset) + for (borderXOffset = (2 * pixelMultiplier); foundSwatch && (borderXOffset < swatchTestWidth); ++borderXOffset) { - foundSwatch &= IsPossibleBorderPixel(pixBytes, x + borderXOffset, y, stride); + foundSwatch &= IsPossibleSwatchSlice(pixBytes, x + borderXOffset, y, stride); + foundSwatch &= IsPossibleSwatchSlice(pixBytes, x + swatchWidth - borderXOffset, y, stride); } } @@ -129,9 +190,7 @@ namespace DesertPaintLab for (int i = 1; i < swatchHeight - 2; ++i) { otherPixelStart = pixelStart + (stride * i); - if ((Math.Abs(pixel_r - pixBytes[otherPixelStart++]) > COLOR_TOLERANCE) || - (Math.Abs(pixel_g - pixBytes[otherPixelStart++]) > COLOR_TOLERANCE) || - (Math.Abs(pixel_b - pixBytes[otherPixelStart]) > COLOR_TOLERANCE)) + if (!IsColorMatch(pixel_r, pixel_g, pixel_b, pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2])) { colorMatch = false; break; diff --git a/gtk-gui/gui.stetic b/gtk-gui/gui.stetic --- a/gtk-gui/gui.stetic +++ b/gtk-gui/gui.stetic @@ -6,7 +6,7 @@ - +