public override void SplitIndices(Intarray result1, Intarray result2, Intarray indices) { result1.MakeLike(indices); result2.MakeLike(indices); int k = l2.nStates(); for (int i = 0; i < indices.Length(); i++) { result1.Put1d(i, indices.At1d(i) / k); result2.Put1d(i, indices.At1d(i) % k); } }
public static void segmentation_correspondences(Narray<Intarray> outsegments, Intarray seg, Intarray cseg) { if (NarrayUtil.Max(seg) >= 10000) throw new Exception("CHECK_ARG: (max(seg)<10000)"); if (NarrayUtil.Max(cseg) >= 10000) throw new Exception("CHECK_ARG: (max(cseg)<10000)"); int nseg = NarrayUtil.Max(seg) + 1; int ncseg = NarrayUtil.Max(cseg) + 1; Intarray overlaps = new Intarray(nseg, ncseg); overlaps.Fill(0); if (seg.Length() != cseg.Length()) throw new Exception("CHECK_ARG: (seg.Length()==cseg.Length())"); for (int i = 0; i < seg.Length(); i++) overlaps[seg.At1d(i), cseg.At1d(i)]++; outsegments.Clear(); outsegments.Resize(ncseg); for (int i = 0; i < nseg; i++) { int j = NarrayRowUtil.RowArgMax(overlaps, i); if (!(j >= 0 && j < ncseg)) throw new Exception("ASSERT: (j>=0 && j<ncseg)"); if (outsegments[j] == null) outsegments[j] = new Intarray(); outsegments[j].Push(i); } }
/// <summary> /// A valid line segmentation may contain 0 or 0xffffff as the /// background, and otherwise numbers components starting at 1. /// The segmentation consists of segmented background pixels /// (0x80xxxx) and segmented foreground pixels (0x00xxxx). The /// segmented foreground pixels should constitute a usable /// binarization of the original image. /// </summary> public static void check_line_segmentation(Intarray cseg) { if (cseg.Length1d() == 0) { return; } if (cseg.Rank() != 2) { throw new Exception("check_line_segmentation: rank must be 2"); } for (int i = 0; i < cseg.Length1d(); i++) { int value = cseg.At1d(i); if (value == 0) { continue; } if (value == 0xffffff) { continue; } if ((value & 0x800000) > 0) { if ((value & ~0x800000) > 100000) { throw new Exception("check_line_segmentation: (value & ~0x800000) > 100000"); } } else if (value > 100000) { throw new Exception("check_line_segmentation: value > 100000"); } } }
public static void check_approximately_sorted(Intarray labels) { for (int i = 0; i < labels.Length1d(); i++) { if (labels.At1d(i) > 100000) { throw new Exception("labels out of range"); } } Narray <Rect> rboxes = new Narray <Rect>(); ImgLabels.bounding_boxes(ref rboxes, labels); #if false // TODO/tmb disabling check until the overseg issue is fixed --tmb for (int i = 1; i < rboxes.Length(); i++) { if (rboxes[i].Right < rboxes[i - 1].Left) { /*errors_log("bad segmentation", labels); * errors_log.recolor("bad segmentation (recolored)", labels); * throw_fmt("boxes aren't approximately sorted: " * "box %d is to the left from box %d", i, i-1);*/ } } #endif }
public static void rseg_to_cseg(Intarray cseg, Intarray rseg, Intarray ids) { Intarray map = new Intarray(NarrayUtil.Max(rseg) + 1); map.Fill(0); int color = 0; for (int i = 0; i < ids.Length(); i++) { if (ids[i] == 0) { continue; } color++; int start = ids[i] >> 16; int end = ids[i] & 0xFFFF; if (start > end) { throw new Exception("segmentation encoded in IDs looks seriously broken!"); } if (start >= map.Length() || end >= map.Length()) { throw new Exception("segmentation encoded in IDs doesn't fit!"); } for (int j = start; j <= end; j++) { map[j] = color; } } cseg.MakeLike(rseg); for (int i = 0; i < cseg.Length1d(); i++) { cseg.Put1d(i, map[rseg.At1d(i)]); } }
/// <summary> /// Merge segments from start to end. /// </summary> /// <param name="cseg">Output</param> /// <param name="rseg">Input</param> /// <param name="start">start merge position</param> /// <param name="end">end merge position</param> public static void rseg_to_cseg(Intarray cseg, Intarray rseg, int start, int end) { int maxSegNum = NarrayUtil.Max(rseg); if (start > end) { throw new Exception("segmentation encoded in IDs looks seriously broken!"); } if (start > maxSegNum || end > maxSegNum) { throw new Exception("segmentation encoded in IDs doesn't fit!"); } Intarray map = new Intarray(maxSegNum + 1); map.Fill(0); int color = 1; for (int i = 1; i <= maxSegNum; i++) { map[i] = color; if (i < start || i >= end) { color++; } } cseg.MakeLike(rseg); for (int i = 0; i < cseg.Length1d(); i++) { cseg.Put1d(i, map[rseg.At1d(i)]); } }
/// <summary> /// Copy one FST to another. /// </summary> /// <param name="dst">The destination. Will be cleared before copying.</param> /// <param name="src">The FST to copy.</param> public static void fst_copy(IGenericFst dst, IGenericFst src) { dst.Clear(); int n = src.nStates(); for (int i = 0; i < n; i++) { dst.NewState(); } dst.SetStart(src.GetStart()); for (int i = 0; i < n; i++) { dst.SetAccept(i, src.GetAcceptCost(i)); Intarray targets = new Intarray(), outputs = new Intarray(), inputs = new Intarray(); Floatarray costs = new Floatarray(); src.Arcs(inputs, targets, outputs, costs, i); int inlen = inputs.Length(); if (inlen != targets.Length()) { throw new Exception("ASSERT: inputs.length() == targets.length()"); } if (inlen != outputs.Length()) { throw new Exception("ASSERT: inputs.length() == outputs.length()"); } if (inlen != costs.Length()) { throw new Exception("ASSERT: inputs.length() == costs.length()"); } for (int j = 0; j < inputs.Length(); j++) { dst.AddTransition(i, targets.At1d(j), outputs.At1d(j), costs.At1d(j), inputs.At1d(j)); } } }
public override void Charseg(ref Intarray outimage, Bytearray inimage) { int swidth = PGeti("swidth"); int sheight = PGeti("sheight"); Bytearray image = new Bytearray(); image.Copy(inimage); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); outimage.Copy(image); if (swidth > 0 || sheight > 0) { Morph.binary_close_rect(image, swidth, sheight); } Intarray labels = new Intarray(); labels.Copy(image); ImgLabels.label_components(ref labels); for (int i = 0; i < outimage.Length1d(); i++) { if (outimage.At1d(i) > 0) { outimage.Put1d(i, SegmRoutine.cseg_pixel(labels.At1d(i))); } } SegmRoutine.make_line_segmentation_white(outimage); SegmRoutine.check_line_segmentation(outimage); }
public static void line_segmentation_sort_x(Intarray segmentation) { if (NarrayUtil.Max(segmentation) > 100000) { throw new Exception("line_segmentation_merge_small_components: to many segments"); } Narray <Rect> bboxes = new Narray <Rect>(); ImgLabels.bounding_boxes(ref bboxes, segmentation); Floatarray x0s = new Floatarray(); unchecked { x0s.Push((float)-999999); } for (int i = 1; i < bboxes.Length(); i++) { if (bboxes[i].Empty()) { x0s.Push(999999); } else { x0s.Push(bboxes[i].x0); } } // dprint(x0s,1000); printf("\n"); Narray <int> permutation = new Intarray(); Narray <int> rpermutation = new Intarray(); NarrayUtil.Quicksort(permutation, x0s); rpermutation.Resize(permutation.Length()); for (int i = 0; i < permutation.Length(); i++) { rpermutation[permutation[i]] = i; } // dprint(rpermutation,1000); printf("\n"); for (int i = 0; i < segmentation.Length1d(); i++) { if (segmentation.At1d(i) == 0) { continue; } segmentation.Put1d(i, rpermutation[segmentation.At1d(i)]); } }
public override void Charseg(ref Intarray outimage, Bytearray inarray) { Bytearray image = new Bytearray(); image.Copy(inarray); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); outimage.Copy(image); Intarray labels = new Intarray(); labels.Copy(image); ImgLabels.label_components(ref labels); Narray <Rect> boxes = new Narray <Rect>(); ImgLabels.bounding_boxes(ref boxes, labels); Intarray equiv = new Intarray(boxes.Length()); for (int i = 0; i < boxes.Length(); i++) { equiv[i] = i; } for (int i = 1; i < boxes.Length(); i++) { Rect p = boxes[i]; for (int j = 1; j < boxes.Length(); j++) { if (i == j) { continue; } Rect q = boxes[j]; int x0 = Math.Max(p.x0, q.x0); int x1 = Math.Min(p.x1, q.x1); int iw = x1 - x0; if (iw <= 0) { continue; // no overlap } int ow = Math.Min(p.Width(), q.Width()); float frac = iw / (float)(ow); if (frac < 0.5f) { continue; // insufficient overlap } // printf("%d %d : %d %d : %g\n",i,j,iw,ow,frac); equiv.Put1d(Math.Max(i, j), Math.Min(i, j)); } } for (int i = 0; i < labels.Length(); i++) { labels.Put1d(i, equiv.At1d(labels.At1d(i))); } ImgLabels.renumber_labels(labels, 1); outimage.Move(labels); SegmRoutine.make_line_segmentation_white(outimage); SegmRoutine.check_line_segmentation(outimage); }
public static void make_line_segmentation_black(Intarray a) { check_line_segmentation(a); ImgMisc.replace_values(a, 0xFFFFFF, 0); for (int i = 0; i < a.Length1d(); i++) { a.Put1d(i, a.At1d(i) & 0xFFF); } }
public static void combine_segmentations(ref Intarray dst, Intarray src) { dst.SameDims(src); int n = NarrayUtil.Max(dst) + 1; for (int i = 0; i < dst.Length1d(); i++) { dst.Put1d(i, (dst.At1d(i) + src.At1d(i) * n)); } ImgLabels.renumber_labels(dst, 1); }
public static void segmentation_as_bitmap(Bytearray image, Intarray cseg) { image.MakeLike(cseg); for (int i = 0; i < image.Length1d(); i++) { int value = cseg.At1d(i); if (value == 0 || value == 0xffffff) { image.Put1d(i, 255); } //if (value == 0xffffff) image.Put1d(i, 255); } }
public static void check_page_segmentation(Intarray pseg) { bool allow_zero = true; Narray <bool> used = new Narray <bool>(5000); used.Fill(false); int nused = 0; int mused = 0; for (int i = 0; i < pseg.Length1d(); i++) { uint pixel = (uint)pseg.At1d(i); if (!(allow_zero || pixel != 0)) { throw new Exception("CHECK_ARG: (allow_zero || pixel != 0)"); } if (pixel == 0 || pixel == 0xffffff) { continue; } int column = (int)(0xff & (pixel >> 16)); int paragraph = (int)(0xff & (pixel >> 8)); int line = (int)(0xff & pixel); if (!((column > 0 && column < 32) || column == 254 || column == 255)) { throw new Exception("CHECK_ARG: ((column > 0 && column < 32) || column == 254 || column == 255)"); } if (!((paragraph >= 0 && paragraph < 64) || (paragraph >= 250 && paragraph <= 255))) { throw new Exception("CHECK_ARG: ((paragraph >= 0 && paragraph < 64) || (paragraph >= 250 && paragraph <= 255))"); } if (column < 32) { if (!used[line]) { nused++; } used[line] = true; if (line > mused) { mused = line; } } } // character segments need to be numbered sequentially (no gaps) // (gaps usually happen when someone passes a binary image instead of a segmentation) if (!(nused == mused || nused == mused + 1)) { Global.Debugf("warn", "check_page_segmentation found non-sequentially numbered segments"); } }
public static void remove_small_components <T>(Narray <T> bimage, int mw, int mh) { Intarray image = new Intarray(); image.Copy(bimage); ImgLabels.label_components(ref image); Narray <Rect> rects = new Narray <Rect>(); ImgLabels.bounding_boxes(ref rects, image); Bytearray good = new Bytearray(rects.Length()); for (int i = 0; i < good.Length(); i++) { good[i] = 1; } for (int i = 0; i < rects.Length(); i++) { if (rects[i].Width() < mw && rects[i].Height() < mh) { // printf("*** %d %d %d\n",i,rects[i].width(),rects[i].height()); good[i] = 0; } } for (int i = 0; i < image.Length1d(); i++) { if (good[image.At1d(i)] == 0) { image.Put1d(i, 0); } } for (int i = 0; i < image.Length1d(); i++) { if (image.At1d(i) == 0) { bimage.Put1d(i, default(T)); // default(T) - 0 } } }
public static void remove_dontcares(ref Intarray image) { Floatarray dist = new Floatarray(); Narray <Point> source = new Narray <Point>(); dist.Resize(image.Dim(0), image.Dim(1)); for (int i = 0; i < dist.Length1d(); i++) { if (!dontcare(image.At1d(i))) { dist.Put1d(i, (image.At1d(i) > 0 ? 1 : 0)); } } BrushFire.brushfire_2(ref dist, ref source, 1000000); for (int i = 0; i < dist.Length1d(); i++) { Point p = source.At1d(i); if (dontcare(image.At1d(i))) { image.Put1d(i, image[p.X, p.Y]); } } }
/// <summary> /// Renumber the non-zero pixels in an image to start with pixel value start. /// The numerical order of pixels is preserved. /// </summary> public static int renumber_labels(Intarray image, int start = 1) { //SortedList<int, int> translation = new SortedList<int, int>(256); Dictionary <int, int> translation = new Dictionary <int, int>(256); int n = start; for (int i = 0; i < image.Length1d(); i++) { int pixel = image.At1d(i); if (pixel == 0 || pixel == 0xffffff) { continue; } if (!translation.ContainsKey(pixel)) { translation.Add(pixel, n); n++; } } n = start; int[] keys = translation.Keys.ToArray(); foreach (int key in keys) { translation[key] = n++; } for (int i = 0; i < image.Length1d(); i++) { int pixel = image.At1d(i); if (pixel == 0 || pixel == 0xffffff) { continue; } image.Put1d(i, translation[pixel]); } return(n); }
public static void propagate_labels_to(ref Intarray target, Intarray seed) { Floatarray dist = new Floatarray(); Narray <Point> source = new Narray <Point>(); dist.Copy(seed); BrushFire.brushfire_2(ref dist, ref source, 1000000); for (int i = 0; i < dist.Length1d(); i++) { Point p = source.At1d(i); if (target.At1d(i) > 0) { target.Put1d(i, seed[p.X, p.Y]); } } }
/// <summary> /// Propagate labels across the entire image from a set of non-zero seeds. /// </summary> public static void propagate_labels(ref Intarray image) { Floatarray dist = new Floatarray(); Narray <Point> source = new Narray <Point>(); dist.Copy(image); BrushFire.brushfire_2(ref dist, ref source, 1000000); for (int i = 0; i < dist.Length1d(); i++) { Point p = source.At1d(i); if (image.At1d(i) == 0) { image.Put1d(i, image[p.X, p.Y]); } } }
/// <summary> /// Remove segments from start to end. /// </summary> /// <param name="cseg">Output</param> /// <param name="rseg">Input</param> /// <param name="start">start remove position</param> /// <param name="end">end remove position</param> public static void rseg_to_cseg_remove(Intarray cseg, Intarray rseg, Bytearray outimg, Bytearray img, int start, int end) { int maxSegNum = NarrayUtil.Max(rseg); if (start > end) { throw new Exception("segmentation encoded in IDs looks seriously broken!"); } if (start > maxSegNum || end > maxSegNum) { throw new Exception("segmentation encoded in IDs doesn't fit!"); } if (rseg.Length1d() != img.Length1d()) { throw new Exception("rseg and img must have same a dimension!"); } Intarray map = new Intarray(maxSegNum + 1); map.Fill(0); int color = 1; for (int i = 1; i <= maxSegNum; i++) { map[i] = color; if (i < start || i > end) { color++; } else { map[i] = 0; } } cseg.MakeLike(rseg); outimg.Copy(img); for (int i = 0; i < cseg.Length1d(); i++) { int val = rseg.At1d(i); cseg.Put1d(i, map[val]); if (val > 0 && map[val] == 0) { outimg.Put1d(i, 255); } } }
public static void simple_recolor(Intarray image) { /*for (int i = 0; i < image.Length1d(); i++) * { * if (image.At1d(i) == 0) continue; * image.At1d(i) = enumerator[image.at1d(i)]; * }*/ for (int i = 0; i < image.Length1d(); i++) { int value = image.At1d(i); if (value == 0 || value == 0xffffff) { continue; } image.Put1d(i, interesting_colors(1 + value % 19)); } }
public static void check_approximately_sorted(Intarray labels) { for (int i = 0; i < labels.Length1d(); i++) if (labels.At1d(i) > 100000) throw new Exception("labels out of range"); Narray<Rect> rboxes = new Narray<Rect>(); ImgLabels.bounding_boxes(ref rboxes, labels); #if false // TODO/tmb disabling check until the overseg issue is fixed --tmb for(int i=1;i<rboxes.Length();i++) { if(rboxes[i].Right<rboxes[i-1].Left) { /*errors_log("bad segmentation", labels); errors_log.recolor("bad segmentation (recolored)", labels); throw_fmt("boxes aren't approximately sorted: " "box %d is to the left from box %d", i, i-1);*/ } } #endif }
public override void Charseg(ref Intarray outimage, Bytearray inimage) { int swidth = PGeti("swidth"); int sheight = PGeti("sheight"); Bytearray image = new Bytearray(); image.Copy(inimage); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); outimage.Copy(image); if (swidth > 0 || sheight > 0) Morph.binary_close_rect(image, swidth, sheight); Intarray labels = new Intarray(); labels.Copy(image); ImgLabels.label_components(ref labels); for(int i=0; i<outimage.Length1d(); i++) if (outimage.At1d(i) > 0) outimage.Put1d(i, SegmRoutine.cseg_pixel(labels.At1d(i))); SegmRoutine.make_line_segmentation_white(outimage); SegmRoutine.check_line_segmentation(outimage); }
public static void segmentation_correspondences(Narray <Intarray> outsegments, Intarray seg, Intarray cseg) { if (NarrayUtil.Max(seg) >= 10000) { throw new Exception("CHECK_ARG: (max(seg)<10000)"); } if (NarrayUtil.Max(cseg) >= 10000) { throw new Exception("CHECK_ARG: (max(cseg)<10000)"); } int nseg = NarrayUtil.Max(seg) + 1; int ncseg = NarrayUtil.Max(cseg) + 1; Intarray overlaps = new Intarray(nseg, ncseg); overlaps.Fill(0); if (seg.Length() != cseg.Length()) { throw new Exception("CHECK_ARG: (seg.Length()==cseg.Length())"); } for (int i = 0; i < seg.Length(); i++) { overlaps[seg.At1d(i), cseg.At1d(i)]++; } outsegments.Clear(); outsegments.Resize(ncseg); for (int i = 0; i < nseg; i++) { int j = NarrayRowUtil.RowArgMax(overlaps, i); if (!(j >= 0 && j < ncseg)) { throw new Exception("ASSERT: (j>=0 && j<ncseg)"); } if (outsegments[j] == null) { outsegments[j] = new Intarray(); } outsegments[j].Push(i); } }
public override void Charseg(ref Intarray outimage, Bytearray inarray) { Bytearray image = new Bytearray(); image.Copy(inarray); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); outimage.Copy(image); Intarray labels = new Intarray(); labels.Copy(image); ImgLabels.label_components(ref labels); Narray<Rect> boxes = new Narray<Rect>(); ImgLabels.bounding_boxes(ref boxes, labels); Intarray equiv = new Intarray(boxes.Length()); for(int i=0; i<boxes.Length(); i++) equiv[i] = i; for(int i=1; i<boxes.Length(); i++) { Rect p = boxes[i]; for(int j=1;j<boxes.Length();j++) { if(i==j) continue; Rect q = boxes[j]; int x0 = Math.Max(p.x0, q.x0); int x1 = Math.Min(p.x1, q.x1); int iw = x1-x0; if(iw <= 0) continue; // no overlap int ow = Math.Min(p.Width(), q.Width()); float frac = iw/(float)(ow); if(frac < 0.5f) continue; // insufficient overlap // printf("%d %d : %d %d : %g\n",i,j,iw,ow,frac); equiv.Put1d(Math.Max(i, j), Math.Min(i, j)); } } for(int i=0; i<labels.Length(); i++) labels.Put1d(i, equiv.At1d(labels.At1d(i))); ImgLabels.renumber_labels(labels, 1); outimage.Move(labels); SegmRoutine.make_line_segmentation_white(outimage); SegmRoutine.check_line_segmentation(outimage); }
/// <summary> /// Reverse the FST's arcs, adding a new start vertex (former accept). /// </summary> public static void fst_copy_reverse(IGenericFst dst, IGenericFst src, bool no_accept = false) { dst.Clear(); int n = src.nStates(); for (int i = 0; i <= n; i++) { dst.NewState(); } if (!no_accept) { dst.SetAccept(src.GetStart()); } dst.SetStart(n); for (int i = 0; i < n; i++) { dst.AddTransition(n, i, 0, src.GetAcceptCost(i), 0); Intarray targets = new Intarray(), outputs = new Intarray(), inputs = new Intarray(); Floatarray costs = new Floatarray(); src.Arcs(inputs, targets, outputs, costs, i); if (inputs.Length() != targets.Length()) { throw new Exception("ASSERT: inputs.length() == targets.length()"); } if (inputs.Length() != outputs.Length()) { throw new Exception("ASSERT: inputs.length() == outputs.length()"); } if (inputs.Length() != costs.Length()) { throw new Exception("ASSERT: inputs.length() == costs.length()"); } for (int j = 0; j < inputs.Length(); j++) { dst.AddTransition(targets.At1d(j), i, outputs.At1d(j), costs.At1d(j), inputs.At1d(j)); } } }
/// <summary> /// Copy one FST to another. /// </summary> /// <param name="dst">The destination. Will be cleared before copying.</param> /// <param name="src">The FST to copy.</param> public static void fst_copy(IGenericFst dst, IGenericFst src) { dst.Clear(); int n = src.nStates(); for (int i = 0; i < n; i++) dst.NewState(); dst.SetStart(src.GetStart()); for (int i = 0; i < n; i++) { dst.SetAccept(i, src.GetAcceptCost(i)); Intarray targets = new Intarray(), outputs = new Intarray(), inputs = new Intarray(); Floatarray costs = new Floatarray(); src.Arcs(inputs, targets, outputs, costs, i); int inlen = inputs.Length(); if (inlen != targets.Length()) throw new Exception("ASSERT: inputs.length() == targets.length()"); if (inlen != outputs.Length()) throw new Exception("ASSERT: inputs.length() == outputs.length()"); if (inlen != costs.Length()) throw new Exception("ASSERT: inputs.length() == costs.length()"); for (int j = 0; j < inputs.Length(); j++) dst.AddTransition(i, targets.At1d(j), outputs.At1d(j), costs.At1d(j), inputs.At1d(j)); } }
public override void Charseg(ref Intarray segmentation, Bytearray inraw) { setParams(); //Logger.Default.Image("segmenting", inraw); int PADDING = 3; OcrRoutine.optional_check_background_is_lighter(inraw); Bytearray image = new Bytearray(); image.Copy(inraw); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); SetImage(image); FindAllCuts(); FindBestCuts(); Intarray seg = new Intarray(); seg.MakeLike(image); seg.Fill(255); for (int r = 0; r < bestcuts.Length(); r++) { int w = seg.Dim(0); int c = bestcuts[r]; Narray<Point> cut = cuts[c]; for (int y = 0; y < image.Dim(1); y++) { for (int i = -1; i <= 1; i++) { int x = cut[y].X; if (x < 1 || x >= w - 1) continue; seg[x + i, y] = 0; } } } ImgLabels.label_components(ref seg); // dshowr(seg,"YY"); dwait(); segmentation.Copy(image); for (int i = 0; i < seg.Length1d(); i++) if (segmentation.At1d(i) == 0) seg.Put1d(i, 0); ImgLabels.propagate_labels_to(ref segmentation, seg); if (PGeti("component_segmentation") > 0) { Intarray ccseg = new Intarray(); ccseg.Copy(image); ImgLabels.label_components(ref ccseg); SegmRoutine.combine_segmentations(ref segmentation, ccseg); if (PGeti("fix_diacritics") > 0) { SegmRoutine.fix_diacritics(segmentation); } } #if false SegmRoutine.line_segmentation_merge_small_components(ref segmentation, small_merge_threshold); SegmRoutine.line_segmentation_sort_x(segmentation); #endif SegmRoutine.make_line_segmentation_white(segmentation); // set_line_number(segmentation, 1); //Logger.Default.Image("resulting segmentation", segmentation); }
public override void Charseg(ref Intarray segmentation, Bytearray inraw) { setParams(); //Logger.Default.Image("segmenting", inraw); int PADDING = 3; OcrRoutine.optional_check_background_is_lighter(inraw); Bytearray image = new Bytearray(); image.Copy(inraw); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); SetImage(image); FindAllCuts(); FindBestCuts(); Intarray seg = new Intarray(); seg.MakeLike(image); seg.Fill(255); for (int r = 0; r < bestcuts.Length(); r++) { int w = seg.Dim(0); int c = bestcuts[r]; Narray <Point> cut = cuts[c]; for (int y = 0; y < image.Dim(1); y++) { for (int i = -1; i <= 1; i++) { int x = cut[y].X; if (x < 1 || x >= w - 1) { continue; } seg[x + i, y] = 0; } } } ImgLabels.label_components(ref seg); // dshowr(seg,"YY"); dwait(); segmentation.Copy(image); for (int i = 0; i < seg.Length1d(); i++) { if (segmentation.At1d(i) == 0) { seg.Put1d(i, 0); } } ImgLabels.propagate_labels_to(ref segmentation, seg); if (PGeti("component_segmentation") > 0) { Intarray ccseg = new Intarray(); ccseg.Copy(image); ImgLabels.label_components(ref ccseg); SegmRoutine.combine_segmentations(ref segmentation, ccseg); if (PGeti("fix_diacritics") > 0) { SegmRoutine.fix_diacritics(segmentation); } } #if false SegmRoutine.line_segmentation_merge_small_components(ref segmentation, small_merge_threshold); SegmRoutine.line_segmentation_sort_x(segmentation); #endif SegmRoutine.make_line_segmentation_white(segmentation); // set_line_number(segmentation, 1); //Logger.Default.Image("resulting segmentation", segmentation); }
public int Key(int i) { return(_keys.At1d(i)); }
/// <summary> /// Reverse the FST's arcs, adding a new start vertex (former accept). /// </summary> public static void fst_copy_reverse(IGenericFst dst, IGenericFst src, bool no_accept = false) { dst.Clear(); int n = src.nStates(); for (int i = 0; i <= n; i++) dst.NewState(); if (!no_accept) dst.SetAccept(src.GetStart()); dst.SetStart(n); for (int i = 0; i < n; i++) { dst.AddTransition(n, i, 0, src.GetAcceptCost(i), 0); Intarray targets = new Intarray(), outputs = new Intarray(), inputs = new Intarray(); Floatarray costs = new Floatarray(); src.Arcs(inputs, targets, outputs, costs, i); if (inputs.Length() != targets.Length()) throw new Exception("ASSERT: inputs.length() == targets.length()"); if (inputs.Length() != outputs.Length()) throw new Exception("ASSERT: inputs.length() == outputs.length()"); if (inputs.Length() != costs.Length()) throw new Exception("ASSERT: inputs.length() == costs.length()"); for (int j = 0; j < inputs.Length(); j++) dst.AddTransition(targets.At1d(j), i, outputs.At1d(j), costs.At1d(j), inputs.At1d(j)); } }
public override void Arcs(Intarray ids, Intarray targets, Intarray outputs, Floatarray costs, int node) { int n1 = node / l2.nStates(); int n2 = node % l2.nStates(); Intarray ids1 = new Intarray(); Intarray ids2 = new Intarray(); Intarray t1 = new Intarray(); Intarray t2 = new Intarray(); Intarray o1 = new Intarray(); Intarray o2 = new Intarray(); Floatarray c1 = new Floatarray(); Floatarray c2 = new Floatarray(); l1.Arcs(ids1, t1, o1, c1, n1); l2.Arcs(ids2, t2, o2, c2, n2); // sort & permute Intarray p1 = new Intarray(); Intarray p2 = new Intarray(); NarrayUtil.Quicksort(p1, o1); NarrayUtil.Permute(ids1, p1); NarrayUtil.Permute(t1, p1); NarrayUtil.Permute(o1, p1); NarrayUtil.Permute(c1, p1); NarrayUtil.Quicksort(p2, ids2); NarrayUtil.Permute(ids2, p2); NarrayUtil.Permute(t2, p2); NarrayUtil.Permute(o2, p2); NarrayUtil.Permute(c2, p2); int k1, k2; // l1 epsilon moves for (k1 = 0; k1 < o1.Length() && o1.At1d(k1) == 0; k1++) { ids.Push(ids1.At1d(k1)); targets.Push(Combine(t1.At1d(k1), n2)); outputs.Push(0); costs.Push(c1.At1d(k1)); } // l2 epsilon moves for (k2 = 0; k2 < o2.Length() && ids2.At1d(k2) == 0; k2++) { ids.Push(0); targets.Push(Combine(n1, t2.At1d(k2))); outputs.Push(o2.At1d(k2)); costs.Push(c2.At1d(k2)); } // non-epsilon moves while (k1 < o1.Length() && k2 < ids2.Length()) { while (k1 < o1.Length() && o1.At1d(k1) < ids2.At1d(k2)) k1++; if (k1 >= o1.Length()) break; while (k2 < ids2.Length() && o1.At1d(k1) > ids2.At1d(k2)) k2++; while (k1 < o1.Length() && k2 < ids2.Length() && o1.At1d(k1) == ids2.At1d(k2)) { for (int j = k2; j < ids2.Length() && o1.At1d(k1) == ids2.At1d(j); j++) { ids.Push(ids1.At1d(k1)); targets.Push(Combine(t1.At1d(k1), t2.At1d(j))); outputs.Push(o2.At1d(j)); costs.Push(c1.At1d(k1) + c2.At1d(j)); } k1++; } } }
/// <summary> /// Label the connected components of an image. /// </summary> public static int label_components(ref Intarray image, bool four_connected = false) { int w = image.Dim(0), h = image.Dim(1); // We slice the image into columns and call make_set() // for every continuous segment within each column. // Maximal number of segments per column is (h + 1) / 2. // We do it `w' times, so it's w * (h + 1) / 2. // We also need to add 1 because index 0 is not used, but counted. UnionFind uf = new UnionFind(w * (h + 1) / 2 + 1); uf.make_set(0); int top = 1; for(int i=0; i<image.Length1d(); i++) image.Put1d(i, (image.At1d(i) > 0 ? 1 : 0)); //for(int i=0;i<w;i++) {image(i,0) = 0; image(i,h-1) = 0;} //for(int j=0;j<h;j++) {image(0,j) = 0; image(w-1,j) = 0;} for(int i=0; i<w; i++) { int current_label = 0; for(int j=0; j<h; j++) { int pixel = image[i,j]; int range = four_connected ? 0 : 1; for(int delta=-range; delta<=range; delta++) { int adj_label = NarrayUtil.Bat(image, i-1, j+delta, 0); if(pixel == 0) { current_label = 0; continue; } if(current_label == 0) { current_label = top; uf.make_set(top); top++; } if(adj_label > 0) { current_label = uf.find_set(current_label); adj_label = uf.find_set(adj_label); if(current_label != adj_label) { uf.make_union(current_label, adj_label); current_label = uf.find_set(current_label); adj_label = uf.find_set(adj_label); } } image[i,j] = current_label; } } } for(int i=0;i<image.Length1d();i++) { if(image.At1d(i) == 0) continue; image.Put1d(i, uf.find_set(image.At1d(i))); } return renumber_labels(image, 1); }
public static void fix_diacritics(Intarray segmentation) { Narray <Rect> bboxes = new Narray <Rect>(); ImgLabels.bounding_boxes(ref bboxes, segmentation); if (bboxes.Length() < 1) { return; } Intarray assignments = new Intarray(bboxes.Length()); for (int i = 0; i < assignments.Length(); i++) { assignments[i] = i; } for (int j = 0; j < bboxes.Length(); j++) { float dist = 1e38f; int closest = -1; for (int i = 0; i < bboxes.Length(); i++) { // j should overlap i in the x direction if (bboxes.At1d(j).x1 < bboxes.At1d(i).x0) { continue; } if (bboxes.At1d(j).x0 > bboxes.At1d(i).x1) { continue; } // j should be above i if (!(bboxes.At1d(j).y0 >= bboxes.At1d(i).y1)) { continue; } #if false // j should be smaller than i if (!(bboxes.At1d(j).area() < bboxes.At1d(i).area())) { continue; } #endif float d = Math.Abs((bboxes[j].x0 + bboxes[j].x1) / 2 - (bboxes[i].x0 + bboxes[i].x1) / 2); if (d >= dist) { continue; } dist = d; closest = i; } if (closest < 0) { continue; } assignments[j] = closest; } for (int i = 0; i < segmentation.Length(); i++) { segmentation.Put1d(i, assignments[segmentation.At1d(i)]); } ImgLabels.renumber_labels(segmentation, 1); }
/// <summary> /// Renumber the non-zero pixels in an image to start with pixel value start. /// The numerical order of pixels is preserved. /// </summary> public static int renumber_labels(Intarray image, int start=1) { //SortedList<int, int> translation = new SortedList<int, int>(256); Dictionary<int, int> translation = new Dictionary<int, int>(256); int n = start; for(int i=0; i<image.Length1d(); i++) { int pixel = image.At1d(i); if(pixel==0 || pixel==0xffffff) continue; if (!translation.ContainsKey(pixel)) { translation.Add(pixel, n); n++; } } n = start; int[] keys = translation.Keys.ToArray(); foreach (int key in keys) translation[key] = n++; for(int i=0;i<image.Length1d();i++) { int pixel = image.At1d(i); if(pixel==0 || pixel==0xffffff) continue; image.Put1d(i, translation[pixel]); } return n; }
public static void simple_recolor(Intarray image) { /*for (int i = 0; i < image.Length1d(); i++) { if (image.At1d(i) == 0) continue; image.At1d(i) = enumerator[image.at1d(i)]; }*/ for (int i = 0; i < image.Length1d(); i++) { int value = image.At1d(i); if (value == 0 || value == 0xffffff) continue; image.Put1d(i, interesting_colors(1 + value % 19)); } }
public static void remove_dontcares(ref Intarray image) { Floatarray dist = new Floatarray(); Narray<Point> source = new Narray<Point>(); dist.Resize(image.Dim(0), image.Dim(1)); for (int i = 0; i < dist.Length1d(); i++) if (!dontcare(image.At1d(i))) dist.Put1d(i, (image.At1d(i) > 0 ? 1 : 0)); BrushFire.brushfire_2(ref dist, ref source, 1000000); for (int i = 0; i < dist.Length1d(); i++) { Point p = source.At1d(i); if (dontcare(image.At1d(i))) image.Put1d(i, image[p.X, p.Y]); } }
public static void propagate_labels_to(ref Intarray target, Intarray seed) { Floatarray dist = new Floatarray(); Narray<Point> source = new Narray<Point>(); dist.Copy(seed); BrushFire.brushfire_2(ref dist, ref source, 1000000); for (int i = 0; i < dist.Length1d(); i++) { Point p = source.At1d(i); if (target.At1d(i) > 0) target.Put1d(i, seed[p.X, p.Y]); } }
/// <summary> /// Propagate labels across the entire image from a set of non-zero seeds. /// </summary> public static void propagate_labels(ref Intarray image) { Floatarray dist = new Floatarray(); Narray<Point> source = new Narray<Point>(); dist.Copy(image); BrushFire.brushfire_2(ref dist, ref source, 1000000); for (int i = 0; i < dist.Length1d(); i++) { Point p = source.At1d(i); if (image.At1d(i) == 0) image.Put1d(i, image[p.X, p.Y]); } }
public override void Arcs(Intarray ids, Intarray targets, Intarray outputs, Floatarray costs, int node) { int n1 = node / l2.nStates(); int n2 = node % l2.nStates(); Intarray ids1 = new Intarray(); Intarray ids2 = new Intarray(); Intarray t1 = new Intarray(); Intarray t2 = new Intarray(); Intarray o1 = new Intarray(); Intarray o2 = new Intarray(); Floatarray c1 = new Floatarray(); Floatarray c2 = new Floatarray(); l1.Arcs(ids1, t1, o1, c1, n1); l2.Arcs(ids2, t2, o2, c2, n2); // sort & permute Intarray p1 = new Intarray(); Intarray p2 = new Intarray(); NarrayUtil.Quicksort(p1, o1); NarrayUtil.Permute(ids1, p1); NarrayUtil.Permute(t1, p1); NarrayUtil.Permute(o1, p1); NarrayUtil.Permute(c1, p1); NarrayUtil.Quicksort(p2, ids2); NarrayUtil.Permute(ids2, p2); NarrayUtil.Permute(t2, p2); NarrayUtil.Permute(o2, p2); NarrayUtil.Permute(c2, p2); int k1, k2; // l1 epsilon moves for (k1 = 0; k1 < o1.Length() && o1.At1d(k1) == 0; k1++) { ids.Push(ids1.At1d(k1)); targets.Push(Combine(t1.At1d(k1), n2)); outputs.Push(0); costs.Push(c1.At1d(k1)); } // l2 epsilon moves for (k2 = 0; k2 < o2.Length() && ids2.At1d(k2) == 0; k2++) { ids.Push(0); targets.Push(Combine(n1, t2.At1d(k2))); outputs.Push(o2.At1d(k2)); costs.Push(c2.At1d(k2)); } // non-epsilon moves while (k1 < o1.Length() && k2 < ids2.Length()) { while (k1 < o1.Length() && o1.At1d(k1) < ids2.At1d(k2)) { k1++; } if (k1 >= o1.Length()) { break; } while (k2 < ids2.Length() && o1.At1d(k1) > ids2.At1d(k2)) { k2++; } while (k1 < o1.Length() && k2 < ids2.Length() && o1.At1d(k1) == ids2.At1d(k2)) { for (int j = k2; j < ids2.Length() && o1.At1d(k1) == ids2.At1d(j); j++) { ids.Push(ids1.At1d(k1)); targets.Push(Combine(t1.At1d(k1), t2.At1d(j))); outputs.Push(o2.At1d(j)); costs.Push(c1.At1d(k1) + c2.At1d(j)); } k1++; } } }
/// <summary> /// Label the connected components of an image. /// </summary> public static int label_components(ref Intarray image, bool four_connected = false) { int w = image.Dim(0), h = image.Dim(1); // We slice the image into columns and call make_set() // for every continuous segment within each column. // Maximal number of segments per column is (h + 1) / 2. // We do it `w' times, so it's w * (h + 1) / 2. // We also need to add 1 because index 0 is not used, but counted. UnionFind uf = new UnionFind(w * (h + 1) / 2 + 1); uf.make_set(0); int top = 1; for (int i = 0; i < image.Length1d(); i++) { image.Put1d(i, (image.At1d(i) > 0 ? 1 : 0)); } //for(int i=0;i<w;i++) {image(i,0) = 0; image(i,h-1) = 0;} //for(int j=0;j<h;j++) {image(0,j) = 0; image(w-1,j) = 0;} for (int i = 0; i < w; i++) { int current_label = 0; for (int j = 0; j < h; j++) { int pixel = image[i, j]; int range = four_connected ? 0 : 1; for (int delta = -range; delta <= range; delta++) { int adj_label = NarrayUtil.Bat(image, i - 1, j + delta, 0); if (pixel == 0) { current_label = 0; continue; } if (current_label == 0) { current_label = top; uf.make_set(top); top++; } if (adj_label > 0) { current_label = uf.find_set(current_label); adj_label = uf.find_set(adj_label); if (current_label != adj_label) { uf.make_union(current_label, adj_label); current_label = uf.find_set(current_label); adj_label = uf.find_set(adj_label); } } image[i, j] = current_label; } } } for (int i = 0; i < image.Length1d(); i++) { if (image.At1d(i) == 0) { continue; } image.Put1d(i, uf.find_set(image.At1d(i))); } return(renumber_labels(image, 1)); }