public override void Encode(IntField image, Stream output) { image.ArgbTo4c(); IntField orig = image.Clone(); //image.PredictionEnTransformXor(new HorzVertForeseer()); //IntField backgr = CodecUtil.BackgroundFilterThin(image, 2, 2); IntField backgr = CodecUtil.BackgroundFilterSmall(image, 50); AddImageGrayscale(image, "orig"); AddImageGrayscale(backgr, "backgr"); for (int p = 0; p < image.Data.Length; p++) { image.Data[p] ^= backgr.Data[p]; } AddImageGrayscale(image, "foregr"); for (int i = 1; i <= 3; i++) { IntField field = image.Clone(); field.Conditional(pix => pix == i); int[] syms = CodecUtil.LzwLinesEn(field, 4, 1); AddImageGrayscale(field, "field{0}-{1}syms-max{2}".Fmt(i, syms.Length, syms.Max())); } }
public void AddImageGrayscale(IntField image, int min, int max, string caption) { IntField temp = image.Clone(); temp.ArgbFromField(min, max); Images.Add(new Tuple <string, IntField>(caption, temp)); }
public static int[] FieldcodeRunlengthsEn2(IntField image, SymbolCodec runlengthCodec, Compressor compr) { compr.AddImageGrayscale(image, 0, 3, "xformed"); List <int> data = new List <int>(); for (int i = 1; i <= 3; i++) { IntField temp = image.Clone(); temp.Map(x => x == i ? 1 : 0); data.AddRange(temp.Data); compr.AddImageGrayscale(temp, 0, 1, "field" + i); } var runs = runlengthCodec.Encode(data.ToArray()); compr.SetCounter("runs", runs.Length); return(runs); }
public static List <int[]> FieldcodeRunlengthsEn(IntField image, SymbolCodec runlengthCodec, Compressor compr) { compr.AddImageGrayscale(image, 0, 3, "xformed"); var fields = new List <int[]>(); for (int i = 1; i <= 3; i++) { IntField temp = image.Clone(); temp.Map(x => x == i ? 1 : 0); var field = runlengthCodec.Encode(temp.Data); CodecUtil.Shift(field, 1); compr.SetCounter("symbols|field-" + i, field.Length); fields.Add(field); compr.AddImageGrayscale(temp, 0, 1, "field" + i); } return(fields); }
public override void Encode(IntField image, Stream output) { // Predictive transform image.ArgbTo4c(); image.PredictionEnTransformXor(Seer); // Convert to three fields' runlengths for (int i = 1; i <= 3; i++) { IntField temp = image.Clone(); temp.Map(x => x == i ? 1 : 0); AddImageGrayscale(temp, 0, 1, "field" + i); var runs = new RunLength01SplitCodec().EncodeSplit(temp.Data); SetCounter("runs|field{0}|0s".Fmt(i), runs.Item1.Count); SetCounter("runs|field{0}|1s".Fmt(i), runs.Item2.Count); AddIntDump("field{0}-0s".Fmt(i), runs.Item1); AddIntDump("field{0}-1s".Fmt(i), runs.Item2); } }
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); }
public static IntField BackgroundFilterThin(IntField image, int w1passes, int w2passes) { image = image.Clone(); bool changed = true; int counter = 0; while (changed) { changed = false; for (int y = 0; y < image.Height; y++) { for (int x = 1; x < image.Width - 1; x++) { if (image[x - 1, y] == image[x + 1, y] && image[x, y] != image[x - 1, y]) { image[x, y] = image[x - 1, y]; changed = true; } } } for (int x = 0; x < image.Width; x++) { for (int y = 1; y < image.Height - 1; y++) { if (image[x, y - 1] == image[x, y + 1] && image[x, y] != image[x, y - 1]) { image[x, y] = image[x, y - 1]; changed = true; } } } counter++; if (counter >= w1passes) { break; } } changed = true; counter = 0; while (changed) { changed = false; for (int y = 0; y < image.Height; y++) { for (int x = 2; x < image.Width - 1; x++) { if (image[x - 2, y] == image[x + 1, y] && image[x, y] != image[x - 2, y]) { image[x, y] = image[x - 2, y]; changed = true; } if (image[x - 2, y] == image[x + 1, y] && image[x - 1, y] != image[x - 2, y]) { image[x - 1, y] = image[x - 2, y]; changed = true; } } } for (int x = 0; x < image.Width; x++) { for (int y = 2; y < image.Height - 1; y++) { if (image[x, y - 2] == image[x, y + 1] && image[x, y - 1] != image[x, y - 2]) { image[x, y - 1] = image[x, y - 2]; changed = true; } } } counter++; if (counter >= w2passes) { break; } } return(image); }
private void saveColors(IntField foregr) { var clr = foregr.Data.Where(pix => pix > 0).ToArray(); Tuple <int, int>[] cc = new Tuple <int, int> [3]; cc[0] = new Tuple <int, int>(clr.Where(pix => pix == 1).Count(), 1); cc[1] = new Tuple <int, int>(clr.Where(pix => pix == 2).Count(), 2); cc[2] = new Tuple <int, int>(clr.Where(pix => pix == 3).Count(), 3); cc = cc.OrderBy(tup => - tup.Item1).ToArray(); int c1 = cc[0].Item2; int c2 = cc[1].Item2; int c3 = cc[2].Item2; IntField cover = foregr.Clone(); cover.Map(pix => pix == c1 ? 1 : pix == c2 ? 5 : 0); AddImageGrayscale(cover, 0, 5, "25-cover-2s"); cover = foregr.Clone(); cover.Map(pix => pix == c1 ? 1 : pix == c2 ? 1 : pix == c3 ? 5 : 0); AddImageGrayscale(cover, 0, 5, "26-cover-3s"); AddIntDump("colors", clr); List <int>[] runs = new List <int> [4]; runs[1] = new List <int>(); runs[2] = new List <int>(); runs[3] = new List <int>(); int p = 0; while (p < clr.Length) { for (int c = 1; c <= 3; c++) { int pbefore = p; while (p < clr.Length && clr[p] == c) { p++; } runs[c].Add(p - pbefore); } } runs[1].Add(0); runs[2].Add(0); runs[3].Add(0); AddIntDump("color-runs-1", runs[1]); AddIntDump("color-runs-2", runs[2]); AddIntDump("color-runs-3", runs[3]); List <int>[] leftovers = new List <int> [4]; leftovers[1] = mrleCutOff(runs[1], 31); leftovers[2] = mrleCutOff(runs[2], 31); leftovers[3] = mrleCutOff(runs[3], 31); ulong[][] probs1 = mrleGetProbs(runs[1].ToArray(), 31); ulong[][] probs2 = mrleGetProbs(runs[2].ToArray(), 31); ulong[][] probs3 = mrleGetProbs(runs[3].ToArray(), 31); SetCounter("bytes|colors|probs", -1); SetCounter("bytes|colors|shortruns|1", mrleEncodeShort(runs[1].ToArray(), probs1).Length); SetCounter("bytes|colors|shortruns|2", mrleEncodeShort(runs[2].ToArray(), probs2).Length); SetCounter("bytes|colors|shortruns|3", mrleEncodeShort(runs[3].ToArray(), probs3).Length); SetCounter("bytes|colors|longruns|1", mrleEncodeLong(leftovers[1].ToArray()).Length); SetCounter("bytes|colors|longruns|2", mrleEncodeLong(leftovers[2].ToArray()).Length); SetCounter("bytes|colors|longruns|3", mrleEncodeLong(leftovers[3].ToArray()).Length); }
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"); } }
public override void Encode(IntField image, Stream output) { image.ArgbTo4c(); image.PredictionEnTransformXor(Seer); IntField[] fields = new IntField[4]; IntField[] cutmaps = new IntField[4]; List <Rectangle>[] areases = new List <Rectangle> [4]; for (int i = 1; i <= 3; i++) { fields[i] = image.Clone(); fields[i].Map(x => x == i ? 1 : 0); cutmaps[i] = fields[i].ReduceKeepingPixels(ReduceBlocksize); areases[i] = new List <Rectangle>(); IntField remains = fields[i].Clone(); while (true) { List <Rectangle> rects = CodecUtil.FindAllRects(cutmaps[i]); if (rects.Count == 0 || rects[0].Width * rects[0].Height <= 1) { break; } Rectangle r = new Rectangle(rects[0].Left * ReduceBlocksize, rects[0].Top * ReduceBlocksize, rects[0].Width * ReduceBlocksize, rects[0].Height * ReduceBlocksize); r = CodecUtil.ShrinkRectangle(remains, r); areases[i].Add(r); cutmaps[i].ShadeRect(rects[0].Left, rects[0].Top, rects[0].Width, rects[0].Height, 0, 0); remains.ShadeRect(r.Left, r.Top, r.Width, r.Height, 0, 0); } SetCounter("areas|" + i, areases[i].Count); IntField vis = fields[i].Clone(); vis.ArgbFromField(0, 1); foreach (var area in areases[i]) { vis.ShadeRect(area.Left, area.Top, area.Width, area.Height, 0xFFFF7F7F, 0x007F0000); } for (int x = 0; x < cutmaps[i].Width; x++) { for (int y = 0; y < cutmaps[i].Height; y++) { if (cutmaps[i][x, y] > 0) { vis.ShadeRect(x * ReduceBlocksize, y * ReduceBlocksize, ReduceBlocksize, ReduceBlocksize, 0xFF7FFF7F, 0x00007F00); } } } AddImageArgb(vis, "vis" + i); } // now have: fields, covered in part by areas and in part by cutmap (only remaining cutmap left at this stage) long pos = 0; output.WriteInt32Optim(image.Width); output.WriteInt32Optim(image.Height); SetCounter("bytes|size", output.Position - pos); pos = output.Position; for (int i = 1; i <= 3; i++) { output.WriteInt32Optim(areases[i].Count); } SetCounter("bytes|areas|count", output.Position - pos); pos = output.Position; for (int i = 1; i <= 3; i++) { foreach (var area in areases[i]) { output.WriteInt32Optim(area.Left); output.WriteInt32Optim(area.Top); } SetCounter("bytes|areas|x,y|" + i, output.Position - pos); pos = output.Position; } for (int i = 1; i <= 3; i++) { foreach (var area in areases[i]) { output.WriteInt32Optim(area.Width); output.WriteInt32Optim(area.Height); } SetCounter("bytes|areas|w,h|" + i, output.Position - pos); pos = output.Position; } for (int i = 1; i <= 3; i++) { var pts = CodecUtil.GetPixelCoords(cutmaps[i], 1); SetCounter("leftpixels|" + i, pts.Count); output.WriteInt32Optim(pts.Count); foreach (var pt in pts) { output.WriteInt32Optim(pt.X); output.WriteInt32Optim(pt.Y); } } RunLength01MaxSmartCodec runlen = new RunLength01MaxSmartCodec(FieldcodeSymbols); List <int> data = new List <int>(); List <int> visdata = new List <int>(); for (int i = 1; i <= 3; i++) { foreach (var area in areases[i]) { int[] aredata = fields[i].GetRectData(area); data.AddRange(aredata); visdata.AddRange(aredata.Select(val => unchecked ((int)0xFF000000) | ((i == 1 ? 0xF00000 : i == 2 ? 0xF08000 : 0xF00080) >> (2 - val * 2)))); fields[i].ShadeRect(area.Left, area.Top, area.Width, area.Height, 0, 0); } } for (int i = 1; i <= 3; i++) { var pts = CodecUtil.GetPixelCoords(cutmaps[i], 1); foreach (var pt in pts) { Rectangle rect = new Rectangle(pt.X * ReduceBlocksize, pt.Y * ReduceBlocksize, ReduceBlocksize, ReduceBlocksize); int[] aredata = fields[i].GetRectData(rect); data.AddRange(aredata); visdata.AddRange(aredata.Select(val => unchecked ((int)0xFF000000) | ((i == 1 ? 0x00F000 : i == 2 ? 0x80F000 : 0x00F080) >> (2 - val * 2)))); } } int[] dataA = data.ToArray(); int[] symbols = runlen.Encode(dataA); SetCounter("crux-pixels", data.Count); SetCounter("crux-rle-symbols", symbols.Length); int viw = (int)(Math.Sqrt(data.Count) * 1.3); int vih = (int)Math.Ceiling((double)data.Count / viw); IntField visual = new IntField(viw, vih); Array.Copy(visdata.ToArray(), visual.Data, visdata.Count); AddImageArgb(visual, "crux"); var probs = CodecUtil.CountValues(symbols); output.WriteUInt32Optim((uint)probs.Length); for (int p = 0; p < probs.Length; p++) { output.WriteUInt64Optim(probs[p]); } SetCounter("bytes|probs", output.Position - pos); pos = output.Position; ArithmeticWriter aw = new ArithmeticWriter(output, probs); foreach (int sym in symbols) { aw.WriteSymbol(sym); } SetCounter("bytes|crux", output.Position - pos); pos = output.Position; aw.Flush(); // BETTER RLE - RUNS OF 1'S // ARITH THE AREAS // ARITH THE PROBS // SHRINK GREENS }
public void AddImageArgb(IntField image, string caption) { Images.Add(new Tuple <string, IntField>(caption, image.Clone())); }