public override void Charseg(ref Intarray result_segmentation, Bytearray orig_image) { Logger.Default.Image("segmenting", orig_image); int PADDING = 3; OcrRoutine.optional_check_background_is_lighter(orig_image); Bytearray image = new Bytearray(); Narray <byte> bimage = image; image.Copy(orig_image); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); ImgOps.pad_by(ref bimage, PADDING, PADDING); // pass image to segmenter segmenter.SetImage(image); // find all cuts in the image segmenter.FindAllCuts(); // choose the best of all cuts segmenter.FindBestCuts(); Intarray segmentation = new Intarray(); segmentation.Resize(image.Dim(0), image.Dim(1)); for (int i = 0; i < image.Dim(0); i++) { for (int j = 0; j < image.Dim(1); j++) { segmentation[i, j] = image[i, j] > 0 ? 1 : 0; } } for (int r = 0; r < segmenter.bestcuts.Length(); r++) { int c = segmenter.bestcuts[r]; Narray <Point> cut = segmenter.cuts[c]; for (int y = 0; y < image.Dim(1); y++) { for (int x = cut[y].X; x < image.Dim(0); x++) { if (segmentation[x, y] > 0) { segmentation[x, y]++; } } } } ImgOps.extract_subimage(result_segmentation, segmentation, PADDING, PADDING, segmentation.Dim(0) - PADDING, segmentation.Dim(1) - PADDING); if (small_merge_threshold > 0) { SegmRoutine.line_segmentation_merge_small_components(ref result_segmentation, small_merge_threshold); SegmRoutine.line_segmentation_sort_x(result_segmentation); } SegmRoutine.make_line_segmentation_white(result_segmentation); // set_line_number(segmentation, 1); Logger.Default.Image("resulting segmentation", result_segmentation); }
/// <summary> /// Return the segmentation-derived mask for the character. /// This may optionally be grown by some pixels. /// </summary> public override void GetMask(out Rect r, ref Bytearray outmask, int index, int grow) { r = boxes.At1d(index).Grow(grow); r.Intersect(new Rect(0, 0, labels.Dim(0), labels.Dim(1))); if (fullheight) { r.y0 = 0; r.y1 = labels.Dim(1); } int x = r.x0, y = r.y0, w = r.Width(), h = r.Height(); Intarray segs = segments.At1d(index); outmask.Resize(w, h); outmask.Fill(0); for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { int label = labels[x + i, y + j]; if (NarrayUtil.first_index_of(segs, label) >= 0) { outmask[i, j] = (byte)255; } } } if (grow > 0) { Morph.binary_dilate_circle(outmask, grow); } }
/// <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); }
/// <summary> /// Compute the bounding boxes for the pixels in the image. /// </summary> public static void bounding_boxes(ref Narray<Rect> result, Intarray image) { result.Clear(); int n = NarrayUtil.Max(image); if (n < 1) return; result.Resize(n + 1); result.Fill(Rect.CreateEmpty()); for (int i = 0; i < image.Dim(0); i++) for (int j = 0; j < image.Dim(1); j++) { int value = image[i, j]; Rect r = result[value]; r.Include(i, j); result[value] = r; //original: result(value).include(i, j); } }
public void RunTest() { IBookStore bstore = new SmartBookStore(); bstore.SetPrefix(@"data2"); Console.WriteLine("Pages in bookstore: {0}", bstore.NumberOfPages()); Console.WriteLine("List pages.."); for (int i = 0; i < bstore.NumberOfPages(); i++) { Console.WriteLine("page {0:0000}\t->\t{1,6} lines", i, bstore.LinesOnPage(i)); } Bytearray line = new Bytearray(); bstore.GetLine(line, 1, 5); Console.WriteLine("line{0} [{1},{2}]", 5, line.Dim(0), line.Dim(1)); Intarray cline = new Intarray(); bstore.GetCharSegmentation(cline, 1, 5); Console.WriteLine("line{0}.cseg [{1},{2}]", 5, cline.Dim(0), cline.Dim(1)); }
public void Init(params string[] books) { bool retrain = PGetb("retrain"); bool randomize = PGetb("randomize"); string cbookstore = PGet("cbookstore"); bookstores.Clear(); all_lines.Clear(); cseg_variant = "cseg.gt"; text_variant = "gt"; if (retrain) { cseg_variant = "cseg"; text_variant = ""; } int nbooks = books.Length; bookstores.Resize(nbooks); int totalNumberOfPages = 0; for (int i = 0; i < nbooks; i++) { bookstores[i] = ComponentCreator.MakeComponent <IBookStore>(cbookstore); bookstores[i].SetPrefix(books[i].Trim()); Global.Debugf("info", "{0}: {1} pages", books[i], bookstores[i].NumberOfPages()); totalNumberOfPages += bookstores[i].NumberOfPages(); } //CHECK_ARG(totalNumberOfPages > 0, "totalNumberOfPages > 0"); // compute a list of all lines Intarray triple = new Intarray(3); for (int i = 0; i < nbooks; i++) { for (int j = 0; j < bookstores[i].NumberOfPages(); j++) { for (int k = 0; k < bookstores[i].LinesOnPage(j); k++) { triple[0] = i; triple[1] = j; triple[2] = k; NarrayRowUtil.RowPush(all_lines, triple); } } } Global.Debugf("info", "got {0} lines", all_lines.Dim(0)); // randomly permute it so that we train in random order if (randomize) { Shuffle(); } index = 0; }
public static void extract_holes(ref Bytearray holes, Bytearray binarized) { Intarray temp = new Intarray(); temp.Copy(binarized); NarrayUtil.Sub(255, temp); ImgLabels.label_components(ref temp); int background = -1; for (int i = 0; i < temp.Dim(0); i++) { if (temp[i, 0] != 0) { background = temp[i, 0]; break; } } holes.MakeLike(temp); holes.Fill((byte)0); if (background <= 0) { throw new Exception("extract_holes: background must be more 0"); } for (int i = 0; i < temp.Dim(0); i++) { for (int j = 0; j < temp.Dim(1); j++) { if (temp[i, j] > 0 && temp[i, j] != background) { holes[i, j] = 255; } } } /*fprintf(stderr, "segholes\n"); * dsection("segholes"); * dshow(holes, "y");*/ }
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> /// Compute the bounding boxes for the pixels in the image. /// </summary> public static void bounding_boxes(ref Narray <Rect> result, Intarray image) { result.Clear(); int n = NarrayUtil.Max(image); if (n < 1) { return; } result.Resize(n + 1); result.Fill(Rect.CreateEmpty()); for (int i = 0; i < image.Dim(0); i++) { for (int j = 0; j < image.Dim(1); j++) { int value = image[i, j]; Rect r = result[value]; r.Include(i, j); result[value] = r; //original: result(value).include(i, j); } } }
public override void Charseg(ref Intarray segmentation, Bytearray inraw) { Logger.Default.Image("segmenting", inraw); OcrRoutine.optional_check_background_is_lighter(inraw); Bytearray image = new Bytearray(); image.Copy(inraw); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); segmenter.SetImage(image); segmenter.FindAllCuts(); segmenter.FindBestCuts(); Intarray seg = new Intarray(); seg.Copy(image); for (int r = 0; r < segmenter.bestcuts.Length(); r++) { int w = seg.Dim(0); int c = segmenter.bestcuts[r]; Narray <Point> cut = segmenter.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); ImgLabels.propagate_labels_to(ref segmentation, seg); SegmRoutine.line_segmentation_merge_small_components(ref segmentation, small_merge_threshold); SegmRoutine.line_segmentation_sort_x(segmentation); 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) { Logger.Default.Image("segmenting", inraw); OcrRoutine.optional_check_background_is_lighter(inraw); Bytearray image = new Bytearray(); image.Copy(inraw); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); segmenter.SetImage(image); segmenter.FindAllCuts(); segmenter.FindBestCuts(); Intarray seg = new Intarray(); seg.Copy(image); for (int r = 0; r < segmenter.bestcuts.Length(); r++) { int w = seg.Dim(0); int c = segmenter.bestcuts[r]; Narray<Point> cut = segmenter.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); ImgLabels.propagate_labels_to(ref segmentation, seg); SegmRoutine.line_segmentation_merge_small_components(ref segmentation, small_merge_threshold); SegmRoutine.line_segmentation_sort_x(segmentation); SegmRoutine.make_line_segmentation_white(segmentation); // set_line_number(segmentation, 1); Logger.Default.Image("resulting segmentation", segmentation); }
public override void SetImage(Bytearray image) { dimage.Copy(image); int w = image.Dim(0), h = image.Dim(1); wimage.Resize(w, h); wimage.Fill(0); float s1 = 0.0f, sy = 0.0f; for (int i = 1; i < w; i++) { for (int j = 0; j < h; j++) { if (image[i, j] > 0) { s1++; sy += j; } if (image[i - 1, j] == 0 && image[i, j] > 0) { wimage[i, j] = boundary_weight; } else if (image[i, j] > 0) { wimage[i, j] = inside_weight; } else { wimage[i, j] = outside_weight; } } } where = (int)(sy / s1); for (int i = 0; i < dimage.Dim(0); i++) { dimage[i, where] = 0x008000; } }
protected void Step(int x0, int x1, int y) { int w = wimage.Dim(0), h = wimage.Dim(1); Queue <Point> queue = new Queue <Point>(w * h); for (int i = x0; i < x1; i++) { queue.Enqueue(new Point(i, y)); } int low = 1; int high = wimage.Dim(0) - 1; while (queue.Count > 0) { Point p = queue.Dequeue(); int i = p.X, j = p.Y; int cost = costs[i, j]; int ncost = cost + wimage[i, j] + down_cost; if (costs[i, j + direction] > ncost) { costs[i, j + direction] = ncost; sources[i, j + direction] = i; if (j + direction != limit) { queue.Enqueue(new Point(i, j + direction)); } } if (i > low) { if (wimage[i, j] == 0) { ncost = cost + wimage[i, j] + outside_diagonal_cost; } else if (wimage[i, j] > 0) { ncost = cost + wimage[i, j] + inside_diagonal_cost; } else if (wimage[i, j] < 0) { ncost = cost + wimage[i, j] + boundary_diagonal_cost; } if (costs[i - 1, j + direction] > ncost) { costs[i - 1, j + direction] = ncost; sources[i - 1, j + direction] = i; if (j + direction != limit) { queue.Enqueue(new Point(i - 1, j + direction)); } } } if (i < high) { if (wimage[i, j] == 0) { ncost = cost + wimage[i, j] + outside_diagonal_cost; } else if (wimage[i, j] > 0) { ncost = cost + wimage[i, j] + inside_diagonal_cost; } else if (wimage[i, j] < 0) { ncost = cost + wimage[i, j] + boundary_diagonal_cost; } if (costs[i + 1, j + direction] > ncost) { costs[i + 1, j + direction] = ncost; sources[i + 1, j + direction] = i; if (j + direction != limit) { queue.Enqueue(new Point(i + 1, j + direction)); } } } } }
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); }
/// <summary> /// Train on a text line, given a segmentation. /// <remarks>This is analogous to addTrainingLine(bytearray,nustring) except that /// it takes the "ground truth" line segmentation.</remarks> /// </summary> public override bool AddTrainingLine(Intarray cseg, Bytearray image_grayscale, string tr) { Bytearray image = new Bytearray(); image.Copy(image_grayscale); if (String.IsNullOrEmpty(tr)) { Global.Debugf("error", "input transcript is empty"); return false; } if (image.Dim(0) < PGeti("minheight")) { Global.Debugf("error", "input line too small ({0} x {1})", image.Dim(0), image.Dim(1)); return false; } if (image.Dim(1) > PGeti("maxheight")) { Global.Debugf("error", "input line too high ({0} x {1})", image.Dim(0), image.Dim(1)); return false; } if (image.Dim(1) * 1.0 / image.Dim(0) > PGetf("maxaspect")) { Global.Debugf("warn", "input line has bad aspect ratio ({0} x {1})", image.Dim(0), image.Dim(1)); return false; } CHECK_ARG(image.Dim(0) == cseg.Dim(0) && image.Dim(1) == cseg.Dim(1), "image.Dim(0) == cseg.Dim(0) && image.Dim(1) == cseg.Dim(1)"); bool use_reject = PGetb("use_reject") && !DisableJunk; // check and set the transcript transcript = tr; SetLine(image_grayscale); if (PGeti("invert") > 0) NarrayUtil.Sub(NarrayUtil.Max(image), image); for (int i = 0; i < transcript.Length; i++) CHECK_ARG((int)transcript[i] >= 32, "(int)transcript[i] >= 32"); // compute correspondences between actual segmentation and // ground truth segmentation Narray<Intarray> segments = new Narray<Intarray>(); GrouperRoutine.segmentation_correspondences(segments, segmentation, cseg); // now iterate through all the hypothesis segments and // train the classifier with them int total = 0; int junk = 0; for (int i = 0; i < grouper.Object.Length(); i++) { Intarray segs = new Intarray(); grouper.Object.GetSegments(segs, i); // see whether this is a ground truth segment int match = -1; for (int j = 0; j < segments.Length(); j++) { if (GrouperRoutine.Equals(segments[j], segs)) { match = j; break; } } match -= 1; // segments are numbered starting at 1 int c = reject_class; if (match >= 0) { if (match >= transcript.Length) { Global.Debugf("error", "mismatch between transcript and cseg: {0}", transcript); continue; } else { c = (int)transcript[match]; Global.Debugf("debugmismatch", "index {0} position {1} char {2} [{3}]", i, match, (char)c, c); } } if (c == reject_class) junk++; // extract the character and add it to the classifier Rect b; Bytearray mask = new Bytearray(); grouper.Object.GetMask(out b, ref mask, i, 0); Bytearray cv = new Bytearray(); grouper.Object.ExtractWithMask(cv, mask, image, i, 0); Floatarray v = new Floatarray(); v.Copy(cv); v /= 255.0; Global.Debugf("cdim", "character dimensions ({0},{1})", v.Dim(0), v.Dim(1)); total++; if (use_reject) { classifier.Object.XAdd(v, c); } else { if (c != reject_class) classifier.Object.XAdd(v, c); } if (c != reject_class) IncClass(c); ntrained++; } Global.Debugf("detail", "AddTrainingLine trained {0} chars, {1} junk", total - junk, junk); return true; }
public void Image(string description, Intarray a, float zoom = 100f) { if (verbose) { writer.WriteLine(String.Format("image {0} w:{1}, h:{2}", description, a.Dim(0), a.Dim(1))); } }
public override void Charseg(ref Intarray result_segmentation, Bytearray orig_image) { Logger.Default.Image("segmenting", orig_image); int PADDING = 3; OcrRoutine.optional_check_background_is_lighter(orig_image); Bytearray image = new Bytearray(); Narray<byte> bimage = image; image.Copy(orig_image); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); ImgOps.pad_by(ref bimage, PADDING, PADDING); // pass image to segmenter segmenter.SetImage(image); // find all cuts in the image segmenter.FindAllCuts(); // choose the best of all cuts segmenter.FindBestCuts(); Intarray segmentation = new Intarray(); segmentation.Resize(image.Dim(0), image.Dim(1)); for (int i = 0; i < image.Dim(0); i++) for (int j = 0; j < image.Dim(1); j++) segmentation[i, j] = image[i, j] > 0 ? 1 : 0; for (int r = 0; r < segmenter.bestcuts.Length(); r++) { int c = segmenter.bestcuts[r]; Narray<Point> cut = segmenter.cuts[c]; for (int y = 0; y < image.Dim(1); y++) { for (int x = cut[y].X; x < image.Dim(0); x++) { if (segmentation[x, y] > 0) segmentation[x, y]++; } } } ImgOps.extract_subimage(result_segmentation, segmentation, PADDING, PADDING, segmentation.Dim(0) - PADDING, segmentation.Dim(1) - PADDING); if (small_merge_threshold > 0) { SegmRoutine.line_segmentation_merge_small_components(ref result_segmentation, small_merge_threshold); SegmRoutine.line_segmentation_sort_x(result_segmentation); } SegmRoutine.make_line_segmentation_white(result_segmentation); // set_line_number(segmentation, 1); Logger.Default.Image("resulting segmentation", result_segmentation); }
public void Image(string description, Intarray a, float zoom = 100f) { if (verbose) writer.WriteLine(String.Format("image {0} w:{1}, h:{2}", description, a.Dim(0), a.Dim(1))); }
/// <summary> /// Train on a text line, given a segmentation. /// <remarks>This is analogous to addTrainingLine(bytearray,nustring) except that /// it takes the "ground truth" line segmentation.</remarks> /// </summary> public override bool AddTrainingLine(Intarray cseg, Bytearray image_grayscale, string tr) { Bytearray image = new Bytearray(); image.Copy(image_grayscale); if (String.IsNullOrEmpty(tr)) { Global.Debugf("error", "input transcript is empty"); return(false); } if (image.Dim(0) < PGeti("minheight")) { Global.Debugf("error", "input line too small ({0} x {1})", image.Dim(0), image.Dim(1)); return(false); } if (image.Dim(1) > PGeti("maxheight")) { Global.Debugf("error", "input line too high ({0} x {1})", image.Dim(0), image.Dim(1)); return(false); } if (image.Dim(1) * 1.0 / image.Dim(0) > PGetf("maxaspect")) { Global.Debugf("warn", "input line has bad aspect ratio ({0} x {1})", image.Dim(0), image.Dim(1)); return(false); } CHECK_ARG(image.Dim(0) == cseg.Dim(0) && image.Dim(1) == cseg.Dim(1), "image.Dim(0) == cseg.Dim(0) && image.Dim(1) == cseg.Dim(1)"); bool use_reject = PGetb("use_reject") && !DisableJunk; // check and set the transcript transcript = tr; SetLine(image_grayscale); if (PGeti("invert") > 0) { NarrayUtil.Sub(NarrayUtil.Max(image), image); } for (int i = 0; i < transcript.Length; i++) { CHECK_ARG((int)transcript[i] >= 32, "(int)transcript[i] >= 32"); } // compute correspondences between actual segmentation and // ground truth segmentation Narray <Intarray> segments = new Narray <Intarray>(); GrouperRoutine.segmentation_correspondences(segments, segmentation, cseg); // now iterate through all the hypothesis segments and // train the classifier with them int total = 0; int junk = 0; for (int i = 0; i < grouper.Object.Length(); i++) { Intarray segs = new Intarray(); grouper.Object.GetSegments(segs, i); // see whether this is a ground truth segment int match = -1; for (int j = 0; j < segments.Length(); j++) { if (GrouperRoutine.Equals(segments[j], segs)) { match = j; break; } } match -= 1; // segments are numbered starting at 1 int c = reject_class; if (match >= 0) { if (match >= transcript.Length) { Global.Debugf("error", "mismatch between transcript and cseg: {0}", transcript); continue; } else { c = (int)transcript[match]; Global.Debugf("debugmismatch", "index {0} position {1} char {2} [{3}]", i, match, (char)c, c); } } if (c == reject_class) { junk++; } // extract the character and add it to the classifier Rect b; Bytearray mask = new Bytearray(); grouper.Object.GetMask(out b, ref mask, i, 0); Bytearray cv = new Bytearray(); grouper.Object.ExtractWithMask(cv, mask, image, i, 0); Floatarray v = new Floatarray(); v.Copy(cv); v /= 255.0; Global.Debugf("cdim", "character dimensions ({0},{1})", v.Dim(0), v.Dim(1)); total++; if (use_reject) { classifier.Object.XAdd(v, c); } else { if (c != reject_class) { classifier.Object.XAdd(v, c); } } if (c != reject_class) { IncClass(c); } ntrained++; } Global.Debugf("detail", "AddTrainingLine trained {0} chars, {1} junk", total - junk, junk); return(true); }
/// <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 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 line_segmentation_merge_small_components(ref Intarray segmentation, int r = 10) { if (NarrayUtil.Max(segmentation) > 100000) { throw new Exception("line_segmentation_merge_small_components: to many segments"); } make_line_segmentation_black(segmentation); Narray <Rect> bboxes = new Narray <Rect>(); ImgLabels.bounding_boxes(ref bboxes, segmentation); bboxes[0] = Rect.CreateEmpty(); bool changed; do { changed = false; for (int i = 1; i < bboxes.Length(); i++) { Rect b = bboxes[i]; if (b.Empty()) { continue; } if (b.Width() >= r || b.Height() >= r) { continue; } // merge small components only with touching components int closest = 0; Rect b1 = b.Grow(1); b1.Intersect(new Rect(0, 0, segmentation.Dim(0), segmentation.Dim(1))); for (int x = b1.x0; x < b1.x1; x++) { for (int y = b1.y0; y < b1.y1; y++) { int value = segmentation[x, y]; if (value == 0) { continue; } if (value == i) { continue; } closest = value; break; } } if (closest == 0) { continue; } for (int x = b.x0; x < b.x1; x++) { for (int y = b.y0; y < b.y1; y++) { if (segmentation[x, y] == i) { segmentation[x, y] = closest; } } } bboxes[i] = Rect.CreateEmpty(); changed = true; } } while (changed); }