// Lookup table to speed up the last phase of G22RegionThinner_v2. // There are 256 possible neighborhood images for a 3x3 neighborhood // excluding the central pixel. // For each of these, we store whether the central pixel should be // deleted (bit is 1 = deletable) sclass G22RegionThinner_LookupTable { byte[] table; settable int lastPhaseThreshold1 = 2; settable int lastPhaseThreshold = 5; static byte[] defaultTable = null/*bytesFromHex( "80c8c84c00ce0004004e5c17000715010000dc04000000000007150101031100" )*/; // for debugging L> regions; int sides; byte[] get aka table aka getTable() { if (table == null) { if (defaultTable != null && lastPhaseThreshold1 == 2 && lastPhaseThreshold == 5) table = defaultTable; else { table = new byte[256/8]; for imgPattern to 256: setBit(table, imgPattern, calculatePattern(imgPattern)); } } ret table; } S toHex() { ret bytesToHex(table()); } // imgPattern bit set = black bool calculatePattern(int imgPattern) { // special case "cross" (don't delete center point) if (imgPattern == 0b01011010) false; Image2B img = new(3, 3); imgPattern = ~imgPattern; img.setPixel(0, 0, testBit(imgPattern, 0)); img.setPixel(1, 0, testBit(imgPattern, 1)); img.setPixel(2, 0, testBit(imgPattern, 2)); img.setPixel(0, 1, testBit(imgPattern, 3)); img.setPixel(1, 1, true); img.setPixel(2, 1, testBit(imgPattern, 4)); img.setPixel(0, 2, testBit(imgPattern, 5)); img.setPixel(1, 2, testBit(imgPattern, 6)); img.setPixel(2, 2, testBit(imgPattern, 7)); var bwImage = img.toBW(); FastRegions_BWImage regionMaker = new(bwImage); regionMaker.withDiagonals(true); regionMaker.run(); // get all the black regions out of the 3x3 image regions = regionMaker.regions(); regions = filter(regions, r -> r.brightness() == 0); bool delete = false; int pixels = 0; // no regions? it's a lonely pixel - keep it if (empty(regions)) {} else if (l(regions) == 1) { // one region pixels = first(regions).numberOfPixels(); // if it's only one or two pixels, we are at the end of a line - keep if (pixels <= lastPhaseThreshold1) delete = false; else { // delete pixel if the region is small, but not too small // (lastPhaseThreshold is 5 by default) if (pixels < lastPhaseThreshold) delete = true; else if (pixels == lastPhaseThreshold) { // if it's exactly 5 pixels, check out how far // the region "surrounds" the pixel (does it touch 2 or 3 sides?) // delete pixel if it is not surrounded sides = 4-(int) (bwImage.getFloatPixel(1, 0) + bwImage.getFloatPixel(0, 1) + bwImage.getFloatPixel(2, 1) + bwImage.getFloatPixel(1, 2)); delete = sides <= 3; // XXX - formerly: < 3 } } } else // we have more than one region - pixel was // structurally important, keep it {} ret delete; } }