// partition.c (621, 1) // boxaPruneSortedOnOverlap(boxas, maxoverlap) as Boxa // boxaPruneSortedOnOverlap(BOXA *, l_float32) as BOXA * /// <summary> /// (1) This selectively removes smaller boxes when they are overlapped /// by any larger box by more than the input 'maxoverlap' fraction.<para/> /// /// (2) To avoid all pruning, use maxoverlap = 1.0. To select only /// boxes that have no overlap with each other (maximal pruning), /// set maxoverlap = 0.0.<para/> /// /// (3) If there are no boxes in boxas, returns an empty boxa. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaPruneSortedOnOverlap/*"/> /// <param name="boxas">[in] - sorted by size in decreasing order</param> /// <param name="maxoverlap">[in] - maximum fractional overlap of a box by any of the larger boxes</param> /// <returns>boxad pruned, or NULL on error</returns> public static Boxa boxaPruneSortedOnOverlap( Boxa boxas, Single maxoverlap) { if (boxas == null) { throw new ArgumentNullException("boxas cannot be Nothing"); } IntPtr _Result = Natives.boxaPruneSortedOnOverlap(boxas.Pointer, maxoverlap); if (_Result == IntPtr.Zero) { return(null); } return(new Boxa(_Result)); }
// pageseg.c (1927, 1) // pixFindLargeRectangles(pixs, polarity, nrect, pboxa, ppixdb) as int // pixFindLargeRectangles(PIX *, l_int32, l_int32, BOXA **, PIX **) as l_ok /// <summary> /// (1) This does a greedy search to find the largest rectangles, /// either black or white and without overlaps, in %pix.<para/> /// /// (2) See pixFindLargestRectangle(), which is called multiple /// times, for details. On each call, the largest rectangle /// found is painted, so that none of its pixels can be /// used later, before calling it again.<para/> /// /// (3) This function is surprisingly fast. Although /// pixFindLargestRectangle() runs at about 50 MPix/sec, when it /// is run multiple times by pixFindLargeRectangles(), it processes /// at 150 - 250 MPix/sec, and the time is approximately linear /// in %nrect. For example, for a 1 MPix image, searching for /// the largest 50 boxes takes about 0.2 seconds. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/pixFindLargeRectangles/*"/> /// <param name="pixs">[in] - 1 bpp</param> /// <param name="polarity">[in] - 0 within background, 1 within foreground</param> /// <param name="nrect">[in] - number of rectangles to be found</param> /// <param name="pboxa">[out] - largest rectangles, sorted by decreasing area</param> /// <param name="ppixdb">[in,out] - optional return output with rectangles drawn on it</param> /// <returns>0 if OK, 1 on error</returns> public static int pixFindLargeRectangles( Pix pixs, int polarity, int nrect, out Boxa pboxa, ref Pix ppixdb) { if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } if ((new List <int> { 1 }).Contains((int)pixs.d) == false) { throw new ArgumentException("1 bpp"); } IntPtr pboxaPtr = IntPtr.Zero; IntPtr ppixdbPtr = IntPtr.Zero; if (ppixdb != null) { ppixdbPtr = ppixdb.Pointer; } int _Result = Natives.pixFindLargeRectangles(pixs.Pointer, polarity, nrect, out pboxaPtr, ref ppixdbPtr); if (pboxaPtr == IntPtr.Zero) { pboxa = null; } else { pboxa = new Boxa(pboxaPtr); }; if (ppixdbPtr == IntPtr.Zero) { ppixdb = null; } else { ppixdb = new Pix(ppixdbPtr); }; return(_Result); }
// morphapp.c (195, 1) // pixMorphSequenceByComponent(pixs, sequence, connectivity, minw, minh, pboxa) as Pix // pixMorphSequenceByComponent(PIX *, const char *, l_int32, l_int32, l_int32, BOXA **) as PIX * /// <summary> /// (1) See pixMorphSequence() for composing operation sequences.<para/> /// /// (2) This operates separately on each c.c. in the input pix.<para/> /// /// (3) The dilation does NOT increase the c.c. size it is clipped /// to the size of the original c.c. This is necessary to /// keep the c.c. independent after the operation.<para/> /// /// (4) You can specify that the width and/or height must equal /// or exceed a minimum size for the operation to take place.<para/> /// /// (5) Use NULL for boxa to avoid returning the boxa. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/pixMorphSequenceByComponent/*"/> /// <param name="pixs">[in] - 1 bpp</param> /// <param name="sequence">[in] - string specifying sequence</param> /// <param name="connectivity">[in] - 4 or 8</param> /// <param name="minw">[in] - minimum width to consider use 0 or 1 for any width</param> /// <param name="minh">[in] - minimum height to consider use 0 or 1 for any height</param> /// <param name="pboxa">[out][optional] - return boxa of c.c. in pixs</param> /// <returns>pixd, or NULL on error</returns> public static Pix pixMorphSequenceByComponent( Pix pixs, String sequence, int connectivity, int minw, int minh, out Boxa pboxa) { if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } if (sequence == null) { throw new ArgumentNullException("sequence cannot be Nothing"); } if ((new List <int> { 1 }).Contains((int)pixs.d) == false) { throw new ArgumentException("1 bpp"); } IntPtr pboxaPtr = IntPtr.Zero; IntPtr _Result = Natives.pixMorphSequenceByComponent(pixs.Pointer, sequence, connectivity, minw, minh, out pboxaPtr); if (pboxaPtr == IntPtr.Zero) { pboxa = null; } else { pboxa = new Boxa(pboxaPtr); }; if (_Result == IntPtr.Zero) { return(null); } return(new Pix(_Result)); }
// affinecompose.c (358, 1) // boxaTranslate(boxas, transx, transy) as Boxa // boxaTranslate(BOXA *, l_float32, l_float32) as BOXA * /// <summary> /// boxaTranslate() /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaTranslate/*"/> /// <param name="boxas">[in] - </param> /// <param name="transx">[in] - x component of translation wrt. the origin</param> /// <param name="transy">[in] - y component of translation wrt. the origin</param> /// <returns>boxad translated boxas, or NULL on error Notes: (1) See createMatrix2dTranslate() for details of transform.</returns> public static Boxa boxaTranslate( Boxa boxas, Single transx, Single transy) { if (boxas == null) { throw new ArgumentNullException("boxas cannot be Nothing"); } IntPtr _Result = Natives.boxaTranslate(boxas.Pointer, transx, transy); if (_Result == IntPtr.Zero) { return(null); } return(new Boxa(_Result)); }
// affinecompose.c (391, 1) // boxaScale(boxas, scalex, scaley) as Boxa // boxaScale(BOXA *, l_float32, l_float32) as BOXA * /// <summary> /// boxaScale() /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaScale/*"/> /// <param name="boxas">[in] - </param> /// <param name="scalex">[in] - horizontal scale factor</param> /// <param name="scaley">[in] - vertical scale factor</param> /// <returns>boxad scaled boxas, or NULL on error Notes: (1) See createMatrix2dScale() for details of transform.</returns> public static Boxa boxaScale( Boxa boxas, Single scalex = 1, Single scaley = 1) { if (boxas == null) { throw new ArgumentNullException("boxas cannot be Nothing"); } IntPtr _Result = Natives.boxaScale(boxas.Pointer, scalex, scaley); if (_Result == IntPtr.Zero) { return(null); } return(new Boxa(_Result)); }
// boxfunc2.c (1602, 1) // boxaEncapsulateAligned(boxa, num, copyflag) as Boxaa // boxaEncapsulateAligned(BOXA *, l_int32, l_int32) as BOXAA * /// <summary> /// (1) This puts %num boxes from the input %boxa into each of a /// set of boxa within an output baa.<para/> /// /// (2) This assumes that the boxes in %boxa are in sets of %num each. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaEncapsulateAligned/*"/> /// <param name="boxa">[in] - </param> /// <param name="num">[in] - number put into each boxa in the baa</param> /// <param name="copyflag">[in] - L_COPY or L_CLONE</param> /// <returns>baa, or NULL on error</returns> public static Boxaa boxaEncapsulateAligned( Boxa boxa, int num, int copyflag) { if (boxa == null) { throw new ArgumentNullException("boxa cannot be Nothing"); } IntPtr _Result = Natives.boxaEncapsulateAligned(boxa.Pointer, num, copyflag); if (_Result == IntPtr.Zero) { return(null); } return(new Boxaa(_Result)); }
// boxfunc3.c (1573, 1) // boxaSelectLargeULBox(boxas, areaslop, yslop) as Box // boxaSelectLargeULBox(BOXA *, l_float32, l_int32) as BOX * /// <summary> /// (1) See usage notes in pixSelectLargeULComp(). /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaSelectLargeULBox/*"/> /// <param name="boxas">[in] - 1 bpp</param> /// <param name="areaslop">[in] - fraction near but less than 1.0</param> /// <param name="yslop">[in] - number of pixels in y direction</param> /// <returns>box, or NULL on error</returns> public static Box boxaSelectLargeULBox( Boxa boxas, Single areaslop, int yslop) { if (boxas == null) { throw new ArgumentNullException("boxas cannot be Nothing"); } IntPtr _Result = Natives.boxaSelectLargeULBox(boxas.Pointer, areaslop, yslop); if (_Result == IntPtr.Zero) { return(null); } return(new Box(_Result)); }
// recogident.c (246, 1) // recogSplitIntoCharacters(recog, pixs, minh, skipsplit, pboxa, ppixa, debug) as int // recogSplitIntoCharacters(L_RECOG *, PIX *, l_int32, l_int32, BOXA **, PIXA **, l_int32) as l_ok /// <summary> /// (1) This can be given an image that has an arbitrary number /// of text characters. It optionally splits connected /// components based on document image decoding in recogDecode(). /// The returned pixa includes the boxes from which the /// (possibly split) components are extracted.<para/> /// /// (2) After noise filtering, the resulting components are put in /// row-major (2D) order, and the smaller of overlapping /// components are removed if they satisfy conditions of /// relative size and fractional overlap.<para/> /// /// (3) Note that the splitting function uses unscaled templates /// and does not bother returning the class results and scores. /// These are more accurately found later using the scaled templates. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/recogSplitIntoCharacters/*"/> /// <param name="recog">[in] - </param> /// <param name="pixs">[in] - 1 bpp, contains only mostly deskewed text</param> /// <param name="minh">[in] - remove shorter components use 0 for default</param> /// <param name="skipsplit">[in] - 1 to skip the splitting step</param> /// <param name="pboxa">[out] - character bounding boxes</param> /// <param name="ppixa">[out] - character images</param> /// <param name="debug">[in] - 1 for results written to pixadb_split</param> /// <returns>0 if OK, 1 on error or if no components are returned</returns> public static int recogSplitIntoCharacters( L_Recog recog, Pix pixs, int minh, int skipsplit, out Boxa pboxa, out Pixa ppixa, Enumerations.DebugOnOff debug = DebugOnOff.DebugOn) { if (recog == null) { throw new ArgumentNullException("recog cannot be Nothing"); } if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } IntPtr pboxaPtr = IntPtr.Zero; IntPtr ppixaPtr = IntPtr.Zero; int _Result = Natives.recogSplitIntoCharacters(recog.Pointer, pixs.Pointer, minh, skipsplit, out pboxaPtr, out ppixaPtr, (int)debug); if (pboxaPtr == IntPtr.Zero) { pboxa = null; } else { pboxa = new Boxa(pboxaPtr); }; if (ppixaPtr == IntPtr.Zero) { ppixa = null; } else { ppixa = new Pixa(ppixaPtr); }; return(_Result); }
// affinecompose.c (424, 1) // boxaRotate(boxas, xc, yc, angle) as Boxa // boxaRotate(BOXA *, l_float32, l_float32, l_float32) as BOXA * /// <summary> /// boxaRotate() /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaRotate/*"/> /// <param name="boxas">[in] - </param> /// <param name="xc">[in] - location of center of rotation</param> /// <param name="yc">[in] - location of center of rotation</param> /// <param name="angle">[in] - rotation in radians clockwise is positive</param> /// <returns>boxad scaled boxas, or NULL on error Notes: (1) See createMatrix2dRotate() for details of transform.</returns> public static Boxa boxaRotate( Boxa boxas, Single xc, Single yc, Single angle) { if (boxas == null) { throw new ArgumentNullException("boxas cannot be Nothing"); } IntPtr _Result = Natives.boxaRotate(boxas.Pointer, xc, yc, angle); if (_Result == IntPtr.Zero) { return(null); } return(new Boxa(_Result)); }
// boxfunc2.c (454, 1) // boxaRotateOrth(boxas, w, h, rotation) as Boxa // boxaRotateOrth(BOXA *, l_int32, l_int32, l_int32) as BOXA * /// <summary> /// (1) See boxRotateOrth() for details. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaRotateOrth/*"/> /// <param name="boxas">[in] - </param> /// <param name="w">[in] - of image in which the boxa is embedded</param> /// <param name="h">[in] - of image in which the boxa is embedded</param> /// <param name="rotation">[in] - 0 = noop, 1 = 90 deg, 2 = 180 deg, 3 = 270 deg all rotations are clockwise</param> /// <returns>boxad, or NULL on error</returns> public static Boxa boxaRotateOrth( Boxa boxas, int w, int h, int rotation) { if (boxas == null) { throw new ArgumentNullException("boxas cannot be Nothing"); } IntPtr _Result = Natives.boxaRotateOrth(boxas.Pointer, w, h, rotation); if (_Result == IntPtr.Zero) { return(null); } return(new Boxa(_Result)); }
// jbclass.c (1312, 1) // jbGetComponents(pixs, components, maxwidth, maxheight, pboxad, ppixad) as int // jbGetComponents(PIX *, l_int32, l_int32, l_int32, BOXA **, PIXA **) as l_ok /// <summary> /// jbGetComponents() /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/jbGetComponents/*"/> /// <param name="pixs">[in] - 1 bpp</param> /// <param name="components">[in] - JB_CONN_COMPS, JB_CHARACTERS, JB_WORDS</param> /// <param name="maxwidth">[in] - of saved components larger are discarded</param> /// <param name="maxheight">[in] - of saved components larger are discarded</param> /// <returns>0 if OK, 1 on error</returns> public static int jbGetComponents( Pix pixs, int components, int maxwidth, int maxheight, Boxa pboxad, Pixa ppixad) { if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } if (pboxad == null) { throw new ArgumentNullException("pboxad cannot be Nothing"); } if (ppixad == null) { throw new ArgumentNullException("ppixad cannot be Nothing"); } if ((new List <int> { 1 }).Contains((int)pixs.d) == false) { throw new ArgumentException("1 bpp"); } IntPtr pboxadPtr = IntPtr.Zero; if (pboxad != null) { pboxadPtr = pboxad.Pointer; } IntPtr ppixadPtr = IntPtr.Zero; if (ppixad != null) { ppixadPtr = ppixad.Pointer; } int _Result = Natives.jbGetComponents(pixs.Pointer, components, maxwidth, maxheight, pboxadPtr, ppixadPtr); return(_Result); }
// finditalic.c (110, 1) // pixItalicWords(pixs, boxaw, pixw, pboxa, debugflag) as int // pixItalicWords(PIX *, BOXA *, PIX *, BOXA **, l_int32) as l_ok /// <summary> /// (1) You can input the bounding boxes for the words in one of /// two forms: as bounding boxes (%boxaw) or as a word mask with /// the word bounding boxes filled (%pixw). For example, /// to compute %pixw, you can use pixWordMaskByDilation().<para/> /// /// (2) Alternatively, you can set both of these inputs to NULL, /// in which case the word mask is generated here. This is /// done by dilating and closing the input image to connect /// letters within a word, while leaving the words separated. /// The parameters are chosen under the assumption that the /// input is 10 to 12 pt text, scanned at about 300 ppi.<para/> /// /// (3) sel_ital1 and sel_ital2 detect the right edges that are /// nearly vertical, at approximately the angle of italic /// strokes. We use the right edge to avoid getting seeds /// from lower-case 'y'. The typical italic slant has a smaller /// angle with the vertical than the 'W', so in most cases we /// will not trigger on the slanted lines in the 'W'.<para/> /// /// (4) Note that sel_ital2 is shorter than sel_ital1. It is /// more appropriate for a typical font scanned at 200 ppi. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/pixItalicWords/*"/> /// <param name="pixs">[in] - 1 bpp</param> /// <param name="boxaw">[in][optional] - word bounding boxes can be NULL</param> /// <param name="pixw">[in][optional] - word box mask can be NULL</param> /// <param name="pboxa">[out] - boxa of italic words</param> /// <param name="debugflag">[in] - 1 for debug output 0 otherwise</param> /// <returns>0 if OK, 1 on error</returns> public static int pixItalicWords( Pix pixs, Boxa boxaw, Pix pixw, out Boxa pboxa, int debugflag) { if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } if ((new List <int> { 1 }).Contains((int)pixs.d) == false) { throw new ArgumentException("1 bpp"); } IntPtr boxawPtr = IntPtr.Zero; if (boxaw != null) { boxawPtr = boxaw.Pointer; } IntPtr pixwPtr = IntPtr.Zero; if (pixw != null) { pixwPtr = pixw.Pointer; } IntPtr pboxaPtr = IntPtr.Zero; int _Result = Natives.pixItalicWords(pixs.Pointer, boxawPtr, pixwPtr, out pboxaPtr, debugflag); if (pboxaPtr == IntPtr.Zero) { pboxa = null; } else { pboxa = new Boxa(pboxaPtr); }; return(_Result); }
// dewarp3.c (537, 1) // dewarpaApplyDisparityBoxa(dewa, pageno, pixs, boxas, mapdir, x, y, pboxad, debugfile) as int // dewarpaApplyDisparityBoxa(L_DEWARPA *, l_int32, PIX *, BOXA *, l_int32, l_int32, l_int32, BOXA **, const char *) as l_ok /// <summary> /// (1) This applies the disparity arrays in one of two mapping directions /// to the specified boxa. It can be used in the backward direction /// to locate a box in the original coordinates that would have /// been dewarped to to the specified image.<para/> /// /// (2) If there is no model for %pageno, this will use the model for /// 'refpage' and put the result in the dew for %pageno.<para/> /// /// (3) This works with both stripped and full resolution page models. /// If the full res disparity array(s) are missing, they are remade.<para/> /// /// (4) If an error occurs, a copy of the input boxa is returned. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/dewarpaApplyDisparityBoxa/*"/> /// <param name="dewa">[in] - </param> /// <param name="pageno">[in] - of page model to be used may be a ref model</param> /// <param name="pixs">[in] - initial pix reference for alignment and debugging</param> /// <param name="boxas">[in] - boxa to be mapped</param> /// <param name="mapdir">[in] - 1 if mapping forward from original to dewarped 0 if backward</param> /// <param name="x">[in] - origin for generation of disparity arrays with respect to the source region</param> /// <param name="y">[in] - origin for generation of disparity arrays with respect to the source region</param> /// <param name="pboxad">[out] - disparity corrected boxa</param> /// <param name="debugfile">[in]use NULL to skip - writing this</param> /// <returns>0 if OK, 1 on error no models or ref models available</returns> public static int dewarpaApplyDisparityBoxa( L_Dewarpa dewa, int pageno, Pix pixs, Boxa boxas, int mapdir, int x, int y, out Boxa pboxad, String debugfile = "") { if (dewa == null) { throw new ArgumentNullException("dewa cannot be Nothing"); } if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } if (boxas == null) { throw new ArgumentNullException("boxas cannot be Nothing"); } IntPtr pboxadPtr = IntPtr.Zero; int _Result = Natives.dewarpaApplyDisparityBoxa(dewa.Pointer, pageno, pixs.Pointer, boxas.Pointer, mapdir, x, y, out pboxadPtr, debugfile); if (pboxadPtr == IntPtr.Zero) { pboxad = null; } else { pboxad = new Boxa(pboxadPtr); }; return(_Result); }
// paintcmap.c (219, 1) // pixColorGrayRegionsCmap(pixs, boxa, type, rval, gval, bval) as int // pixColorGrayRegionsCmap(PIX *, BOXA *, l_int32, l_int32, l_int32, l_int32) as l_ok /// <summary> /// (1) This is an in-place operation.<para/> /// /// (2) If type == L_PAINT_LIGHT, it colorizes non-black pixels, /// preserving antialiasing. /// If type == L_PAINT_DARK, it colorizes non-white pixels, /// preserving antialiasing. See pixColorGrayCmap() for details.<para/> /// /// (3) This can also be called through pixColorGrayRegions().<para/> /// /// (4) This increases the colormap size by the number of /// different gray (non-black or non-white) colors in the /// selected regions of pixs. If there is not enough room in /// the colormap for this expansion, it returns 1 (error), /// and the caller should check the return value.<para/> /// /// (5) Because two boxes in the boxa can overlap, pixels that /// are colorized in the first box must be excluded in the /// second because their value exceeds the size of the map. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/pixColorGrayRegionsCmap/*"/> /// <param name="pixs">[in] - 8 bpp, with colormap</param> /// <param name="boxa">[in] - of regions in which to apply color</param> /// <param name="type">[in] - L_PAINT_LIGHT, L_PAINT_DARK</param> /// <param name="rval">[in] - target color</param> /// <param name="gval">[in] - target color</param> /// <param name="bval">[in] - target color</param> /// <returns>0 if OK, 1 on error</returns> public static int pixColorGrayRegionsCmap( Pix pixs, Boxa boxa, int type, int rval, int gval, int bval) { if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } if (boxa == null) { throw new ArgumentNullException("boxa cannot be Nothing"); } int _Result = Natives.pixColorGrayRegionsCmap(pixs.Pointer, boxa.Pointer, type, rval, gval, bval); return(_Result); }
// jbclass.c (1597, 1) // pixWordBoxesByDilation(pixs, minwidth, minheight, maxwidth, maxheight, pboxa, psize, pixadb) as int // pixWordBoxesByDilation(PIX *, l_int32, l_int32, l_int32, l_int32, BOXA **, l_int32 *, PIXA *) as l_ok /// <summary> /// (1) Returns a pruned set of word boxes.<para/> /// /// (2) See pixWordMaskByDilation(). /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/pixWordBoxesByDilation/*"/> /// <param name="pixs">[in] - 1 bpp typ. 75 - 200 ppi</param> /// <param name="minwidth">[in] - saved components smaller are discarded</param> /// <param name="minheight">[in] - saved components smaller are discarded</param> /// <param name="maxwidth">[in] - saved components larger are discarded</param> /// <param name="maxheight">[in] - saved components larger are discarded</param> /// <param name="pboxa">[out] - of dilated word mask</param> /// <param name="psize">[out][optional] - size of good horizontal dilation</param> /// <param name="pixadb">[out][optional] - debug: pixa of intermediate steps</param> /// <returns>0 if OK, 1 on error</returns> public static int pixWordBoxesByDilation( Pix pixs, int minwidth, int minheight, int maxwidth, int maxheight, out Boxa pboxa, out int psize, out Pixa pixadb) { if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } IntPtr pboxaPtr = IntPtr.Zero; IntPtr pixadbPtr = IntPtr.Zero; int _Result = Natives.pixWordBoxesByDilation(pixs.Pointer, minwidth, minheight, maxwidth, maxheight, out pboxaPtr, out psize, out pixadbPtr); if (pboxaPtr == IntPtr.Zero) { pboxa = null; } else { pboxa = new Boxa(pboxaPtr); }; if (pixadbPtr == IntPtr.Zero) { pixadb = null; } else { pixadb = new Pixa(pixadbPtr); }; return(_Result); }
// classapp.c (515, 1) // boxaExtractSortedPattern(boxa, na) as Numaa // boxaExtractSortedPattern(BOXA *, NUMA *) as NUMAA * /// <summary> /// (1) The input is expected to come from pixGetWordBoxesInTextlines().<para/> /// /// (2) Each numa in the output consists of an average y coordinate /// of the first box in the textline, followed by pairs of /// x coordinates representing the left and right edges of each /// of the boxes in the textline. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaExtractSortedPattern/*"/> /// <param name="boxa">[in] - typ. of word bounding boxes, in textline order</param> /// <param name="na">[in] - index of textline for each box in boxa</param> /// <returns>naa NUMAA, where each numa represents one textline, or NULL on error</returns> public static Numaa boxaExtractSortedPattern( Boxa boxa, Numa na) { if (boxa == null) { throw new ArgumentNullException("boxa cannot be Nothing"); } if (na == null) { throw new ArgumentNullException("na cannot be Nothing"); } IntPtr _Result = Natives.boxaExtractSortedPattern(boxa.Pointer, na.Pointer); if (_Result == IntPtr.Zero) { return(null); } return(new Numaa(_Result)); }
// affinecompose.c (493, 1) // boxaAffineTransform(boxas, mat) as Boxa // boxaAffineTransform(BOXA *, l_float32 *) as BOXA * /// <summary> /// boxaAffineTransform() /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaAffineTransform/*"/> /// <param name="boxas">[in] - </param> /// <param name="mat">[in] - 3x3 transform matrix canonical form</param> /// <returns>boxad transformed boxas, or NULL on error</returns> public static Boxa boxaAffineTransform( Boxa boxas, Single[] mat) { if (boxas == null) { throw new ArgumentNullException("boxas cannot be Nothing"); } if (mat == null) { throw new ArgumentNullException("mat cannot be Nothing"); } IntPtr _Result = Natives.boxaAffineTransform(boxas.Pointer, mat); if (_Result == IntPtr.Zero) { return(null); } return(new Boxa(_Result)); }
// boxfunc2.c (1024, 1) // boxaSort2dByIndex(boxas, naa) as Boxaa // boxaSort2dByIndex(BOXA *, NUMAA *) as BOXAA * /// <summary> /// boxaSort2dByIndex() /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaSort2dByIndex/*"/> /// <param name="boxas">[in] - </param> /// <param name="naa">[in] - numaa that maps from the new baa to the input boxa</param> /// <returns>baa sorted boxaa, or NULL on error</returns> public static Boxaa boxaSort2dByIndex( Boxa boxas, Numaa naa) { if (boxas == null) { throw new ArgumentNullException("boxas cannot be Nothing"); } if (naa == null) { throw new ArgumentNullException("naa cannot be Nothing"); } IntPtr _Result = Natives.boxaSort2dByIndex(boxas.Pointer, naa.Pointer); if (_Result == IntPtr.Zero) { return(null); } return(new Boxaa(_Result)); }
// boxfunc3.c (364, 1) // pixPaintBoxaRandom(pixs, boxa) as Pix // pixPaintBoxaRandom(PIX *, BOXA *) as PIX * /// <summary> /// (1) If pixs is 1 bpp, we paint the boxa using a colormap /// otherwise, we convert to 32 bpp.<para/> /// /// (2) We use up to 254 different colors for painting the regions.<para/> /// /// (3) If boxes overlap, the later ones paint over earlier ones. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/pixPaintBoxaRandom/*"/> /// <param name="pixs">[in] - any depth, can be cmapped</param> /// <param name="boxa">[in] - of boxes, to paint</param> /// <returns>pixd with painted boxes, or NULL on error</returns> public static Pix pixPaintBoxaRandom( Pix pixs, Boxa boxa) { if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } if (boxa == null) { throw new ArgumentNullException("boxa cannot be Nothing"); } IntPtr _Result = Natives.pixPaintBoxaRandom(pixs.Pointer, boxa.Pointer); if (_Result == IntPtr.Zero) { return(null); } return(new Pix(_Result)); }
// boxfunc3.c (283, 1) // pixSetBlackOrWhiteBoxa(pixs, boxa, op) as Pix // pixSetBlackOrWhiteBoxa(PIX *, BOXA *, l_int32) as PIX * /// <summary> /// pixSetBlackOrWhiteBoxa() /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/pixSetBlackOrWhiteBoxa/*"/> /// <param name="pixs">[in] - any depth, can be cmapped</param> /// <param name="boxa">[in][optional] - of boxes, to clear or set</param> /// <param name="op">[in] - L_SET_BLACK, L_SET_WHITE</param> /// <returns>pixd with boxes filled with white or black, or NULL on error</returns> public static Pix pixSetBlackOrWhiteBoxa( Pix pixs, Boxa boxa, int op) { if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } IntPtr boxaPtr = IntPtr.Zero; if (boxa != null) { boxaPtr = boxa.Pointer; } IntPtr _Result = Natives.pixSetBlackOrWhiteBoxa(pixs.Pointer, boxaPtr, op); if (_Result == IntPtr.Zero) { return(null); } return(new Pix(_Result)); }
// classapp.c (453, 1) // pixGetWordBoxesInTextlines(pixs, minwidth, minheight, maxwidth, maxheight, pboxad, pnai) as int // pixGetWordBoxesInTextlines(PIX *, l_int32, l_int32, l_int32, l_int32, BOXA **, NUMA **) as l_ok /// <summary> /// (1) The input should be at a resolution of between 75 and 150 ppi.<para/> /// /// (2) This is a special version of pixGetWordsInTextlines(), that /// just finds the word boxes in line order, with a numa /// giving the textline index for each word. /// See pixGetWordsInTextlines() for more details. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/pixGetWordBoxesInTextlines/*"/> /// <param name="pixs">[in] - 1 bpp, typ. 300 ppi</param> /// <param name="minwidth">[in] - of saved components smaller are discarded</param> /// <param name="minheight">[in] - of saved components smaller are discarded</param> /// <param name="maxwidth">[in] - of saved components larger are discarded</param> /// <param name="maxheight">[in] - of saved components larger are discarded</param> /// <param name="pboxad">[out] - word boxes sorted in textline line order</param> /// <param name="pnai">[out][optional] - index of textline for each word</param> /// <returns>0 if OK, 1 on error</returns> public static int pixGetWordBoxesInTextlines( Pix pixs, int minwidth, int minheight, int maxwidth, int maxheight, out Boxa pboxad, out Numa pnai) { if (pixs == null) { throw new ArgumentNullException("pixs cannot be Nothing"); } IntPtr pboxadPtr = IntPtr.Zero; IntPtr pnaiPtr = IntPtr.Zero; int _Result = Natives.pixGetWordBoxesInTextlines(pixs.Pointer, minwidth, minheight, maxwidth, maxheight, out pboxadPtr, out pnaiPtr); if (pboxadPtr == IntPtr.Zero) { pboxad = null; } else { pboxad = new Boxa(pboxadPtr); }; if (pnaiPtr == IntPtr.Zero) { pnai = null; } else { pnai = new Numa(pnaiPtr); }; return(_Result); }
// boxfunc2.c (1170, 1) // boxaExtractAsPta(boxa, pptal, pptat, pptar, pptab, pptaw, pptah, keepinvalid) as int // boxaExtractAsPta(BOXA *, PTA **, PTA **, PTA **, PTA **, PTA **, PTA **, l_int32) as l_ok /// <summary> /// (1) For most applications, such as counting, sorting, fitting /// to some parametrized form, plotting or filtering in general, /// you should remove the invalid boxes. Each pta saves the /// box index in the x array, so replacing invalid boxes by /// filling with boxaFillSequence(), which is required for /// boxaExtractAsNuma(), is not necessary.<para/> /// /// (2) If invalid boxes are retained, each one will result in /// entries (typically 0) in all selected output pta. /// </summary> /// <remarks> /// </remarks> /// <include file="..\CHM_Help\IncludeComments.xml" path="Comments/boxaExtractAsPta/*"/> /// <param name="boxa">[in] - </param> /// <param name="pptal">[out][optional] - array of left locations vs. index</param> /// <param name="pptat">[out][optional] - array of top locations vs. index</param> /// <param name="pptar">[out][optional] - array of right locations vs. index</param> /// <param name="pptab">[out][optional] - array of bottom locations vs. index</param> /// <param name="pptaw">[out][optional] - array of widths vs. index</param> /// <param name="pptah">[out][optional] - array of heights vs. index</param> /// <param name="keepinvalid">[in] - 1 to keep invalid boxes 0 to remove them</param> /// <returns>0 if OK, 1 on error</returns> public static int boxaExtractAsPta( Boxa boxa, out Pta pptal, out Pta pptat, out Pta pptar, out Pta pptab, out Pta pptaw, out Pta pptah, int keepinvalid) { if (boxa == null) { throw new ArgumentNullException("boxa cannot be Nothing"); } IntPtr pptalPtr = IntPtr.Zero; IntPtr pptatPtr = IntPtr.Zero; IntPtr pptarPtr = IntPtr.Zero; IntPtr pptabPtr = IntPtr.Zero; IntPtr pptawPtr = IntPtr.Zero; IntPtr pptahPtr = IntPtr.Zero; int _Result = Natives.boxaExtractAsPta(boxa.Pointer, out pptalPtr, out pptatPtr, out pptarPtr, out pptabPtr, out pptawPtr, out pptahPtr, keepinvalid); if (pptalPtr == IntPtr.Zero) { pptal = null; } else { pptal = new Pta(pptalPtr); }; if (pptatPtr == IntPtr.Zero) { pptat = null; } else { pptat = new Pta(pptatPtr); }; if (pptarPtr == IntPtr.Zero) { pptar = null; } else { pptar = new Pta(pptarPtr); }; if (pptabPtr == IntPtr.Zero) { pptab = null; } else { pptab = new Pta(pptabPtr); }; if (pptawPtr == IntPtr.Zero) { pptaw = null; } else { pptaw = new Pta(pptawPtr); }; if (pptahPtr == IntPtr.Zero) { pptah = null; } else { pptah = new Pta(pptahPtr); }; return(_Result); }
public string Recognize(Texture2D texture) { if (_tessHandle.Equals(IntPtr.Zero)) { return(null); } _highlightedTexture = texture; int width = _highlightedTexture.width; int height = _highlightedTexture.height; Color32[] colors = _highlightedTexture.GetPixels32(); int count = width * height; int bytesPerPixel = 4; byte[] dataBytes = new byte[count * bytesPerPixel]; int bytePtr = 0; for (int y = height - 1; y >= 0; y--) { for (int x = 0; x < width; x++) { int colorIdx = y * width + x; dataBytes[bytePtr++] = colors[colorIdx].r; dataBytes[bytePtr++] = colors[colorIdx].g; dataBytes[bytePtr++] = colors[colorIdx].b; dataBytes[bytePtr++] = colors[colorIdx].a; } } IntPtr imagePtr = Marshal.AllocHGlobal(count * bytesPerPixel); Marshal.Copy(dataBytes, 0, imagePtr, count * bytesPerPixel); TessBaseAPISetImage(_tessHandle, imagePtr, width, height, bytesPerPixel, width * bytesPerPixel); if (TessBaseAPIRecognize(_tessHandle, IntPtr.Zero) != 0) { Marshal.FreeHGlobal(imagePtr); return(null); } IntPtr confidencesPointer = TessBaseAPIAllWordConfidences(_tessHandle); int i = 0; List <int> confidence = new List <int>(); while (true) { int tempConfidence = Marshal.ReadInt32(confidencesPointer, i * 4); if (tempConfidence == -1) { break; } i++; confidence.Add(tempConfidence); } int pointerSize = Marshal.SizeOf(typeof(IntPtr)); IntPtr intPtr = TessBaseAPIGetWords(_tessHandle, IntPtr.Zero); Boxa boxa = Marshal.PtrToStructure <Boxa>(intPtr); Box[] boxes = new Box[boxa.n]; for (int index = 1; index < boxes.Length; index++) { if (confidence[index] >= MinimumConfidence) { IntPtr boxPtr = Marshal.ReadIntPtr(boxa.box, index * pointerSize); boxes[index] = Marshal.PtrToStructure <Box>(boxPtr); Box box = boxes[index]; DrawLines(_highlightedTexture, new Rect(box.x, _highlightedTexture.height - box.y - box.h, box.w, box.h), Color.white); n += 1; text_size += box.h; } } text_size /= n; IntPtr stringPtr = TessBaseAPIGetUTF8Text(_tessHandle); Marshal.FreeHGlobal(imagePtr); if (stringPtr.Equals(IntPtr.Zero)) { return(null); } #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN string recognizedText = Marshal.PtrToStringAnsi(stringPtr); #else string recognizedText = Marshal.PtrToStringAuto(stringPtr); #endif TessBaseAPIClear(_tessHandle); TessDeleteText(stringPtr); string[] words = recognizedText.Split(new[] { ' ', '\n' }, StringSplitOptions.RemoveEmptyEntries); StringBuilder result = new StringBuilder(); rapport1 = Screen.width / x; rapport2 = Screen.height / y; // Pour chaque lettre reconnue, on créé un GameObject de type TextMeshPro dans lequel on écrit la lettre reconnue, puis on la place au bon endroit devant l'image. for (i = 0; i < boxes.Length; i++) { //Debug.Log(words[i] + " -> " + confidence[i]); if (confidence[i] >= MinimumConfidence) { Box box = boxes[i]; float decalage = (float)box.w * rapport1 / (float)words[i].Length; for (int j = 0; j < words[i].Length; j++) { //TextMeshProUGUI te = GameObject.Instantiate(prefab, new Vector3(0, 0, 0), Quaternion.identity); TextMeshProUGUI te = GameObject.Instantiate(prefab, parent.transform); te.transform.SetParent(parent.transform); te.text = words[i][j].ToString(); //te.fontSize = box.h; te.rectTransform.sizeDelta = new Vector2(decalage, (float)box.h * rapport2); float a = te.rectTransform.sizeDelta.x > te.rectTransform.sizeDelta.y ? te.rectTransform.sizeDelta.x : te.rectTransform.sizeDelta.y; te.fontSize = a; //te.rectTransform.position = new Vector3((Screen.width / 2 - parent.rectTransform.sizeDelta.x / 2) + box.x + te.rectTransform.sizeDelta.x / 2 + j * decalage, (Screen.height / 2 - parent.rectTransform.sizeDelta.y / 2) + (parent.rectTransform.sizeDelta.y - box.y) - te.rectTransform.sizeDelta.y / 2, 0); te.rectTransform.anchoredPosition = new Vector3(box.x * rapport1 + te.rectTransform.sizeDelta.x / 2 + j * decalage, (parent.rectTransform.sizeDelta.y - box.y * rapport2) - te.rectTransform.sizeDelta.y / 2, 0); //te.rectTransform.anchoredPosition = new Vector3(0, 0, 0); } result.Append(words[i]); result.Append(" "); } } return(result.ToString()); }
public string Recognize(Texture2D texture) { if (_tessHandle.Equals(IntPtr.Zero)) { return(null); } _highlightedTexture = texture; int width = _highlightedTexture.width; int height = _highlightedTexture.height; Color32[] colors = _highlightedTexture.GetPixels32(); int count = width * height; int bytesPerPixel = 4; byte[] dataBytes = new byte[count * bytesPerPixel]; int bytePtr = 0; for (int y = height - 1; y >= 0; y--) { for (int x = 0; x < width; x++) { int colorIdx = y * width + x; dataBytes[bytePtr++] = colors[colorIdx].r; dataBytes[bytePtr++] = colors[colorIdx].g; dataBytes[bytePtr++] = colors[colorIdx].b; dataBytes[bytePtr++] = colors[colorIdx].a; } } IntPtr imagePtr = Marshal.AllocHGlobal(count * bytesPerPixel); Marshal.Copy(dataBytes, 0, imagePtr, count * bytesPerPixel); TessBaseAPISetImage(_tessHandle, imagePtr, width, height, bytesPerPixel, width * bytesPerPixel); if (TessBaseAPIRecognize(_tessHandle, IntPtr.Zero) != 0) { Marshal.FreeHGlobal(imagePtr); return(null); } IntPtr confidencesPointer = TessBaseAPIAllWordConfidences(_tessHandle); int i = 0; List <int> confidence = new List <int>(); while (true) { int tempConfidence = Marshal.ReadInt32(confidencesPointer, i * 4); if (tempConfidence == -1) { break; } i++; confidence.Add(tempConfidence); } int pointerSize = Marshal.SizeOf(typeof(IntPtr)); IntPtr intPtr = TessBaseAPIGetWords(_tessHandle, IntPtr.Zero); Boxa boxa = Marshal.PtrToStructure <Boxa>(intPtr); Box[] boxes = new Box[boxa.n]; for (int index = 0; index < boxes.Length; index++) { if (confidence[index] >= MinimumConfidence) { IntPtr boxPtr = Marshal.ReadIntPtr(boxa.box, index * pointerSize); boxes[index] = Marshal.PtrToStructure <Box>(boxPtr); Box box = boxes[index]; DrawLines(_highlightedTexture, new Rect(box.x, _highlightedTexture.height - box.y - box.h, box.w, box.h), Color.green); } } IntPtr stringPtr = TessBaseAPIGetUTF8Text(_tessHandle); Marshal.FreeHGlobal(imagePtr); if (stringPtr.Equals(IntPtr.Zero)) { return(null); } #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN string recognizedText = Marshal.PtrToStringAnsi(str_ptr); #else string recognizedText = Marshal.PtrToStringAuto(stringPtr); #endif TessBaseAPIClear(_tessHandle); TessDeleteText(stringPtr); string[] words = recognizedText.Split(new[] { ' ', '\n' }, StringSplitOptions.RemoveEmptyEntries); StringBuilder result = new StringBuilder(); for (i = 0; i < boxes.Length; i++) { Debug.Log(words[i] + " -> " + confidence[i]); if (confidence[i] >= MinimumConfidence) { result.Append(words[i]); result.Append(" "); } } return(result.ToString()); }
// Recognize the text by feeding it a Texture2D , return a string public List <WordList> Recognize(Texture2D texture) { // Guard in case Tesseract isn't initialized if (_tessHandle.Equals(IntPtr.Zero)) { return(null); } // Set a property to store the texture _highlightedTexture = texture; // Determine the bytes data // First get the texture's dimensions int width = _highlightedTexture.width; int height = _highlightedTexture.height; //Get the color scape // The image texture must have read/write enabled otherwise this function will fail Color32[] colors = _highlightedTexture.GetPixels32(); // Count the total pixels int count = width * height; //Determine the number of bytes by multiplying the total pixels by the bytes per pixel // Four bytes as we're using RGBA (one byte for each element in the byte array int bytesPerPixel = 4; byte[] dataBytes = new byte[count * bytesPerPixel]; // Byte Pointer int bytePtr = 0; // Set up the Byte Stream/Array from the PixelArray // For each pixel of Y (height) while it's greater than 0 for (int y = height - 1; y >= 0; y--) { // At each Y value, For each pixel of x (width) while X is smaller than the total width // Scanning top down like a security guard using a metal detector for (int x = 0; x < width; x++) { // ColorIndex equals current height times total width plus the current width int colorIdx = y * width + x; // Comprehension of where the data is being placed: // dataBytes[0] = First Pixel (Top left), Red Channel // dataBytes[1] = First Pixel (Top left), Green Channel // dataBytes[2] = Second Pixel (Top Left, one pixel right), Red Channel dataBytes[bytePtr++] = colors[colorIdx].r; dataBytes[bytePtr++] = colors[colorIdx].g; dataBytes[bytePtr++] = colors[colorIdx].b; dataBytes[bytePtr++] = colors[colorIdx].a; } } // Method Research: // IntPtr is pointer for an integer who's size is platform-specific (32 or 64 bit) // The Marshal class provides a collection of methods for allocating and manipulating unmanaged memory // AllocHGlobal allocates memory from the unmanaged memory of the process, equal to the size of the image by the number of bytes per pixel IntPtr imagePtr = Marshal.AllocHGlobal(count * bytesPerPixel); //Copies data from the datastream we set up earlier to our new unmanaged memory pointer // We're using overload 16: Copy(Byte[], Int32, IntPtr, Int32): Copies data from a one-dimensional, managed 8-bit unsigned integer array to an unmanaged memory pointer. Marshal.Copy(dataBytes, 0, imagePtr, count * bytesPerPixel); // Passing a pointer to the memory of the byte array as a parameter of SetImage TessBaseAPISetImage(_tessHandle, imagePtr, width, height, bytesPerPixel, width * bytesPerPixel); // See if Tesseract has recognized the image if (TessBaseAPIRecognize(_tessHandle, IntPtr.Zero) != 0) { // If Tesseract has recognized the image, free the memory used for the image data Marshal.FreeHGlobal(imagePtr); return(null); } // Determine the confidence level for each word IntPtr confidencesPointer = TessBaseAPIAllWordConfidences(_tessHandle); int i = 0; // Create a list of the confidence at each byte // Note the AllWordConfidences returns a pointer to the 1st element of an Integer32 array ending with -1, // so you need to loop through until you get -1 confidence = new List <int>(); while (true) { int tempConfidence = Marshal.ReadInt32(confidencesPointer, i * 4); if (tempConfidence == -1) { break; } i++; confidence.Add(tempConfidence); } // -------- Determine Boxes for Highlights // Get the byte size of the pointer int pointerSize = Marshal.SizeOf(typeof(IntPtr)); // Get the words from Tesseract IntPtr intPtr = TessBaseAPIGetWords(_tessHandle, IntPtr.Zero); // Put the pointer data into the Boxa structure Boxa boxa = Marshal.PtrToStructure <Boxa>(intPtr); // Determine the boxes boxes = new Box[boxa.n]; // For Each of the boxes, set it to the read value of the box at the given offset and make it a box structure for (int index = 0; index < boxes.Length; index++) { // If the confidence of the word meets the minimum index if (confidence[index] >= MinimumConfidence) { IntPtr boxPtr = Marshal.ReadIntPtr(boxa.box, index * pointerSize); boxes[index] = Marshal.PtrToStructure <Box>(boxPtr); Box box = boxes[index]; // draw lines around the box / word DrawLines(texture, new Rect(box.x, texture.height - box.y - box.h, box.w, box.h), Color.magenta); } } // --------- End Highlight Section // Create a new pointer for the string data and assign it to the result of the method to return UTF8 data. IntPtr str_ptr = TessBaseAPIGetUTF8Text(_tessHandle); // Free the memory used for the image data Marshal.FreeHGlobal(imagePtr); // If the string returns null/empty, return null if (str_ptr.Equals(IntPtr.Zero)) { return(null); } //IF we're in windows, convert to an ansi string #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN string recognizedText = Marshal.PtrToStringAnsi(str_ptr); // Else, convert auto #else string recognizedText = Marshal.PtrToStringAuto(str_ptr); #endif // Clear Tesseract TessBaseAPIClear(_tessHandle); // Clear the text from Tesseract TessDeleteText(str_ptr); // Filter out the words from the text that are too low in confidence words = recognizedText.Split(new[] { ' ', '\n' }, StringSplitOptions.RemoveEmptyEntries); StringBuilder result = new StringBuilder(); for (i = 0; i < boxes.Length; i++) { // public int Width, Height, X, Y, confidence; // public string Word; if (confidence[i] >= MinimumConfidence) { Box box = boxes[i]; Rect location = new Rect(box.x, texture.height - box.y - box.h, box.w, box.h); var temp = new WordList(); temp.box = location; temp.word = words[i]; temp.confidence = confidence[i]; recognizedWords.Add(temp); result.Append(words[i]); result.Append(" "); } } // Return the filtered words return(recognizedWords); }
public string Recognize(Texture2D texture) { if (_tessHandle.Equals(IntPtr.Zero)) { return(null); } _highlightedTexture = texture; int width = _highlightedTexture.width; int height = _highlightedTexture.height; Color32[] colors = texture.GetPixels32(); int count = width * height; int bytesPerPixel = 4; byte[] dataBytes = new byte[count * bytesPerPixel]; int bytePtr = 0; for (int y = height - 1; y >= 0; y--) { for (int x = 0; x < width; x++) { int colorIdx = y * width + x; dataBytes[bytePtr++] = colors[colorIdx].r; dataBytes[bytePtr++] = colors[colorIdx].g; dataBytes[bytePtr++] = colors[colorIdx].b; dataBytes[bytePtr++] = colors[colorIdx].a; } } IntPtr imagePtr = Marshal.AllocHGlobal(count * bytesPerPixel); Marshal.Copy(dataBytes, 0, imagePtr, count * bytesPerPixel); TessBaseAPISetImage(_tessHandle, imagePtr, width, height, bytesPerPixel, width * bytesPerPixel); if (TessBaseAPIRecognize(_tessHandle, IntPtr.Zero) != 0) { Marshal.FreeHGlobal(imagePtr); return(null); } int pointerSize = Marshal.SizeOf(typeof(IntPtr)); IntPtr intPtr = TessBaseAPIGetWords(_tessHandle, IntPtr.Zero); Boxa boxa = Marshal.PtrToStructure <Boxa>(intPtr); Box[] boxes = new Box[boxa.n]; for (int index = 0; index < boxes.Length; index++) { IntPtr boxPtr = Marshal.ReadIntPtr(boxa.box, index * pointerSize); boxes[index] = Marshal.PtrToStructure <Box>(boxPtr); Box box = boxes[index]; DrawLines(texture, new Rect(box.x, texture.height - box.y - box.h, box.w, box.h), Color.green); } IntPtr str_ptr = TessBaseAPIGetUTF8Text(_tessHandle); Marshal.FreeHGlobal(imagePtr); if (str_ptr.Equals(IntPtr.Zero)) { return(null); } #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN string recognizedText = Marshal.PtrToStringAnsi(str_ptr); #else string recognizedText = Marshal.PtrToStringAuto(str_ptr); #endif TessBaseAPIClear(_tessHandle); TessDeleteText(str_ptr); return(recognizedText); }
public void Display(Boxa boxa) { var n = new ShowPix(_All.pixDrawBoxa(this, boxa, 1, Convert.RGBAUInt(Color.Red))); }