/// <summary> /// Train on a text line. /// <remarks>Usage is: call addTrainingLine with training data, then call finishTraining /// The state of the object is undefined between calling addTrainingLine and finishTraining, and it is /// an error to call recognizeLine before finishTraining completes. This allows both batch /// and incemental training. /// NB: you might train on length 1 strings for single character training /// and might train on words if line alignment is not working /// (well, for some training data)</remarks> /// </summary> public void AddTrainingLine(Intarray cseg, string tr) { Bytearray gimage = new Bytearray(); ClassifierUtil.segmentation_as_bitmap(gimage, cseg); AddTrainingLine(cseg, gimage, tr); }
public static void write_image_gray(string path, Bytearray image) { Bitmap bitmap = ImgRoutine.NarrayToRgbBitmap(image); bitmap.Save(path); bitmap.Dispose(); }
public static void binary_close_circle(Bytearray image, int r) { if (r == 0) return; binary_dilate_circle(image, r); binary_erode_circle(image, r); }
public override bool GetLine(Bytearray image, int page, int line, string variant = null) { string s = PathFile(page, line, variant, "png"); if (!File.Exists(s)) return false; ImgIo.read_image_gray(image, s); return true; }
public static Bitmap read_image_gray(Bytearray image, string path) { Bitmap bitmap = LoadBitmapFromFile(path); image.Resize(bitmap.Width, bitmap.Height); ImgRoutine.NarrayFromBitmap(image, bitmap); return bitmap; }
public static void make_binary(Bytearray image) { for (int i = 0; i < image.Length1d(); i++) { image.Put1d(i, (byte)(image.At1d(i) > 0 ? 255 : 0)); } }
/// <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]; } } } }
/// <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); } }
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 void Binarize(Bytearray outarray, Floatarray inarray) { Bytearray image = new Bytearray(); image.Copy(inarray); Binarize(outarray, image); }
public override void Binarize(Bytearray outa, Bytearray ina_) { fraction = (float)PGetf("f"); Floatarray ina = new Floatarray(); ina.Copy(ina_); binarize_by_range(outa, ina, fraction); }
public static void binary_close_rect(Bytearray image, int rw, int rh) { if (rw == 0 && rh == 0) return; binary_dilate_rect(image, rw, rh); binary_erode_rect(image, rw, rh); }
public void Image(string description, Bytearray a, float zoom = 100f) { if (verbose) { writer.WriteLine(String.Format("image {0} w:{1}, h:{2}", description, a.Dim(0), a.Dim(1))); } }
public void SetLine(Bytearray image) { CHECK_ARG(image.Dim(1) < PGeti("maxheight"), "image.Dim(1) < PGeti(\"maxheight\")"); // run the segmenter /*Narray<Rect> bboxes = new Narray<Rect>(); * Intarray iar = new Intarray(); * iar.Copy(image); * ImgLabels.bounding_boxes(ref bboxes, iar);*/ //Console.WriteLine("IMG SETLINE: imin:{0} imax:{1}", NarrayUtil.ArgMin(iar), NarrayUtil.ArgMax(iar)); //Console.WriteLine("INDEX_BLACK:{0} {1} {2} {3}", bboxes[0].x0, bboxes[0].y0, bboxes[0].x1, bboxes[0].y1); //ImgIo.write_image_gray("image.png", image); OcrRoutine.binarize_simple(binarized, image); segmenter.Object.Charseg(ref segmentation, binarized); /*Intarray segm = new Intarray(); * segm.Copy(segmentation); * ImgLabels.simple_recolor(segm); * ImgIo.write_image_packed("segm_image.png", segm);*/ //NarrayUtil.Sub(255, binarized); SegmRoutine.make_line_segmentation_black(segmentation); SegmRoutine.remove_small_components(segmentation, 3, 3); // i add this line ImgLabels.renumber_labels(segmentation, 1); // set up the grouper grouper.Object.SetSegmentation(segmentation); }
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 TestArrays() { string imgfn = "test-c3.png"; // load Bytearray Bytearray ba = new Bytearray(1, 1); ImgIo.read_image_gray(ba, imgfn); OcrRoutine.Invert(ba); //NarrayUtil.Sub((byte)255, image); byte[] bytes1 = ba.To1DArray(); NarrayShow.ShowConsole(ba); StdInput linput1 = new StdInput(ba); Console.WriteLine(); // load StdInput Bitmap bitmap = ImgIo.LoadBitmapFromFile(imgfn); StdInput linput2 = StdInput.FromBitmap(bitmap); //NarrayShow.ShowConsole(linput2); // test convert Floatarray fa = linput2.ToFloatarray(); StdInput linput3 = new StdInput(fa); Console.WriteLine("Arrays is identical? {0}", Equals(linput1.GetDataBuffer(), linput2.GetDataBuffer())); Console.WriteLine("Arrays is identical? {0}", Equals(linput2.GetDataBuffer(), linput3.GetDataBuffer())); }
private void ProcessSegmentationMethod(object sender, RoutedEventArgs e) { string strSermenterName = (sender as Control).Tag.ToString(); ISegmentLine segmenter = ComponentCreator.MakeComponent <ISegmentLine>(strSermenterName); if (segmenter == null || currBookLine == null) { return; } // приведем к чернобелому Bytearray image = currBookLine.ImageBytearray; //IBinarize binarizer = new BinarizeByOtsu(); //binarizer.Binarize(image, image); OcrRoutine.binarize_simple(image, image); // сегментация Intarray charseg = new Intarray(); segmenter.Charseg(ref charseg, image); // фон равен 0 SegmRoutine.make_line_segmentation_black(charseg); // удалим маленькие сегменты SegmRoutine.remove_small_components(charseg, 3, 3); ImgLabels.renumber_labels(charseg, 1); currBookLine.CharsegIntarray = charseg; CurrSegmentsCount = NarrayUtil.Max(charseg); // Show segmented image ShowCharsegImage(charseg, (currBookLine.HaveTranscript && CurrSegmentsCount == currBookLine.Transcript.Length) ? currBookLine.Transcript : ""); // to enable save button EnableCharsegCmdButtons(); }
public static void threshold_frac(Bytearray thresholded, Floatarray input, float frac) { float minofinput = NarrayUtil.Min(input); float theta = frac * (NarrayUtil.Max(input) - minofinput) + minofinput; binarize_with_threshold(thresholded, input, theta); }
public static int average_on_border(Bytearray a) { int sum = 0; int right = a.Dim(0) - 1; int top = a.Dim(1) - 1; for (int x = 0; x < a.Dim(0); x++) { sum += a[x, 0]; } for (int x = 0; x < a.Dim(0); x++) { sum += a[x, top]; } for (int y = 1; y < top; y++) { sum += a[0, y]; } for (int y = 1; y < top; y++) { sum += a[right, y]; } // If average border intensity is between 127-128, inverting the // image does not work correctly float average_border_intensity = sum / ((right + top) * 2.0f); if (!(average_border_intensity <= 127 || average_border_intensity >= 128)) { Console.WriteLine("average border intensity is between 127-128, inverting the image does not work correctly"); } return(sum / ((right + top) * 2)); }
public void TestSimple() { Global.SetEnv("debug", Global.GetEnv("debug") + ""); // image file name to recognize string imgFileName = "line.png"; string imgCsegFileName = "line.cseg.png"; string imgTranscriptFileName = "line.txt"; // line recognizer Linerec lrec = (Linerec)Linerec.LoadLinerec("default.model"); //Linerec lrec = (Linerec)Linerec.LoadLinerec("2m2-reject.cmodel"); //Linerec lrec = (Linerec)Linerec.LoadLinerec("multi3.cmodel"); //Linerec lrec = (Linerec)Linerec.LoadLinerec("latin-ascii.model"); lrec.Info(); // language model OcroFST default_lmodel = OcroFST.MakeOcroFst(); default_lmodel.Load("default.fst"); OcroFST lmodel = default_lmodel; // read image Bytearray image = new Bytearray(1, 1); ImgIo.read_image_gray(image, imgFileName); // recognize! OcroFST fst = OcroFST.MakeOcroFst(); Intarray rseg = new Intarray(); lrec.RecognizeLine(rseg, fst, image); // show result 1 string resStr; fst.BestPath(out resStr); Console.WriteLine("Fst BestPath: {0}", resStr); // find result 2 Intarray v1 = new Intarray(); Intarray v2 = new Intarray(); Intarray inp = new Intarray(); Intarray outp = new Intarray(); Floatarray c = new Floatarray(); BeamSearch.beam_search(v1, v2, inp, outp, c, fst, lmodel, 100); FstUtil.remove_epsilons(out resStr, outp); Console.WriteLine("Fst BeamSearch: {0}", resStr); Intarray cseg = new Intarray(); SegmRoutine.rseg_to_cseg(cseg, rseg, inp); SegmRoutine.make_line_segmentation_white(cseg); ImgLabels.simple_recolor(cseg); // for human readable ImgIo.write_image_packed(imgCsegFileName, cseg); File.WriteAllText(imgTranscriptFileName, resStr.Replace(" ", "")); }
public Linerec(string classifier1 = "latin"/*none*/, string extractor1 = "scaledfe", string segmenter1 = "DpSegmenter", int use_reject = 1) { transcript = ""; //line = new Bytearray(); segmentation = new Intarray(); binarized = new Bytearray(); // component choices PDef("classifier", classifier1, "character classifier"); PDef("extractor", extractor1, "feature extractor"); PDef("segmenter", segmenter1, "line segmenter"); PDef("grouper", "SimpleGrouper", "line grouper"); // retraining PDef("cpreload", "none", "classifier to be loaded prior to training"); // debugging PDef("verbose", 0, "verbose output from glinerec"); // outputs PDef("use_priors", 0, "correct the classifier output by priors"); PDef("use_reject", use_reject, "use a reject class (use posteriors only and train on junk chars)"); PDef("maxcost", 20.0, "maximum cost of a character to be added to the output"); PDef("minclass", 32, "minimum output class to be added (default=unicode space)"); PDef("minprob", 1e-9, "minimum probability for a character to appear in the output at all"); PDef("invert", 1, "invert the input line prior to char extraction"); // segmentation PDef("maxrange", 5, "maximum number of components that are grouped together"); // sanity limits on input PDef("minheight", 9, "minimum height of input line"); PDef("maxheight", 300, "maximum height of input line"); PDef("maxaspect", 2.0, "maximum height/width ratio of input line"); // space estimation (FIXME factor this out eventually) PDef("space_fractile", 0.5, "fractile for space estimation"); PDef("space_multiplier", 2.0, "multipler for space estimation"); PDef("space_min", 0.2, "minimum space threshold (in xheight)"); PDef("space_max", 1.1, "maximum space threshold (in xheight)"); PDef("space_yes", 1.0, "cost of inserting a space"); PDef("space_no", 5.0, "cost of not inserting a space"); // back compability PDef("minsize_factor", 0.0, ""); counts = new Intarray(); segmenter = new ComponentContainerISegmentLine(ComponentCreator.MakeComponent<ISegmentLine>(PGet("segmenter"))); grouper = new ComponentContainerIGrouper(ComponentCreator.MakeComponent<IGrouper>(PGet("grouper"))); classifier = new ComponentContainerIModel(IModel.MakeModel(PGet("classifier"))); TryAttachClassifierEvent(classifier.Object); Persist(classifier, "classifier"); Persist(counts, "counts"); Persist(segmenter, "segmenter"); Persist(grouper, "grouper"); if (!classifier.IsEmpty) { classifier.Object.Set("junk", PGeti("use_reject")); classifier.Object.SetExtractor(PGet("extractor")); } ntrained = 0; counts_warned = false; }
public Linerec(string classifier1 = "latin" /*none*/, string extractor1 = "scaledfe", string segmenter1 = "DpSegmenter", int use_reject = 1) { transcript = ""; //line = new Bytearray(); segmentation = new Intarray(); binarized = new Bytearray(); // component choices PDef("classifier", classifier1, "character classifier"); PDef("extractor", extractor1, "feature extractor"); PDef("segmenter", segmenter1, "line segmenter"); PDef("grouper", "SimpleGrouper", "line grouper"); // retraining PDef("cpreload", "none", "classifier to be loaded prior to training"); // debugging PDef("verbose", 0, "verbose output from glinerec"); // outputs PDef("use_priors", 0, "correct the classifier output by priors"); PDef("use_reject", use_reject, "use a reject class (use posteriors only and train on junk chars)"); PDef("maxcost", 20.0, "maximum cost of a character to be added to the output"); PDef("minclass", 32, "minimum output class to be added (default=unicode space)"); PDef("minprob", 1e-9, "minimum probability for a character to appear in the output at all"); PDef("invert", 1, "invert the input line prior to char extraction"); // segmentation PDef("maxrange", 5, "maximum number of components that are grouped together"); // sanity limits on input PDef("minheight", 9, "minimum height of input line"); PDef("maxheight", 300, "maximum height of input line"); PDef("maxaspect", 2.0, "maximum height/width ratio of input line"); // space estimation (FIXME factor this out eventually) PDef("space_fractile", 0.5, "fractile for space estimation"); PDef("space_multiplier", 2.0, "multipler for space estimation"); PDef("space_min", 0.2, "minimum space threshold (in xheight)"); PDef("space_max", 1.1, "maximum space threshold (in xheight)"); PDef("space_yes", 1.0, "cost of inserting a space"); PDef("space_no", 5.0, "cost of not inserting a space"); // back compability PDef("minsize_factor", 0.0, ""); counts = new Intarray(); segmenter = new ComponentContainerISegmentLine(ComponentCreator.MakeComponent <ISegmentLine>(PGet("segmenter"))); grouper = new ComponentContainerIGrouper(ComponentCreator.MakeComponent <IGrouper>(PGet("grouper"))); classifier = new ComponentContainerIModel(IModel.MakeModel(PGet("classifier"))); TryAttachClassifierEvent(classifier.Object); Persist(classifier, "classifier"); Persist(counts, "counts"); Persist(segmenter, "segmenter"); Persist(grouper, "grouper"); if (!classifier.IsEmpty) { classifier.Object.Set("junk", PGeti("use_reject")); classifier.Object.SetExtractor(PGet("extractor")); } ntrained = 0; counts_warned = false; }
public static void binary_and(Bytearray image, Bytearray image2, int dx, int dy) { int w = image.Dim(0); int h = image.Dim(1); for (int i = 0; i < w; i++) for (int j = 0; j < h; j++) image[i, j] = Math.Min(image[i, j], NarrayUtil.Ext(image2, i - dx, j - dy)); }
public static void binary_invert(Bytearray image) { check_binary(image); for (int i = 0; i < image.Length1d(); i++) { image.Put1d(i, (byte)(255 - image.At1d(i))); } }
public virtual void Extract(Bytearray outa, Bytearray ina) { Floatarray fina = new Floatarray(); Floatarray fouta = new Floatarray(); fina.Copy(ina); Extract(fouta, fina); outa.Copy(fouta); }
public static Bitmap read_image_gray(Bytearray image, string path) { Bitmap bitmap = LoadBitmapFromFile(path); image.Resize(bitmap.Width, bitmap.Height); ImgRoutine.NarrayFromBitmap(image, bitmap); return(bitmap); }
public static int binarize_simple(Bytearray result, Bytearray image) { int threshold = (NarrayUtil.Max(image)/* + NarrayUtil.Min(image)*/) / 2; result.MakeLike(image); for (int i = 0; i < image.Length1d(); i++) result.Put1d(i, image.At1d(i) < threshold ? (byte)0 : (byte)255); return threshold; }
public static void binarize_with_threshold(Bytearray result, Floatarray image, float threshold) { result.MakeLike(image); for (int i = 0; i < image.Length1d(); i++) { result.Put1d(i, image.At1d(i) < threshold ? (byte)0 : (byte)255); } }
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; }
public static void binary_close_circle(Bytearray image, int r) { if (r == 0) { return; } binary_dilate_circle(image, r); binary_erode_circle(image, r); }
public static void binary_close_rect(Bytearray image, int rw, int rh) { if (rw == 0 && rh == 0) { return; } binary_dilate_rect(image, rw, rh); binary_erode_rect(image, rw, rh); }
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 Invert(Bytearray a) { int n = a.Length1d(); for (int i = 0; i < n; i++) { a.Put1d(i, (byte)(255 - a.At1d(i))); } }
public static void Thin(ref Bytearray uci) { int w = uci.Dim(0) - 1; int h = uci.Dim(1) - 1; for (int i = 0, n = uci.Length1d(); i < n; i++) { if (uci.At1d(i) > 0) uci.Put1d(i, ON); else uci.Put1d(i, OFF); } bool flag; do { flag = false; for (int j = 0; j < 8; j += 2) { for (int x = 1; x < w; x++) for (int y = 1; y < h; y++) { if (uci[x, y] != ON) continue; if (uci[x + nx[j], y + ny[j]] != OFF) continue; int b = 0; for (int i = 7; i >= 0; i--) { b <<= 1; b |= (uci[x + nx[i], y + ny[i]] != OFF ? 1 : 0); } if (ttable[b] > 0) uci[x, y] = SKEL; else { uci[x, y] = DEL; flag = true; } } if (!flag) continue; for (int x = 1; x < w; x++) for (int y = 1; y < h; y++) if (uci[x, y] == DEL) uci[x, y] = OFF; } } while (flag); for (int i = 0, n = uci.Length1d(); i < n; i++) { if (uci.At1d(i) == SKEL) uci.Put1d(i, 255); else uci.Put1d(i, 0); } }
public static void binary_autoinvert(Bytearray image) { check_binary(image); int count = 0; for (int i = 0; i < image.Length1d(); i++) if (image.At1d(i) > 0) count++; if (count > image.Length1d() / 2) binary_invert(image); }
public override void PutLine(Bytearray image, int page, int line, string variant = null) { MaybeMakeDirectory(page); FileStream fs = Open(FileMode.Create, page, line, variant, "png"); ImgIo.write_image_gray(fs, image, System.Drawing.Imaging.ImageFormat.Png); fs.Flush(); fs.Close(); }
public void SetImage(Bytearray image_) { Bytearray image = new Bytearray(); //image = image_; image.Copy(image_); dimage.Copy(image); if (PGeti("fill_holes") > 0) { Bytearray holes = new Bytearray(); SegmRoutine.extract_holes(ref holes, image); for (int i = 0; i < image.Length(); i++) { if (holes.At1d(i) > 0) { image.Put1d(i, 255); } } } 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, j] > 0) { wimage[i, j] = inside_weight; } else { wimage[i, j] = outside_weight; } } } if (s1 == 0) { where = image.Dim(1) / 2; } else { where = (int)(sy / s1); } for (int i = 0; i < dimage.Dim(0); i++) { dimage[i, where] = 0x008000; } }
public void PutLineBin(Bytearray image, int page, int line, string variant = null) { string v = "bin"; if (!String.IsNullOrEmpty(variant)) { v += "."; v += variant; } PutLine(image, page, line, v); }
public static void optional_check_background_is_darker(Bytearray a) { if (bgcheck) { if (!background_seems_black(a)) { throw new Exception("background must be black"); } } }
public static Bitmap read_image_binary(Bytearray image, string path) { Bitmap bitmap = LoadBitmapFromFile(path); image.Resize(bitmap.Width, bitmap.Height); ImgRoutine.NarrayFromBitmap(image, bitmap); double threshold = (NarrayUtil.Min(image) + NarrayUtil.Max(image)) / 2.0; for (int i = 0; i < image.Length1d(); i++) image.Put1d(i, (byte)((image.At1d(i) < threshold) ? 0 : 255)); return bitmap; }
public static void optional_check_background_is_lighter(Bytearray a) { if (bgcheck) { if (!background_seems_white(a)) { throw new Exception("background must be white"); } } }
public static void binarize_by_range(Bytearray outa, Floatarray ina, float fraction) { float imin = NarrayUtil.Min(ina); float imax = NarrayUtil.Max(ina); float thresh = (int)(imin + (imax - imin) * fraction); outa.MakeLike(ina); for (int i = 0; i < ina.Length1d(); i++) { if (ina.At1d(i) > thresh) outa.Put1d(i, 255); else outa.Put1d(i, 0); } }
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 static void binary_erode_circle(Bytearray image, int r) { if (r == 0) return; Bytearray outa = new Bytearray(); outa.Copy(image); for (int i = -r; i <= r; i++) for (int j = -r; j <= r; j++) { if (i * i + j * j <= r * r) binary_and(outa, image, i, j); } image.Move(outa); }
public static void binary_dilate_rect(Bytearray image, int rw, int rh) { if(rw==0 && rh==0) return; Bytearray outa = new Bytearray(); outa.Copy(image); // note that we handle the even cases complementary // to erode_rect; this makes open_rect and close_rect // do the right thing for(int i=0; i<rw; i++) binary_or(outa, image, i-(rw-1)/2, 0); for(int j=0; j<rh; j++) binary_or(image, outa, 0, j-(rh-1)/2); }
public override void Charseg(ref Intarray result_segmentation, Bytearray orig_image) { Bytearray image = new Bytearray(); image.Copy(orig_image); OcrRoutine.optional_check_background_is_lighter(image); OcrRoutine.binarize_simple(image); OcrRoutine.Invert(image); Intarray ccseg = new Intarray(); ccseg.Copy(image); ImgLabels.label_components(ref ccseg); base.Charseg(ref result_segmentation, orig_image); SegmRoutine.combine_segmentations(ref result_segmentation, ccseg); }
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 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 static int average_on_border(Bytearray a) { int sum = 0; int right = a.Dim(0) - 1; int top = a.Dim(1) - 1; for(int x = 0; x < a.Dim(0); x++) sum += a[x, 0]; for(int x = 0; x < a.Dim(0); x++) sum += a[x, top]; for(int y = 1; y < top; y++) sum += a[0, y]; for(int y = 1; y < top; y++) sum += a[right, y]; // If average border intensity is between 127-128, inverting the // image does not work correctly float average_border_intensity = sum / ((right + top) * 2.0f); if (!(average_border_intensity <= 127 || average_border_intensity >= 128)) Console.WriteLine("average border intensity is between 127-128, inverting the image does not work correctly"); return sum / ((right + top) * 2); }
public override void Charseg(ref Intarray segmentation, Bytearray image) { Bytearray timage = new Bytearray(); timage.Copy(image); //for (int i = 0; i < image.Length(); i++) image[i] = (byte)(image[i] > 0 ? 0 : 1); OcrRoutine.binarize_simple(timage); OcrRoutine.Invert(image); Skeleton.Thin(ref timage); //ImgIo.write_image_gray("_thinned.png", timage); ImgMisc.remove_singular_points(ref timage, 2); //ImgIo.write_image_gray("_segmented.png", timage); Intarray tsegmentation = new Intarray(); tsegmentation.Copy(timage); ImgLabels.label_components(ref tsegmentation); SegmRoutine.remove_small_components(tsegmentation, 4, 4); //ImgIo.write_image_packed("_labeled.png", tsegmentation); segmentation.Copy(image); ImgLabels.propagate_labels_to(ref segmentation, tsegmentation); //ImgIo.write_image_packed("_propagated.png", segmentation); }
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 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 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; }
/// <summary> /// Get the mask around a given rectangle. /// </summary> public abstract void GetMaskAt(ref Bytearray outmask, int index, Rect b);
/// <summary> /// Get the bounding rectangle and mask for group "index". /// Optionally, expand the mask by the given margin. /// </summary> public abstract void GetMask(out Rect r, ref Bytearray outmask, int index, int margin);
public abstract void ExtractWithMask(Floatarray outa, Bytearray mask, Floatarray source, int index, int grow = 0);
public abstract void ExtractSliced(Bytearray outa, Bytearray source, byte dflt, int index, int grow=0);