public static void Crop <T>(Narray <T> a, Rect box) { Narray <T> t = new Narray <T>(); ImgOps.extract_subimage(t, a, box.x0, box.y0, box.x1, box.y1); a.Move(t); }
public static Bitmap DrawSegmentNumbers(Bitmap bmp, Narray<Rect> bboxes) { int numAreaHeight = 10; Bitmap newbitmap = new Bitmap(bmp.Width, bmp.Height + numAreaHeight, bmp.PixelFormat); int height = bmp.Height; using (Graphics g = Graphics.FromImage(newbitmap)) { SolidBrush bgrnBrush = new SolidBrush(Color.White); SolidBrush txtBrush = new SolidBrush(Color.Black); Pen rectPen = new Pen(Color.DarkGray); g.FillRectangle(bgrnBrush, new Rectangle(Point.Empty, newbitmap.Size)); g.DrawImage(bmp, Point.Empty); bgrnBrush.Dispose(); FontFamily fontFam; try { fontFam = new FontFamily("Tahoma"); } catch { fontFam = FontFamily.GenericSansSerif; } Font font = new Font(fontFam, 5f); for (int i = 1; i < bboxes.Length(); i++) { Rect b = bboxes[i]; int bposY = (height - b.y1); // draw bounding rects g.DrawRectangle(rectPen, Math.Max(0, b.x0-1), Math.Max(0, bposY-1), b.W, b.H+1); // draw numbers g.DrawString(i.ToString(), font, txtBrush, b.x0, height + 1); } txtBrush.Dispose(); } return newbitmap; }
public static Bitmap DrawSegmentNumbers(Bitmap bmp, Narray <Rect> bboxes) { int numAreaHeight = 10; Bitmap newbitmap = new Bitmap(bmp.Width, bmp.Height + numAreaHeight, bmp.PixelFormat); int height = bmp.Height; using (Graphics g = Graphics.FromImage(newbitmap)) { SolidBrush bgrnBrush = new SolidBrush(Color.White); SolidBrush txtBrush = new SolidBrush(Color.Black); Pen rectPen = new Pen(Color.DarkGray); g.FillRectangle(bgrnBrush, new Rectangle(Point.Empty, newbitmap.Size)); g.DrawImage(bmp, Point.Empty); bgrnBrush.Dispose(); FontFamily fontFam; try { fontFam = new FontFamily("Tahoma"); } catch { fontFam = FontFamily.GenericSansSerif; } Font font = new Font(fontFam, 5f); for (int i = 1; i < bboxes.Length(); i++) { Rect b = bboxes[i]; int bposY = (height - b.y1); // draw bounding rects g.DrawRectangle(rectPen, Math.Max(0, b.x0 - 1), Math.Max(0, bposY - 1), b.W, b.H + 1); // draw numbers g.DrawString(i.ToString(), font, txtBrush, b.x0, height + 1); } txtBrush.Dispose(); } return(newbitmap); }
public static Bitmap DrawSegmentTranscript(Bitmap bmp, Narray<Rect> bboxes, string trans) { if (String.IsNullOrEmpty(trans) || bboxes.Length() - 1 != trans.Length) return bmp; int numAreaHeight = 15; Bitmap newbitmap = new Bitmap(bmp.Width, bmp.Height + numAreaHeight, bmp.PixelFormat); int height = bmp.Height; using (Graphics g = Graphics.FromImage(newbitmap)) { SolidBrush bgrnBrush = new SolidBrush(Color.White); SolidBrush txtBrush = new SolidBrush(Color.Black); Pen rectPen = new Pen(Color.DarkGray); g.FillRectangle(bgrnBrush, new Rectangle(Point.Empty, newbitmap.Size)); g.DrawImage(bmp, Point.Empty); bgrnBrush.Dispose(); g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; FontFamily fontFam; try { fontFam = new FontFamily("Tahoma"); } catch { fontFam = FontFamily.GenericSansSerif; } Font font = new Font(fontFam, 6f); for (int i = 1; i < bboxes.Length(); i++) { Rect b = bboxes[i]; g.DrawString(trans[i-1].ToString(), font, txtBrush, b.x0, height + 1); } txtBrush.Dispose(); } return newbitmap; }
public static void Copy(Narray<byte> dst, Narray<float> src) { dst.Resize(src.Dim(0), src.Dim(1), src.Dim(2), src.Dim(3)); int n = dst.Length1d(); for (int i = 0; i < n; i++) dst.UnsafePut1d(i, Convert.ToByte(src.UnsafeAt1d(i) * 255)); }
/// <summary> ///A test for SameDims ///</summary> public void SameDimsTestHelper <T, S>() { Narray <T> target = new Narray <T>(10, 12); Narray <S> b = new Narray <S>(12, 10); Assert.IsFalse(target.SameDims <S>(b)); }
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 override void Extract(Narray<Floatarray> outarrays, Floatarray inarray) { outarrays.Clear(); Floatarray image = outarrays.Push(); rescale(image, inarray); //image /= Math.Max(1.0f, NarrayUtil.Max(image)); }
/// <summary> ///A test for Truncate ///</summary> public void TruncateTestHelper <T>() { Narray <T> target = new Narray <T>(20); target.Truncate(5); Assert.AreEqual(5, target.Length()); }
public static Bitmap DrawSegmentTranscript(Bitmap bmp, Narray <Rect> bboxes, string trans) { if (String.IsNullOrEmpty(trans) || bboxes.Length() - 1 != trans.Length) { return(bmp); } int numAreaHeight = 15; Bitmap newbitmap = new Bitmap(bmp.Width, bmp.Height + numAreaHeight, bmp.PixelFormat); int height = bmp.Height; using (Graphics g = Graphics.FromImage(newbitmap)) { SolidBrush bgrnBrush = new SolidBrush(Color.White); SolidBrush txtBrush = new SolidBrush(Color.Black); Pen rectPen = new Pen(Color.DarkGray); g.FillRectangle(bgrnBrush, new Rectangle(Point.Empty, newbitmap.Size)); g.DrawImage(bmp, Point.Empty); bgrnBrush.Dispose(); g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; FontFamily fontFam; try { fontFam = new FontFamily("Tahoma"); } catch { fontFam = FontFamily.GenericSansSerif; } Font font = new Font(fontFam, 6f); for (int i = 1; i < bboxes.Length(); i++) { Rect b = bboxes[i]; g.DrawString(trans[i - 1].ToString(), font, txtBrush, b.x0, height + 1); } txtBrush.Dispose(); } return(newbitmap); }
public static void remove_small_components(Intarray segmentation, int w = 5, int h = 4) { if (NarrayUtil.Max(segmentation) > 100000) { throw new Exception("remove_small_components: to many segments"); } Narray <Rect> bboxes = new Narray <Rect>(); ImgLabels.bounding_boxes(ref bboxes, segmentation); for (int i = 1; i < bboxes.Length(); i++) { Rect b = bboxes[i]; if (b.Width() < w && b.Height() < h) { 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] = 0; } } } } } }
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 Extract(Narray <Floatarray> outarrays, Floatarray inarray) { outarrays.Clear(); Floatarray image = outarrays.Push(new Floatarray()); image.Copy(inarray); }
public static unsafe Bitmap GrayNarrayToBitmap(Narray <byte> image) { if (image.Rank() != 2) { throw new Exception("Narray must be rank 2"); } int w = image.Dim(0); int h = image.Dim(1); // create new image Bitmap bitmap = new Bitmap(w, h, PixelFormat.Format8bppIndexed); // lock destination bitmap data BitmapData destinationData = bitmap.LockBits( new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, bitmap.PixelFormat); int pixelOffset = 1; int dstOffset = destinationData.Stride - w * pixelOffset; byte *dst = (byte *)destinationData.Scan0.ToPointer(); // for each line for (int y = h - 1; y >= 0; y--) { // for each pixel for (int x = 0; x < w; x++, dst += pixelOffset) { *dst = image[x, y]; } dst += dstOffset; } // unlock destination image bitmap.UnlockBits(destinationData); return(bitmap); }
public override void FindBestCuts() { unchecked { for (int i = 0; i < cutcosts.Length(); i++) { NarrayUtil.ExtPut(dimage, i, (int)(cutcosts[i] + 10), 0xff0000); } for (int i = 0; i < cutcosts.Length(); i++) { NarrayUtil.ExtPut(dimage, i, (int)(min_thresh + 10), 0x800000); } } Floatarray temp = new Floatarray(); Gauss.Gauss1d(temp, cutcosts, 3.0f); cutcosts.Move(temp); SegmRoutine.local_minima(ref bestcuts, cutcosts, min_range, min_thresh); for (int i = 0; i < bestcuts.Length(); i++) { Narray <Point> cut = cuts[bestcuts[i]]; for (int j = 0; j < cut.Length(); j++) { Point p = cut[j]; NarrayUtil.ExtPut(dimage, p.X, p.Y, 0x00ff00); } } ///-if(debug.Length > 0) write_image_packed(debug, dimage); // dshow1d(cutcosts,"Y"); //dshow(dimage,"Y"); }
/// <summary> ///A test for Rank ///</summary> public void RankTestHelper <T>() { Narray <T> target = new Narray <T>(3, 2, 4); int expected = 3; Assert.AreEqual(expected, target.Rank()); }
/// <summary> /// Extract the character by bounding rectangle (no masking). /// </summary> void extractSlicedWithBackground <T>(Narray <T> outa, Narray <T> source, T dflt, int index, int grow = 0) { if (!labels.SameDims(source)) { throw new Exception("ASSERT: labels.SameDims(source)"); } Bytearray mask = new Bytearray(); Rect r; GetMask(out r, ref mask, index, grow); int x = r.x0, y = r.y0, w = r.Width(), h = r.Height(); outa.Resize(w, source.Dim(1)); outa.Fill(dflt); for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { if (mask[i, j] > 0) { outa[i, j + y] = source[i + x, j + y]; } } } }
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 pad_by <T>(ref Narray <T> image, int px, int py, T value = default(T)) { if (px == 0 && py == 0) { return; } int w = image.Dim(0), h = image.Dim(1); Narray <T> temp = new Narray <T>(w + 2 * px, h + 2 * py); temp.Fill(value); for (int i = 0; i < image.Dim(0); i++) { for (int j = 0; j < image.Dim(1); j++) { unchecked { if ((uint)(i + px) >= (uint)(temp.Dim(0)) || (uint)(j + py) >= (uint)(temp.Dim(1))) { continue; } } temp[i + px, j + py] = image[i, j]; } } image.Move(temp); }
public Dataset8() { DatatypeSize = sizeof(sbyte); // one byte data = new Narray<sbyte>(); classes = new Intarray(); nc = -1; nf = -1; }
public static void RowGet(Narray <byte> outv, Narray <byte> data, int row) { outv.Resize(data.Dim(1)); for (int i = 0; i < outv.Length(); i++) { outv[i] = data[row, i]; } }
public static void RowGet(Narray <byte> outv, Narray <float> data, int row) { outv.Resize(data.Dim(1)); for (int i = 0; i < outv.Length(); i++) { outv[i] = Convert.ToByte(data[row, i] * 255); } }
public LineSource() { PDef("retrain", 0, "set parameters for retraining"); PDef("randomize", 1, "randomize lines"); PDef("cbookstore", "SmartBookStore", "bookstore using for reading pages"); bookstores = new Narray <IBookStore>(); all_lines = new Intarray(); }
public Dataset8() { DatatypeSize = sizeof(sbyte); // one byte data = new Narray <sbyte>(); classes = new Intarray(); nc = -1; nf = -1; }
public static void getd1 <T, S>(Narray <T> image, Narray <S> slice, int index) { slice.Resize(image.Dim(0)); for (int i = 0; i < image.Dim(0); i++) { slice.UnsafePut(i, (S)Convert.ChangeType(image.UnsafeAt(i, index), typeof(S))); } }
/// <summary> /// Brushfire transformation using 2-norm. /// </summary> public static void brushfire_2(ref Floatarray distance, ref Narray <Point> source, float maxdist) { BrushFire.Go(Metric2.Default, ref distance, ref source, maxdist); for (int i = 0; i < distance.Length1d(); i++) { distance.Put1d(i, (float)Math.Sqrt(distance.At1d(i))); } }
public override void Extract(Narray <Floatarray> outarrays, Floatarray inarray) { outarrays.Clear(); Floatarray image = outarrays.Push(); rescale(image, inarray); //image /= Math.Max(1.0f, NarrayUtil.Max(image)); }
/// <summary> ///A test for Dim ///</summary> public void DimTestHelper <T>() { var target = new Narray <T>(10, 11, 22); Assert.AreEqual(10, target.Dim(0)); Assert.AreEqual(11, target.Dim(1)); Assert.AreEqual(22, target.Dim(2)); }
public List<List<float>> SpaceCosts(List<Candidate> candidates, Bytearray image) { /* Given a list of character recognition candidates and their classifications, and an image of the corresponding text line, compute a list of pairs of costs for putting/not putting a space after each of the candidate characters. The basic idea behind this simple algorithm is to try larger and larger horizontal closing operations until most of the components start having a "wide" aspect ratio; that's when characters have merged into words. The remaining whitespace should be spaces. This is just a simple stopgap measure; it will be replaced with trainable space modeling. */ int w = image.Dim(0); int h = image.Dim(1); Bytearray closed = new Bytearray(); int r; for (r = 0; r < maxrange; r++) { if (r > 0) { closed.Copy(image); Morph.binary_close_circle(closed, r); } else closed.Copy(image); Intarray labeled = new Intarray(); labeled.Copy(closed); ImgLabels.label_components(ref labeled); Narray<Rect> rects = new Narray<Rect>(); ImgLabels.bounding_boxes(ref rects, labeled); Floatarray aspects = new Floatarray(); for (int i = 0; i < rects.Length(); i++) { Rect rect = rects[i]; float aspect = rect.Aspect(); aspects.Push(aspect); } float maspect = NarrayUtil.Median(aspects); if (maspect >= this.aspect_threshold) break; } // close with a little bit of extra space closed.Copy(image); Morph.binary_close_circle(closed, r+1); // compute the remaining aps //Morph.binary_dilate_circle(); // every character box that ends near a cap gets a space appended return null; }
/// <summary> ///A test for Last ///</summary> public void LastTestHelper <T>() { var target = new Narray <T>(460); var expected = (T)Convert.ChangeType(99, typeof(T)); Assert.AreNotEqual(expected, target.Last()); target.Put1d(target.Length1d() - 1, expected); Assert.AreEqual(expected, target.Last()); }
public UnionFind(int max = 10000) { p = new Narray<int>(); p.Resize(max); p.Fill(-1); rank = new Narray<int>(); rank.Resize(max); rank.Fill(-1); }
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 UnionFind(int max = 10000) { p = new Narray <int>(); p.Resize(max); p.Fill(-1); rank = new Narray <int>(); rank.Resize(max); rank.Fill(-1); }
/// <summary> ///A test for Push ///</summary> public void PushTestHelper <T>() { int size = 12; Narray <T> target = new Narray <T>(size); T value = (T)Convert.ChangeType(99, typeof(T)); target.Push(value); Assert.AreEqual(size + 1, target.Length1d()); Assert.AreEqual(value, target.At1d(target.Length1d() - 1)); }
/// <summary> ///A test for GrowTo ///</summary> public void GrowToTestHelper <T>() { var target = new Narray <T>(12); Assert.AreEqual(1, target.Rank()); Assert.AreEqual(12, target.Length1d()); target.GrowTo(45); Assert.AreEqual(1, target.Rank()); Assert.AreEqual(45, target.Length1d()); }
/// <summary> ///A test for At1d ///</summary> public void At1dTestHelper <T>() { var target = new Narray <T>(120); int i = 0; T expected = default(T); Assert.AreEqual(expected, target.At1d(i)); Assert.AreEqual(expected, target.At1d(10)); Assert.AreEqual(expected, target.At1d(100)); }
public RowDataset8(Narray <byte> ds, Intarray cs) : this() { for (int i = 0; i < ds.Dim(0); i++) { RowGet(data.Push(new Narray <byte>()), ds, i); classes.Push(cs[i]); } Recompute(); }
public RowDataset8(Narray<byte> ds, Intarray cs) : this() { for (int i = 0; i < ds.Dim(0); i++) { RowGet(data.Push(new Narray<byte>()), ds, i); classes.Push(cs[i]); } Recompute(); }
/// <summary> ///A test for Put1d ///</summary> public void Put1dTestHelper <T>() { Narray <T> target = new Narray <T>(15, 10); int i0 = 50; T value = (T)Convert.ChangeType(99, typeof(T)); Assert.AreEqual(default(T), target.At1d(i0)); target.Put1d(i0, value); Assert.AreEqual(value, target.At1d(i0)); }
public StdInput(Narray<float> floatarray) { alloc_(floatarray.Dim(1), floatarray.Dim(0)); int yput; for (int y = 0; y < Height; y++) { yput = Height - y - 1; for (int x = 0; x < Width; x++) Put(yput, x, Convert.ToByte(floatarray[x, y] * 255)); } }
public StdInput(Narray<byte> bytearray) { alloc_(bytearray.Dim(1), bytearray.Dim(0)); int yput; for (int y = 0; y < Height; y++) { yput = Height - y - 1; for(int x=0; x < Width; x++) Put(yput, x, bytearray[x, y]); } }
public static int Max(Narray<sbyte> a) { sbyte value = a.At1d(0); for (int i = 1; i < a.Length1d(); i++) { sbyte nvalue = a.At1d(i); if (nvalue <= value) continue; value = nvalue; } return value; }
public CurvedCutSegmenterImpl() { wimage = new Intarray(); costs = new Intarray(); sources = new Intarray(); bestcuts = new Intarray(); dimage = new Intarray(); cuts = new Narray<Narray<Point>>(); cutcosts = new Floatarray(); //params_for_chars(); params_for_lines(); //params_from_hwrec_c(); }
/// <summary> /// SGI compiler bug: can't make this a template function with /// an unused last argument for the template parameter /// </summary> public static void Go(Metric m, ref Floatarray distance, ref Narray<Point> source, float maxdist) { const float BIG = 1e38f; int w = distance.Dim(0); int h = distance.Dim(1); distance.Resize(w,h); source.Resize(w,h); Queue<Point> queue = new Queue<Point>(w*h); int i, j; for(i = 0; i < w; i++) for(j = 0; j < h; j++) { if(distance.At(i, j) > 0) { queue.Enqueue(new Point(i, j)); distance[i, j] = 0; source[i, j] = new Point(i, j); } else { distance[i, j] = BIG; source[i, j] = new Point(-1, -1); } } while(queue.Count != 0) { Point q = queue.Dequeue(); float d = m.metric(new Point(q.X - 1, q.Y), source.At(q.X, q.Y)); if(d <= maxdist && q.X > 0 && d < distance.At(q.X - 1, q.Y)) { queue.Enqueue(new Point(q.X - 1, q.Y)); source[q.X - 1, q.Y] = source.At(q.X, q.Y); distance[q.X - 1, q.Y] = d; } d = m.metric(new Point(q.X, q.Y - 1), source.At(q.X, q.Y)); if(d <= maxdist && q.Y > 0 && d < distance.At(q.X, q.Y - 1)) { queue.Enqueue(new Point(q.X, q.Y - 1)); source[q.X, q.Y - 1] = source.At(q.X, q.Y); distance[q.X, q.Y - 1] = d; } d = m.metric(new Point(q.X + 1, q.Y), source.At(q.X, q.Y)); if(d <= maxdist && q.X < w - 1 && d < distance.At(q.X + 1, q.Y)) { queue.Enqueue(new Point(q.X + 1, q.Y)); source[q.X + 1, q.Y] = source.At(q.X, q.Y); distance[q.X + 1, q.Y] = d; } d = m.metric(new Point(q.X, q.Y + 1), source.At(q.X, q.Y)); if(d <= maxdist && q.Y < h - 1 && d < distance.At(q.X, q.Y + 1)) { queue.Enqueue(new Point(q.X, q.Y + 1)); source[q.X, q.Y + 1] = source.At(q.X, q.Y); distance[q.X, q.Y + 1] = d; } } }
public static Bitmap ConvertCharsegToBitmapRecolor(Intarray charseg, string trans = "") { Intarray cseg = new Intarray(); cseg.Copy(charseg); Narray<Rect> bboxes = new Narray<Rect>(); //SegmRoutine.make_line_segmentation_black(cseg); ImgLabels.bounding_boxes(ref bboxes, cseg); SegmRoutine.make_line_segmentation_white(cseg); ImgLabels.simple_recolor(cseg); return DrawSegmentTranscript( DrawSegmentNumbers( ImgRoutine.NarrayToRgbBitmap(cseg), bboxes), bboxes, trans); }
public virtual void Extract(Floatarray outa, Floatarray ina) { outa.Clear(); Narray<Floatarray> items = new Narray<Floatarray>(); Extract(items, ina); //int num = 0; for (int i = 0; i < items.Length(); i++) { Floatarray a = items[i]; outa.ReserveTo(outa.Length() + a.Length()); // optimization for (int j = 0; j < a.Length(); j++) { outa.Push(a.At1d(j)); //outa[num++] = a.At1d(j); } } }
/// <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 Dataset8(Narray<sbyte> data, Intarray classes) : this() { data.Copy(data); classes.Copy(classes); if (classes.Length() > 0) { nc = NarrayUtil.Max(classes) + 1; nf = data.Dim(1); //CHECK_ARG(NarrayUtil.Min(data) > -100 && NarrayUtil.Max(data) < 100, "min(data)>-100 && max(data)<100"); CHECK_ARG(NarrayUtil.Min(classes) >= -1 && NarrayUtil.Max(classes) < 10000, "min(classes)>=-1 && max(classes)<10000"); } else { nc = 0; nf = -1; } }
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 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 DpSegmenter() { wimage = new Floatarray(); costs = new Intarray(); sources = new Intarray(); bestcuts = new Intarray(); dimage = new Intarray(); cuts = new Narray<Narray<Point>>(); cutcosts = new Floatarray(); PDef("down_cost", 0, "cost of down step"); PDef("outside_diagonal_cost", 1, "cost of outside diagonal step to the left"); PDef("outside_diagonal_cost_r", 1, "cost of outside diagonal step to the right"); PDef("inside_diagonal_cost", 4, "cost of inside diagonal step"); PDef("outside_weight", 0, "cost of outside pixel"); PDef("inside_weight", 4, "cost of inside pixel"); PDef("cost_smooth", 2.0, "smoothing parameter for costs"); PDef("min_range", 1, "min range value"); PDef("min_thresh", 80.0, "min threshold value"); PDef("component_segmentation", 0, "also perform connected component segmentation"); PDef("fix_diacritics", 1, "group dots above characters back with those characters"); PDef("fill_holes", 1, "fill holes prior to dp segmentation (for cases like oo)"); PDef("debug", "none", "debug output file"); }
public override void FindAllCuts() { int w = wimage.Dim(0), h = wimage.Dim(1); // initialize dimensions of cuts, costs etc cuts.Resize(w); cutcosts.Resize(w); costs.Resize(w, h); sources.Resize(w, h); costs.Fill(1000000000); for (int i = 0; i < w; i++) costs[i, 0] = 0; sources.Fill(-1); limit = where; direction = 1; Step(0, w, 0); for (int x = 0; x < w; x++) { cutcosts[x] = costs[x, where]; cuts[x] = new Narray<Point>(); cuts[x].Clear(); // bottom should probably be initialized with 2*where instead of // h, because where cannot be assumed to be h/2. In the most extreme // case, the cut could go through 2 pixels in each row Narray<Point> bottom = new Narray<Point>(); int i = x, j = where; while (j >= 0) { bottom.Push(new Point(i, j)); i = sources[i, j]; j--; } //cuts(x).resize(h); for (i = bottom.Length() - 1; i >= 0; i--) cuts[x].Push(bottom[i]); } costs.Fill(1000000000); for (int i = 0; i < w; i++) costs[i, h - 1] = 0; sources.Fill(-1); limit = where; direction = -1; Step(0, w, h - 1); for (int x = 0; x < w; x++) { cutcosts[x] += costs[x, where]; // top should probably be initialized with 2*(h-where) instead of // h, because where cannot be assumed to be h/2. In the most extreme // case, the cut could go through 2 pixels in each row Narray<Point> top = new Narray<Point>(); int i = x, j = where; while (j < h) { if (j > where) top.Push(new Point(i, j)); i = sources[i, j]; j++; } for (i = 0; i < top.Length(); i++) cuts[x].Push(top[i]); } // add costs for line "where" for (int x = 0; x < w; x++) { cutcosts[x] += wimage[x, where]; } }
public void EstimateSpaceSize() { Intarray labels = new Intarray(); labels.Copy(segmentation); ImgLabels.label_components(ref labels); Narray<Rect> boxes = new Narray<Rect>(); ImgLabels.bounding_boxes(ref boxes, labels); Floatarray distances = new Floatarray(); distances.Resize(boxes.Length()); distances.Fill(99999f); for (int i = 1; i < boxes.Length(); i++) { Rect b = boxes[i]; for (int j = 1; j < boxes.Length(); j++) { Rect n = boxes[j]; int delta = n.x0 - b.x1; if (delta < 0) continue; if (delta >= distances[i]) continue; distances[i] = delta; } } float interchar = NarrayUtil.Fractile(distances, PGetf("space_fractile")); space_threshold = interchar * PGetf("space_multiplier"); // impose some reasonable upper and lower bounds float xheight = 10.0f; // FIXME space_threshold = Math.Max(space_threshold, PGetf("space_min") * xheight); space_threshold = Math.Min(space_threshold, PGetf("space_max") * xheight); }
/// <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 override void Extract(Narray<Floatarray> outarrays, Floatarray inarray) { outarrays.Clear(); Floatarray input = new Floatarray(); input.Copy(inarray); int w = input.Dim(0), h = input.Dim(1); Floatarray a = new Floatarray(); // working array int csize = PGeti("csize"); // get rid of small components SegmRoutine.erase_small_components(input, PGetf("minsize"), PGetf("threshold")); // compute a thresholded version for morphological operations Bytearray thresholded = new Bytearray(); OcrRoutine.threshold_frac(thresholded, input, PGetf("threshold")); // compute a smoothed version of the input for gradient computations float sigma = PGetf("gradsigma"); Floatarray smoothed = new Floatarray(); smoothed.Copy(input); Gauss.Gauss2d(smoothed, sigma, sigma); // x gradient a.Resize(w, h); for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { float delta; if (i == 0) delta = 0f; else delta = smoothed[i, j] - smoothed[i - 1, j]; a[i, j] = delta; } } Floatarray xgrad = outarrays.Push(new Floatarray()); OcrRoutine.scale_to(xgrad, a, csize, PGetf("noupscale"), PGetf("aa")); for (int j = 0; j < csize; j++) { for (int i = 0; i < csize; i++) { if (j % 2 == 0) xgrad[i, j] = Math.Max(xgrad[i, j], 0f); else xgrad[i, j] = Math.Min(xgrad[i, j], 0f); } } // y gradient a.Resize(w, h); for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { float delta; if (j == 0) delta = 0f; else delta = smoothed[i, j] - smoothed[i, j - 1]; a[i, j] = delta; } } Floatarray ygrad = outarrays.Push(new Floatarray()); OcrRoutine.scale_to(ygrad, a, csize, PGetf("noupscale"), PGetf("aa")); for (int i = 0; i < csize; i++) { for (int j = 0; j < csize; j++) { if (i % 2 == 0) ygrad[i, j] = Math.Max(ygrad[i, j], 0f); else ygrad[i, j] = Math.Min(ygrad[i, j], 0f); } } // junctions, endpoints, and holes Floatarray junctions = new Floatarray(); Floatarray endpoints = new Floatarray(); Floatarray holes = new Floatarray(); Bytearray junctions1 = new Bytearray(); Bytearray endpoints1 = new Bytearray(); Bytearray holes1 = new Bytearray(); Bytearray dilated = new Bytearray(); Bytearray binary = new Bytearray(); junctions.MakeLike(input, 0f); endpoints.MakeLike(input, 0f); holes.MakeLike(input, 0f); int n = PGeti("n"); float step = PGetf("step"); int bs = PGeti("binsmooth"); for(int i=0; i<n; i++) { sigma = step * i; if(bs > 0) OcrRoutine.binsmooth(binary, input, sigma); else { binary.Copy(thresholded); Morph.binary_dilate_circle(binary, (int)(sigma)); } OcrRoutine.skeletal_features(endpoints1, junctions1, binary, 0.0f, 0.0f); NarrayUtil.Greater(junctions1, (byte)0, (byte)0, (byte)1); junctions.Copy(junctions1); NarrayUtil.Greater(endpoints1, (byte)0, (byte)0, (byte)1); endpoints.Copy(endpoints1); SegmRoutine.extract_holes(ref holes1, binary); NarrayUtil.Greater(holes1, (byte)0, (byte)0, (byte)1); holes.Copy(holes1); } junctions *= 1.0f / (float)n; endpoints *= 1.0f / (float)n; holes *= 1.0f / (float)n; OcrRoutine.scale_to(outarrays.Push(new Floatarray()), junctions, csize, PGetf("noupscale"), PGetf("aa")); OcrRoutine.scale_to(outarrays.Push(new Floatarray()), endpoints, csize, PGetf("noupscale"), PGetf("aa")); OcrRoutine.scale_to(outarrays.Push(new Floatarray()), holes, csize, PGetf("noupscale"), PGetf("aa")); }
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]); } }
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 override void Binarize(Bytearray bin_image, Bytearray gray_image) { w = PGeti("w"); k = (float)PGetf("k"); whalf = w >> 1; // fprintf(stderr,"[sauvola %g %d]\n",k,w); if(k<0.001 || k>0.999) throw new Exception("Binarize: CHECK_ARG(k>=0.001 && k<=0.999)"); if(w==0 || k>=1000) throw new Exception("Binarize: CHECK_ARG(w>0 && k<1000)"); if(bin_image.Length1d() != gray_image.Length1d()) bin_image.MakeLike(gray_image); if(NarrayUtil.contains_only(gray_image, (byte)0, (byte)255)) { bin_image.Copy(gray_image); return; } int image_width = gray_image.Dim(0); int image_height = gray_image.Dim(1); whalf = w >> 1; // Calculate the integral image, and integral of the squared image Narray<long> integral_image = new Narray<long>(), rowsum_image = new Narray<long>(); Narray<long> integral_sqimg = new Narray<long>(), rowsum_sqimg = new Narray<long>(); integral_image.MakeLike(gray_image); rowsum_image.MakeLike(gray_image); integral_sqimg.MakeLike(gray_image); rowsum_sqimg.MakeLike(gray_image); int xmin,ymin,xmax,ymax; double diagsum,idiagsum,diff,sqdiagsum,sqidiagsum,sqdiff,area; double mean,std,threshold; for (int j = 0; j < image_height; j++) { rowsum_image[0, j] = gray_image[0, j]; rowsum_sqimg[0, j] = gray_image[0, j] * gray_image[0, j]; } for (int i = 1; i < image_width; i++) { for (int j = 0; j < image_height; j++) { rowsum_image[i, j] = rowsum_image[i - 1, j] + gray_image[i, j]; rowsum_sqimg[i, j] = rowsum_sqimg[i - 1, j] + gray_image[i, j] * gray_image[i, j]; } } for (int i = 0; i < image_width; i++) { integral_image[i, 0] = rowsum_image[i, 0]; integral_sqimg[i, 0] = rowsum_sqimg[i, 0]; } for (int i = 0; i < image_width; i++) { for (int j = 1; j < image_height; j++) { integral_image[i, j] = integral_image[i, j - 1] + rowsum_image[i, j]; integral_sqimg[i, j] = integral_sqimg[i, j - 1] + rowsum_sqimg[i, j]; } } //Calculate the mean and standard deviation using the integral image for(int i=0; i<image_width; i++){ for(int j=0; j<image_height; j++){ xmin = Math.Max(0,i-whalf); ymin = Math.Max(0, j - whalf); xmax = Math.Min(image_width - 1, i + whalf); ymax = Math.Min(image_height - 1, j + whalf); area = (xmax-xmin+1)*(ymax-ymin+1); // area can't be 0 here // proof (assuming whalf >= 0): // we'll prove that (xmax-xmin+1) > 0, // (ymax-ymin+1) is analogous // It's the same as to prove: xmax >= xmin // image_width - 1 >= 0 since image_width > i >= 0 // i + whalf >= 0 since i >= 0, whalf >= 0 // i + whalf >= i - whalf since whalf >= 0 // image_width - 1 >= i - whalf since image_width > i // --IM if (area <= 0) throw new Exception("Binarize: area can't be 0 here"); if (xmin == 0 && ymin == 0) { // Point at origin diff = integral_image[xmax, ymax]; sqdiff = integral_sqimg[xmax, ymax]; } else if (xmin == 0 && ymin > 0) { // first column diff = integral_image[xmax, ymax] - integral_image[xmax, ymin - 1]; sqdiff = integral_sqimg[xmax, ymax] - integral_sqimg[xmax, ymin - 1]; } else if (xmin > 0 && ymin == 0) { // first row diff = integral_image[xmax, ymax] - integral_image[xmin - 1, ymax]; sqdiff = integral_sqimg[xmax, ymax] - integral_sqimg[xmin - 1, ymax]; } else { // rest of the image diagsum = integral_image[xmax, ymax] + integral_image[xmin - 1, ymin - 1]; idiagsum = integral_image[xmax, ymin - 1] + integral_image[xmin - 1, ymax]; diff = diagsum - idiagsum; sqdiagsum = integral_sqimg[xmax, ymax] + integral_sqimg[xmin - 1, ymin - 1]; sqidiagsum = integral_sqimg[xmax, ymin - 1] + integral_sqimg[xmin - 1, ymax]; sqdiff = sqdiagsum - sqidiagsum; } mean = diff/area; std = Math.Sqrt((sqdiff - diff*diff/area)/(area-1)); threshold = mean*(1+k*((std/128)-1)); if(gray_image[i,j] < threshold) bin_image[i,j] = 0; else bin_image[i,j] = (byte)(MAXVAL-1); } } if(PGeti("debug_binarize") > 0) { ImgIo.write_image_gray("debug_binarize.png", bin_image); } }
public static void RowGet(Narray<byte> outv, Narray<float> data, int row) { outv.Resize(data.Dim(1)); for (int i = 0; i < outv.Length(); i++) outv[i] = Convert.ToByte(data[row, i] * 255); }
public static void RowGet(Narray<byte> outv, Narray<byte> data, int row) { outv.Resize(data.Dim(1)); for (int i = 0; i < outv.Length(); i++) outv[i] = data[row, i]; }