public static IntField BackgroundFilterSmall(IntField image, int areaThresh) { image = image.Clone(); IntField processed = image.Clone(); // 0..3 - original unprocessed colors // -1 - accepted as background // -2 - trial fill / kept for later elimination for (int y = 0; y < image.Height; y++) { for (int x = 0; x < image.Width; x++) { if (processed[x, y] >= 0) { // Do trial fill processed.Floodfill(x, y, -2); // Accept as background? if (processed.Counter_Floodfill_TotalPixels > areaThresh) { processed.Floodfill(x, y, -1); } } } } for (int p = 0; p < image.Data.Length; p++) { if (processed.Data[p] == -2) { image.Data[p] = -2; } } for (int y = 0; y < image.Height; y++) { for (int x = 0; x < image.Width; x++) { if (processed[x, y] == -2) { if (x > 0 && processed[x - 1, y] == -1) { image.Floodfill(x, y, image[x - 1, y]); processed.Floodfill(x, y, -3); } else if (y > 0 && processed[x, y - 1] == -1) { image.Floodfill(x, y, image[x, y - 1]); processed.Floodfill(x, y, -3); } else if (x < image.Width - 1 && processed[x + 1, y] == -1) { image.Floodfill(x, y, image[x + 1, y]); processed.Floodfill(x, y, -3); } else if (y < image.Height - 1 && processed[x, y + 1] == -1) { image.Floodfill(x, y, image[x, y + 1]); processed.Floodfill(x, y, -3); } } } } return(image); }
private void backgroundSplit(IntField image, out IntField backgr, out IntField foregr) { IntField largeBackgrMap; // First pass: all large areas are always backgrounds { IntField vis_hitpoints = image.Clone(); largeBackgrMap = image.Clone(); int x = 0, y = 0, xfr = 0; double yd = 0; double ystep = _backgrLargeStepSize * 0.866 / ((double)image.Width / _backgrLargeStepSize); int curfill = -2; while (true) { y = (int)yd; if (y >= image.Height) { break; } vis_hitpoints[x, y] = 10; if (largeBackgrMap[x, y] >= 0) { largeBackgrMap.Floodfill(x, y, curfill); curfill--; if (largeBackgrMap.Counter_Floodfill_TotalPixels > _backgrLargeAreaThresh) { largeBackgrMap.Floodfill(x, y, -1); } } yd += ystep; x += _backgrLargeStepSize; if (x >= image.Width) { xfr += _backgrLargeStepSize / 3; if (xfr > _backgrLargeStepSize) { xfr -= _backgrLargeStepSize; } x = xfr; } } largeBackgrMap.Map(pix => pix == -1 ? 1 : 0); AddImageGrayscale(vis_hitpoints, "10-bkg-large-hitpoints"); AddImageGrayscale(largeBackgrMap, "11-bkg-large-map"); } // TODO: also background if perfectly rectangular and larger than 4 area // Second pass - background continuation { // Prepare image backgr = image.Clone(); for (int p = 0; p < image.Data.Length; p++) { if (largeBackgrMap.Data[p] == 0) { backgr.Data[p] = -1; } } AddImageGrayscale(backgr, -1, 3, "12-bkg-cont-before"); // Horizontal continuation for (int y = 0; y < backgr.Height; y++) { int lastbg = -1; int lastfgstart = -1; // -1 means not in a foreground run int x = 0; while (true) { if (lastfgstart != -1 && (x == backgr.Width || backgr[x, y] != -1)) { // in a fg run and either end of image or end of run (no longer foreground) if (lastbg == -1 || x == backgr.Width || lastbg == backgr[x, y]) { int clr = x == backgr.Width ? lastbg : backgr[x, y]; for (int fx = lastfgstart; fx < x; fx++) { backgr[fx, y] = clr; } } lastfgstart = -1; } if (x == backgr.Width) { break; } if (lastfgstart == -1 && backgr[x, y] == -1) { lastfgstart = x; lastbg = x == 0 ? -1 : backgr[x - 1, y]; } x++; } } AddImageGrayscale(backgr, -1, 3, "13-bkg-cont-horz"); // Vertical continuation for (int x = 0; x < backgr.Width; x++) { int lastbg = -1; int lastfgstart = -1; // -1 means not in a foreground run int y = 0; while (true) { if (lastfgstart != -1 && (y == backgr.Height || backgr[x, y] != -1)) { // in a fg run and either end of image or end of run (no longer foreground) if (lastbg == -1 || y == backgr.Height || lastbg == backgr[x, y]) { int clr = y == backgr.Height ? lastbg : backgr[x, y]; for (int fy = lastfgstart; fy < y; fy++) { backgr[x, fy] = clr; } } lastfgstart = -1; } if (y == backgr.Height) { break; } if (lastfgstart == -1 && backgr[x, y] == -1) { lastfgstart = y; lastbg = y == 0 ? -1 : backgr[x, y - 1]; } y++; } } AddImageGrayscale(backgr, -1, 3, "14-bkg-cont-vert"); // Continuation of leftover areas int lastc = -1; for (int p = 0; p < backgr.Data.Length; p++) { if (backgr.Data[p] == -1 && lastc != -1) { backgr.Floodfill(p % backgr.Width, p / backgr.Width, lastc); } else if (p > 0 && backgr.Data[p - 1] == -1 && backgr.Data[p] != -1) { backgr.Floodfill((p - 1) % backgr.Width, (p - 1) / backgr.Width, backgr.Data[p]); } if (backgr.Data[p] != -1) { lastc = backgr.Data[p]; } } // TODO: remove anything that's highly non-rect AddImageGrayscale(backgr, 0, 3, "15-final-bkg"); } // Final pass - extract foreground { foregr = image.Clone(); for (int p = 0; p < image.Data.Length; p++) { foregr.Data[p] ^= backgr.Data[p]; } AddImageGrayscale(foregr, 0, 3, "16-final-fgr"); } }