once again I'm having some difficulties while trying to use tessdll
from C#.
I dont know if im doing the marshaling correctly. Let me present the
code for my wrapper before I start explaining my problem:
<CODE>
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using System.IO;
[StructLayout(LayoutKind.Sequential)]
public struct ETEXT_DESC /*output header */
{
Int16 count; /*chars in this buffer(0) */
Int16 progress; /*percent complete increasing (0-100)
*/
sbyte more_to_come; /*true if not last */
sbyte ocr_alive; /*ocr sets to 1, HP 0 */
sbyte err_code; /*for errcode use */
unsafe void* cancel; /*returns true to cancel */
unsafe void* cancel_this; /*this or other data for
cancel*/
Int32 end_time; /*time to stop if not 0*/
EANYCODE_CHAR text; /*character data */
}
namespace testingWrapper
{
class WrapperTesseract
{
[DllImport("tessdll.dll")]
private unsafe static extern int
TessDllBeginPageUpright(UInt32 xsize, UInt32 ysize, byte* buf, string
lang);
private static byte[]
ConvertImageToByteArray(System.Drawing.Image imageToConvert,
ImageFormat formatOfImage)
{
byte[] Ret;
using (MemoryStream ms = new MemoryStream())
{
imageToConvert.Save(ms, formatOfImage);
Ret = ms.ToArray();
}
return Ret;
}
public static void recognizeChars(System.Drawing.Bitmap bmp,
string language)
{
//This is a test image to see if i have some output as the
dlltest
bmp = new Bitmap("test5.tif");
//Convertion from image to a byte array
byte[] byteBmp = ConvertImageToByteArray(bmp,
bmp.RawFormat);
unsafe
{
//Convertion from a byte array to a pointer
fixed (byte* imgPtr = &byteBmp[0])
{
BitmapData bmd1 = bmp.LockBits(new Rectangle(0, 0,
bmp.Size.Width, bmp.Size.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
ETEXT_DESC d = new ETEXT_DESC();
d = (ETEXT_DESC)(Marshal.PtrToStructure(data,
typeof(ETEXT_DESC)));
data = IntPtr.Zero;
}
}
}
}
}
</CODE>
Alright so what i've done is to redefine the ETEXT_DESC as a managed
struct (and i've also specify [StructLayout(LayoutKind.Sequential)] to
order the struct as i defined it) but the difference is that it
contains a EANYCODE_CHAR text an not an array (i can't seem to find
how to do it without having a AccessViolation crash).
And i had to find a way to convert a C# image into a "unsigned char*",
so i thought that a byte* would be my best candidate. But i'm not sure
if i've done it correctly.
Right now the results between dlltess and my wrapper for the same tiff
is different and the text variable never seem correct.
Anyone could tell me what i'm doing wrong?
If i manage to write the code for this wrapper, ill post the solution
and the .dll on the group.
> once again I'm having some difficulties while trying to use tessdll
> from C#.
> I dont know if im doing the marshaling correctly. Let me present the
> code for my wrapper before I start explaining my problem:
> <CODE>
> using System;
> using System.Collections.Generic;
> using System.Text;
> using System.Drawing;
> using System.Runtime.InteropServices;
> using System.Drawing.Imaging;
> using System.IO;
> [StructLayout(LayoutKind.Sequential)]
> public struct ETEXT_DESC /*output header */
> {
> Int16 count; /*chars in this buffer(0) */
> Int16 progress; /*percent complete increasing (0-100)
> */
> sbyte more_to_come; /*true if not last */
> sbyte ocr_alive; /*ocr sets to 1, HP 0 */
> sbyte err_code; /*for errcode use */
> unsafe void* cancel; /*returns true to cancel */
> unsafe void* cancel_this; /*this or other data for
> cancel*/
> Int32 end_time; /*time to stop if not 0*/
> EANYCODE_CHAR text; /*character data */
> private static byte[]
> ConvertImageToByteArray(System.Drawing.Image imageToConvert,
> ImageFormat formatOfImage)
> {
> byte[] Ret;
> using (MemoryStream ms = new MemoryStream())
> {
> imageToConvert.Save(ms, formatOfImage);
> Ret = ms.ToArray();
> }
> return Ret;
> }
> public static void recognizeChars(System.Drawing.Bitmap bmp,
> string language)
> {
> //This is a test image to see if i have some output as the
> dlltest
> bmp = new Bitmap("test5.tif");
> //Convertion from image to a byte array
> byte[] byteBmp = ConvertImageToByteArray(bmp,
> bmp.RawFormat);
> unsafe
> {
> //Convertion from a byte array to a pointer
> fixed (byte* imgPtr = &byteBmp[0])
> {
> BitmapData bmd1 = bmp.LockBits(new Rectangle(0, 0,
> bmp.Size.Width, bmp.Size.Height),
> System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
> ETEXT_DESC d = new ETEXT_DESC();
> d = (ETEXT_DESC)(Marshal.PtrToStructure(data,
> typeof(ETEXT_DESC)));
> data = IntPtr.Zero;
> }
> }
> }
> }
> }
> </CODE>
> Alright so what i've done is to redefine the ETEXT_DESC as a managed
> struct (and i've also specify [StructLayout(LayoutKind.Sequential)] to
> order the struct as i defined it) but the difference is that it
> contains a EANYCODE_CHAR text an not an array (i can't seem to find
> how to do it without having a AccessViolation crash).
> And i had to find a way to convert a C# image into a "unsigned char*",
> so i thought that a byte* would be my best candidate. But i'm not sure
> if i've done it correctly.
> Right now the results between dlltess and my wrapper for the same tiff
> is different and the text variable never seem correct.
> Anyone could tell me what i'm doing wrong?
> If i manage to write the code for this wrapper, ill post the solution
> and the .dll on the group.
OK I was able to fix 1 bug, my old struct had 1 byte missing before
the cancel attribute (probably because of the typedef signature)
so my new structure is:
public struct ETEXT_DESC /*output header */
{
public Int16 count; /*chars in this buffer(0) */
public Int16 progress; /*percent complete increasing
(0-100) */
public SByte more_to_come; /*true if not last */
public SByte ocr_alive; /*ocr sets to 1, HP 0 */
public SByte err_code; /*for errcode use */
public SByte cancelSignature; /*for errcode use */
public unsafe void* cancel; /*returns true to cancel */
public unsafe void* cancel_this; /*this or other data
for cancel*/
public Int32 end_time; /*time to stop if not 0*/
unsafe public EANYCODE_CHAR text ; /*character data */
}
So i've add "public SByte cancelSignature; /*for
errcode use */"
But now im pretty sure i'm having problem with my image conversion.
The value of the arrays for the image from dlltest and my wrapper is
different.
I'm guessing that maybe .Net doesnt remove the header of my image
which is done in tesseract?! Anytips on how to remove this header?(if
this is my problem)
Another thing, I dont seem to be able to create an array for the text
variable in my structure. Is it because managed array aren't the same
size in unmanged code?
On Wed, Mar 5, 2008 at 3:26 AM, EricD <eri...@videotron.ca> wrote:
> Alright, I think my wrapper is working now. I need to clean the code > up and make some tests to make sure its ok.
> If anyone is really in need of the code contact me and ill give you > the correct code.
Could you please post here your wrapper, or at least the correct p/invokes signatures and structures. I think it will be very useful for persons (including me) wanting to integrate tesseract with the .Net framework. After the hard work you have done, it would be sad if everyone else had to reinvent the wheel.
> On Wed, Mar 5, 2008 at 3:26 AM, EricD <eri...@videotron.ca> wrote:
> > Alright, I think my wrapper is working now. I need to clean the code
> > up and make some tests to make sure its ok.
> > If anyone is really in need of the code contact me and ill give you
> > the correct code.
> Could you please post here your wrapper, or at least the correct p/invokes
> signatures and structures. I think it will be very useful for persons
> (including me) wanting to integrate tesseract with the .Net framework. After
> the hard work you have done, it would be sad if everyone else had to
> reinvent the wheel.
> Eric, way to go! Please share your hard earned knowledge :)
> Did you end up using an intptr for the char array? I was going down
> this path and having some grief....
> Please post your changes and we'll gladly help you test.
> On Mar 5, 2:28 am, "Julien Benoit" <julien.ben...@gmail.com> wrote:
> > On Wed, Mar 5, 2008 at 3:26 AM, EricD <eri...@videotron.ca> wrote:
> > > Alright, I think my wrapper is working now. I need to clean the code
> > > up and make some tests to make sure its ok.
> > > If anyone is really in need of the code contact me and ill give you
> > > the correct code.
> > Could you please post here your wrapper, or at least the correct p/invokes
> > signatures and structures. I think it will be very useful for persons
> > (including me) wanting to integrate tesseract with the .Net framework. After
> > the hard work you have done, it would be sad if everyone else had to
> > reinvent the wheel.
Ok before i start, i want to tell everyone that this code work to
invoke only 3 fonctions of tesseract
(TessDllBeginPageUpright,TessDllBeginPage and
TessDllRecognize_all_Words) but it can be easily expanded if you
follow the logic.
Plus this code is only a startup, this is why i wont post the .cs to
the group right now since its not finished (I'm posting it only to
help those who need a wrapper fast)
Another thing i realized is that SOME images will have different (and
ugly) results than if you used tesseract.exe or the .dll. This is
probably cause because tesseract.exe and the .dll must do some image
preprocessing before it is analysed (am i right?)
So the next version of the code will fix this problem
BUGS: Here's a list of bugs that i found when using the wrapper
1-Changing language between some extraction make the application
crash.
2-Results vary from the wrapper and the dlltest for SOME image
(Preprocessing missing?)
...more to come
And remember this is only a prototype of the wrapper and it may
contains some bug so do not use it without testing it to make sure it
does what you want.
<CODE SNIPPET>
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using System.IO;
/
**********************************************************************
* CharDescription
* Description of a single character. The character code is defined by
* the character set of the current font.
* Output text is sent as an array of these structures.
* Spaces and line endings in the output are represented in the
* structures of the surrounding characters. They are not directly
* represented as characters.
* The first character in a word has a positive value of blanks.
* Missing information should be set to the defaults in the comments.
* If word bounds are known, but not character bounds, then the top
and
* bottom of each character should be those of the word. The left of
the
* first and right of the last char in each word should be set. All
other
* lefts and rights should be set to -1.
* If set, the values of right and bottom are left+width and top
+height.
* Most of the members come directly from the parameters to
ocr_append_char.
* The formatting member uses the enhancement parameter and combines
the
* line direction stuff into the top 3 bits.
* The coding is 0=RL char, 1=LR char, 2=DR NL, 3=UL NL, 4=DR Para,
* 5=UL Para, 6=TB char, 7=BT char. API users do not need to know what
* the coding is, only that it is backwards compatible with the
previous
* version.
**********************************************************************/
[StructLayout(LayoutKind.Sequential)]
public struct CharDescription /*single character */
{
public UInt16 char_code; /*character itself */
public Int16 left; /*of char (-1) */
public Int16 right; /*of char (-1) */
public Int16 top; /*of char (-1) */
public Int16 bottom; /*of char (-1) */
public Int16 font_index; /*what font (0) */
public Byte confidence; /*0=perfect, 100=reject
(0/100) */
public Byte point_size; /*of char, 72=i inch, (10) */
public SByte blanks; /*no of spaces before this
char (1) */
public Byte formatting; /*char formatting (0) */
} /*single character */
[StructLayout(LayoutKind.Sequential)]
public struct GeneralInfos /*output header */
{
public Int16 count; /*chars in this buffer(0) */
public Int16 progress; /*percent complete
increasing (0-100) */
public SByte more_to_come; /*true if not last */
public SByte ocr_alive; /*ocr sets to 1, HP 0 */
public SByte err_code; /*for errcode use */
public Byte cancelSignature;
public unsafe void* cancel; /*returns true to cancel */
public unsafe void* cancel_this; /*this or other data
for cancel*/
public Int32 end_time; /*time to stop if not 0*/
}
/// <summary>
/// Used for returning a managed structure contains OCR extraction
results
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public class AnalysisResults
{
public GeneralInfos generalInfos=new GeneralInfos();
public List<CharDescription> charactersFound = new
List<CharDescription>();
public string stringFound = "";
}
namespace tesseractOCR
{
/// <summary>
/// A wrapper that expose some fonctionnalies of TesseractOCR
/// </summary>
class WrapperTesseract
{
/// <summary>
/// Take an image and extract any text found using the
specified language with TesseractOCR.
/// </summary>
/// <param name="bmp">The image to analyse.</param>
/// <param name="language">The language to be used to extract
text.</param>
/// <param name="bpp">The number of bits per pixel(bpp) of the
image.</param>
/// <returns>A AnalysisResults structure that contains the
results of the Tesseract
/// extraction.</returns>
public static AnalysisResults
recognizeChars(System.Drawing.Bitmap bmp, string language, Byte bpp)
{
//TODO: IMAGE RESIZING TO INCREASE TESSERACT ACCURACY
//Create a BitmapData and Lock all pixels to be read
BitmapData bmpData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.ReadOnly, bmp.PixelFormat);
/// <summary>
/// Build and return a AnalysisResults object that contains
the results of the Tesseract
/// extraction.
/// </summary>
/// <param name="data">A pointer to the data to be
transformed.</param>
/// <returns>A AnalysisResults structure that contains the
results of the Tesseract
/// extraction.</returns>
private static AnalysisResults BuildAnalysisResults(IntPtr
data)
{
AnalysisResults analysisResults = new AnalysisResults();
//Retreives the structure starting at the address of the
pointer
analysisResults.generalInfos = (GeneralInfos)
(Marshal.PtrToStructure(data, typeof(GeneralInfos)));
//Move to the text data (next data is actually at + 20 not
4, but 4 will be
//add up with 16 in the for loop (and make 20)
data = new IntPtr(data.ToInt32() + 4);
for (int i = 0; i < analysisResults.generalInfos.count; i+
+)
{
//Move to the next character
data = new IntPtr(data.ToInt32() + 16);
//TODO: ADD CHARACTER ANALYSIS TO FORMAT THE STRING OR/
AND TO REMOVE UNWANTED CHARACTERS
//Lets add all the white space detected
for(int j = 0; j<charInfos.blanks;j++)
analysisResults.stringFound += " ";
//Now lets add the char found
analysisResults.stringFound +=
(char)charInfos.char_code;
}
//Unaffect the pointer
data = IntPtr.Zero;
return analysisResults;
}
}
}
</CODE SNIPPET>
Knowing the offset of each value returned by my structure and because
of the complexity of it, i decided that it would be better to build
the structure myselft. But if the structure was without any array that
can grows i would suggest to use the marshal.PtrToStructure fonction.
Plus the first methods required a pointer to the first pixel of an
image. In my first code i was using the .save method, but it save the
content of the header as well, so what i neeeded to do is to use
the .Scan0 which return this pointer.
Oh and it seems that the typedef required an additionnal byte for
storing the def signature, so this is why i have a byte
cancelSignature in my structure.
REMARK: This code is only a beginning
I hope this code can help someone with interop because its not an easy
subject and it can get confusing sometimes...
OK congrats on the progress so far! I can run all the way through now
without any memory errors :)
Now I just need to get my image to a point where it can be processed
correctly. I've tried reading a bitmap from a file and passing that,
but I never get the results expected. Usually I just get a single
tilde '~' back from the call.
Ultimately I want to be able to capture part of the screen and process
that. Any ideas on how to get this to work reliably? Any idea on
exactly what format the bitmap needs to be in to get tesseract to like
it?
Thanks!
On Mar 5, 11:50 am, EricD <eri...@videotron.ca> wrote:
> Ok before i start, i want to tell everyone that this code work to
> invoke only 3 fonctions of tesseract
> (TessDllBeginPageUpright,TessDllBeginPage and
> TessDllRecognize_all_Words) but it can be easily expanded if you
> follow the logic.
> Plus this code is only a startup, this is why i wont post the .cs to
> the group right now since its not finished (I'm posting it only to
> help those who need a wrapper fast)
> Another thing i realized is that SOME images will have different (and
> ugly) results than if you used tesseract.exe or the .dll. This is
> probably cause because tesseract.exe and the .dll must do some image
> preprocessing before it is analysed (am i right?)
> So the next version of the code will fix this problem
> BUGS: Here's a list of bugs that i found when using the wrapper
> 1-Changing language between some extraction make the application
> crash.
> 2-Results vary from the wrapper and the dlltest for SOME image
> (Preprocessing missing?)
> ...more to come
> And remember this is only a prototype of the wrapper and it may
> contains some bug so do not use it without testing it to make sure it
> does what you want.
> <CODE SNIPPET>
> using System;
> using System.Collections.Generic;
> using System.Text;
> using System.Drawing;
> using System.Runtime.InteropServices;
> using System.Drawing.Imaging;
> using System.IO;
> /
> **********************************************************************
> * CharDescription
> * Description of a single character. The character code is defined by
> * the character set of the current font.
> * Output text is sent as an array of these structures.
> * Spaces and line endings in the output are represented in the
> * structures of the surrounding characters. They are not directly
> * represented as characters.
> * The first character in a word has a positive value of blanks.
> * Missing information should be set to the defaults in the comments.
> * If word bounds are known, but not character bounds, then the top
> and
> * bottom of each character should be those of the word. The left of
> the
> * first and right of the last char in each word should be set. All
> other
> * lefts and rights should be set to -1.
> * If set, the values of right and bottom are left+width and top
> +height.
> * Most of the members come directly from the parameters to
> ocr_append_char.
> * The formatting member uses the enhancement parameter and combines
> the
> * line direction stuff into the top 3 bits.
> * The coding is 0=RL char, 1=LR char, 2=DR NL, 3=UL NL, 4=DR Para,
> * 5=UL Para, 6=TB char, 7=BT char. API users do not need to know what
> * the coding is, only that it is backwards compatible with the
> previous
> * version.
> **********************************************************************/
> [StructLayout(LayoutKind.Sequential)]
> public struct CharDescription /*single character */
> {
> public UInt16 char_code; /*character itself */
> public Int16 left; /*of char (-1) */
> public Int16 right; /*of char (-1) */
> public Int16 top; /*of char (-1) */
> public Int16 bottom; /*of char (-1) */
> public Int16 font_index; /*what font (0) */
> public Byte confidence; /*0=perfect, 100=reject
> (0/100) */
> public Byte point_size; /*of char, 72=i inch, (10) */
> public SByte blanks; /*no of spaces before this
> char (1) */
> public Byte formatting; /*char formatting (0) */
> } /*single character */
> [StructLayout(LayoutKind.Sequential)]
> public struct GeneralInfos /*output header */
> {
> public Int16 count; /*chars in this buffer(0) */
> public Int16 progress; /*percent complete
> increasing (0-100) */
> public SByte more_to_come; /*true if not last */
> public SByte ocr_alive; /*ocr sets to 1, HP 0 */
> public SByte err_code; /*for errcode use */
> public Byte cancelSignature;
> public unsafe void* cancel; /*returns true to cancel */
> public unsafe void* cancel_this; /*this or other data
> for cancel*/
> public Int32 end_time; /*time to stop if not 0*/
> }
> /// <summary>
> /// Used for returning a managed structure contains OCR extraction
> results
> /// </summary>
> [StructLayout(LayoutKind.Sequential)]
> public class AnalysisResults
> {
> public GeneralInfos generalInfos=new GeneralInfos();
> public List<CharDescription> charactersFound = new
> List<CharDescription>();
> public string stringFound = "";
> }
> namespace tesseractOCR
> {
> /// <summary>
> /// A wrapper that expose some fonctionnalies of TesseractOCR
> /// </summary>
> class WrapperTesseract
> {
> /// <summary>
> /// Take an image and extract any text found using the
> specified language with TesseractOCR.
> /// </summary>
> /// <param name="bmp">The image to analyse.</param>
> /// <param name="language">The language to be used to extract
> text.</param>
> /// <param name="bpp">The number of bits per pixel(bpp) of the
> image.</param>
> /// <returns>A AnalysisResults structure that contains the
> results of the Tesseract
> /// extraction.</returns>
> public static AnalysisResults
> recognizeChars(System.Drawing.Bitmap bmp, string language, Byte bpp)
> {
> //TODO: IMAGE RESIZING TO INCREASE TESSERACT ACCURACY
> //Create a BitmapData and Lock all pixels to be read
> BitmapData bmpData = bmp.LockBits(
> new Rectangle(0, 0, bmp.Width, bmp.Height),
> ImageLockMode.ReadOnly, bmp.PixelFormat);
> /// <summary>
> /// Build and return a AnalysisResults object that contains
> the results of the Tesseract
> /// extraction.
> /// </summary>
> /// <param name="data">A pointer to the data to be
> transformed.</param>
> /// <returns>A AnalysisResults structure that contains the
> results of the Tesseract
> /// extraction.</returns>
> private static AnalysisResults BuildAnalysisResults(IntPtr
> data)
> {
> AnalysisResults analysisResults = new AnalysisResults();
> //Retreives the structure starting at the address of the
> pointer
> analysisResults.generalInfos = (GeneralInfos)
> (Marshal.PtrToStructure(data, typeof(GeneralInfos)));
> //Move to the text data (next data is actually at + 20 not
> 4, but 4 will be
> //add up with 16 in the for loop (and make 20)
> data = new IntPtr(data.ToInt32() + 4);
> for (int i = 0; i < analysisResults.generalInfos.count; i+
> +)
> {
> //Move to the next character
> data = new IntPtr(data.ToInt32() + 16);
> //TODO: ADD CHARACTER ANALYSIS TO FORMAT THE STRING OR/
> AND TO REMOVE UNWANTED CHARACTERS
> //Lets add all the white space detected
> for(int j = 0; j<charInfos.blanks;j++)
> analysisResults.stringFound += " ";
> //Now lets add the char found
> analysisResults.stringFound +=
> (char)charInfos.char_code;
> }
> //Unaffect the pointer
> data = IntPtr.Zero;
> return analysisResults;
> }
> }
> }
> </CODE SNIPPET>
> Knowing the offset of each value returned by my structure and because
> of the complexity of it, i decided that it would be better to build
> the structure myselft. But if the structure was without any array that
> can grows i would suggest to use the marshal.PtrToStructure fonction.
> Plus the first methods required a pointer to the first pixel of an
> image. In my first code i was using the .save method, but it save the
> content of the header as well, so what i neeeded to do is to use
> the
// Get an ImageCodecInfo object that represents the TIFF
codec.
myImageCodecInfo = GetEncoder(ImageFormat.Tiff);
// Create an Encoder object based on the GUID
// for the Compression parameter category.
myEncoder = System.Drawing.Imaging.Encoder.Compression;
// Create an EncoderParameters object.
// An EncoderParameters object has an array of
EncoderParameter
// objects. In this case, there is only one
// EncoderParameter object in the array.
myEncoderParameters = new EncoderParameters(1);
// Save the bitmap as a TIFF file with no compression.
myEncoderParameter = new EncoderParameter(myEncoder,
(long)System.Drawing.Imaging.EncoderValue.CompressionNone);
> OK congrats on the progress so far! I can run all the way through now
> without any memory errors :)
> Now I just need to get my image to a point where it can be processed
> correctly. I've tried reading a bitmap from a file and passing that,
> but I never get the results expected. Usually I just get a single
> tilde '~' back from the call.
> Ultimately I want to be able to capture part of the screen and process
> that. Any ideas on how to get this to work reliably? Any idea on
> exactly what format the bitmap needs to be in to get tesseract to like
> it?
> Thanks!
> On Mar 5, 11:50 am, EricD <eri...@videotron.ca> wrote:
> > Ok before i start, i want to tell everyone that this code work to
> > invoke only 3 fonctions of tesseract
> > (TessDllBeginPageUpright,TessDllBeginPage and
> > TessDllRecognize_all_Words) but it can be easily expanded if you
> > follow the logic.
> > Plus this code is only a startup, this is why i wont post the .cs to
> > the group right now since its not finished (I'm posting it only to
> > help those who need a wrapper fast)
> > Another thing i realized is that SOME images will have different (and
> > ugly) results than if you used tesseract.exe or the .dll. This is
> > probably cause because tesseract.exe and the .dll must do some image
> > preprocessing before it is analysed (am i right?)
> > So the next version of the code will fix this problem
> > BUGS: Here's a list of bugs that i found when using the wrapper
> > 1-Changing language between some extraction make the application
> > crash.
> > 2-Results vary from the wrapper and the dlltest for SOME image
> > (Preprocessing missing?)
> > ...more to come
> > And remember this is only a prototype of the wrapper and it may
> > contains some bug so do not use it without testing it to make sure it
> > does what you want.
> > <CODE SNIPPET>
> > using System;
> > using System.Collections.Generic;
> > using System.Text;
> > using System.Drawing;
> > using System.Runtime.InteropServices;
> > using System.Drawing.Imaging;
> > using System.IO;
> > /
> > **********************************************************************
> > * CharDescription
> > * Description of a single character. The character code is defined by
> > * the character set of the current font.
> > * Output text is sent as an array of these structures.
> > * Spaces and line endings in the output are represented in the
> > * structures of the surrounding characters. They are not directly
> > * represented as characters.
> > * The first character in a word has a positive value of blanks.
> > * Missing information should be set to the defaults in the comments.
> > * If word bounds are known, but not character bounds, then the top
> > and
> > * bottom of each character should be those of the word. The left of
> > the
> > * first and right of the last char in each word should be set. All
> > other
> > * lefts and rights should be set to -1.
> > * If set, the values of right and bottom are left+width and top
> > +height.
> > * Most of the members come directly from the parameters to
> > ocr_append_char.
> > * The formatting member uses the enhancement parameter and combines
> > the
> > * line direction stuff into the top 3 bits.
> > * The coding is 0=RL char, 1=LR char, 2=DR NL, 3=UL NL, 4=DR Para,
> > * 5=UL Para, 6=TB char, 7=BT char. API users do not need to know what
> > * the coding is, only that it is backwards compatible with the
> > previous
> > * version.
> > **********************************************************************/
> > [StructLayout(LayoutKind.Sequential)]
> > public struct CharDescription /*single character */
> > {
> > public UInt16 char_code; /*character itself */
> > public Int16 left; /*of char (-1) */
> > public Int16 right; /*of char (-1) */
> > public Int16 top; /*of char (-1) */
> > public Int16 bottom; /*of char (-1) */
> > public Int16 font_index; /*what font (0) */
> > public Byte confidence; /*0=perfect, 100=reject
> > (0/100) */
> > public Byte point_size; /*of char, 72=i inch, (10) */
> > public SByte blanks; /*no of spaces before this
> > char (1) */
> > public Byte formatting; /*char formatting (0) */
> > } /*single character */
> > [StructLayout(LayoutKind.Sequential)]
> > public struct GeneralInfos /*output header */
> > {
> > public Int16 count; /*chars in this buffer(0) */
> > public Int16 progress; /*percent complete
> > increasing (0-100) */
> > public SByte more_to_come; /*true if not last */
> > public SByte ocr_alive; /*ocr sets to 1, HP 0 */
> > public SByte err_code; /*for errcode use */
> > public Byte cancelSignature;
> > public unsafe void* cancel; /*returns true to cancel */
> > public unsafe void* cancel_this; /*this or other data
> > for cancel*/
> > public Int32 end_time; /*time to stop if not 0*/
> > }
> > /// <summary>
> > /// Used for returning a managed structure contains OCR extraction
> > results
> > /// </summary>
> > [StructLayout(LayoutKind.Sequential)]
> > public class AnalysisResults
> > {
> > public GeneralInfos generalInfos=new GeneralInfos();
> > public List<CharDescription> charactersFound = new
> > List<CharDescription>();
> > public string stringFound = "";
> > }
> > namespace tesseractOCR
> > {
> > /// <summary>
> > /// A wrapper that expose some fonctionnalies of TesseractOCR
> > /// </summary>
> > class WrapperTesseract
> > {
> > /// <summary>
> > /// Take an image and extract any text found using the
> > specified language with TesseractOCR.
> > /// </summary>
> > /// <param name="bmp">The image to analyse.</param>
> > /// <param name="language">The language to be used to extract
> > text.</param>
> > /// <param name="bpp">The number of bits per pixel(bpp) of the
> > image.</param>
> > /// <returns>A AnalysisResults structure that contains the
> > results of the Tesseract
> > /// extraction.</returns>
> > public static AnalysisResults
> > recognizeChars(System.Drawing.Bitmap bmp, string language, Byte bpp)
> > {
> > //TODO: IMAGE RESIZING TO INCREASE TESSERACT ACCURACY
> > //Create a BitmapData and Lock all pixels to be read
> > BitmapData bmpData = bmp.LockBits(
> > new Rectangle(0, 0, bmp.Width, bmp.Height),
> > ImageLockMode.ReadOnly, bmp.PixelFormat);
After some tests with the dll, the .exe and my wrapper i notice that
the data retrieve are not always the same.
In fact the .exe is the one giving me the best results, after its
the .dll and finally my wrapper.
Ok maybe my wrapper is buggy at the moment but why isn't the .dll
results not the same as the .exe results.
What is so different between the .dll and the .exe
I've done the test on different image and below is the results found
(i could also upload my image in case someone want to help me) (with
eng language)
Actual Word | Res .dll | Res wrapper| Res .exe
--------------------------------------------------------------------
MFD | unru- | {S! | nrt!
FMS1 | ~ | ~ | FHS1
HDG | HUG | HUG | HDG
PFD | PFD | REU | PFD
113.80 | 113.80 | ~ | 113.80
The image are small and maybe not that clear, so i'm expecting that
the value retreived wont be 100% accurate. But I want at least to see
that value extracted to have the same results as the .exe.
Why are the results so different?!
On Mar 6, 12:05 pm, EricD <eri...@videotron.ca> wrote:
> // Get an ImageCodecInfo object that represents the TIFF
> codec.
> myImageCodecInfo = GetEncoder(ImageFormat.Tiff);
> // Create an Encoder object based on the GUID
> // for the Compression parameter category.
> myEncoder = System.Drawing.Imaging.Encoder.Compression;
> // Create an EncoderParameters object.
> // An EncoderParameters object has an array of
> EncoderParameter
> // objects. In this case, there is only one
> // EncoderParameter object in the array.
> myEncoderParameters = new EncoderParameters(1);
> // Save the bitmap as a TIFF file with no compression.
> myEncoderParameter = new EncoderParameter(myEncoder,
> (long)System.Drawing.Imaging.EncoderValue.CompressionNone);
> (this save the image to a file but you can easily just rebuild the
> image with the new compression infos without saving it)
> On Mar 5, 2:29 pm, twknox <twk...@gmail.com> wrote:
> > OK congrats on the progress so far! I can run all the way through now
> > without any memory errors :)
> > Now I just need to get my image to a point where it can be processed
> > correctly. I've tried reading a bitmap from a file and passing that,
> > but I never get the results expected. Usually I just get a single
> > tilde '~' back from the call.
> > Ultimately I want to be able to capture part of the screen and process
> > that. Any ideas on how to get this to work reliably? Any idea on
> > exactly what format the bitmap needs to be in to get tesseract to like
> > it?
> > Thanks!
> > On Mar 5, 11:50 am, EricD <eri...@videotron.ca> wrote:
> > > Ok before i start, i want to tell everyone that this code work to
> > > invoke only 3 fonctions of tesseract
> > > (TessDllBeginPageUpright,TessDllBeginPage and
> > > TessDllRecognize_all_Words) but it can be easily expanded if you
> > > follow the logic.
> > > Plus this code is only a startup, this is why i wont post the .cs to
> > > the group right now since its not finished (I'm posting it only to
> > > help those who need a wrapper fast)
> > > Another thing i realized is that SOME images will have different (and
> > > ugly) results than if you used tesseract.exe or the .dll. This is
> > > probably cause because tesseract.exe and the .dll must do some image
> > > preprocessing before it is analysed (am i right?)
> > > So the next version of the code will fix this problem
> > > BUGS: Here's a list of bugs that i found when using the wrapper
> > > 1-Changing language between some extraction make the application
> > > crash.
> > > 2-Results vary from the wrapper and the dlltest for SOME image
> > > (Preprocessing missing?)
> > > ...more to come
> > > And remember this is only a prototype of the wrapper and it may
> > > contains some bug so do not use it without testing it to make sure it
> > > does what you want.
> > > <CODE SNIPPET>
> > > using System;
> > > using System.Collections.Generic;
> > > using System.Text;
> > > using System.Drawing;
> > > using System.Runtime.InteropServices;
> > > using System.Drawing.Imaging;
> > > using System.IO;
> > > /
> > > **********************************************************************
> > > * CharDescription
> > > * Description of a single character. The character code is defined by
> > > * the character set of the current font.
> > > * Output text is sent as an array of these structures.
> > > * Spaces and line endings in the output are represented in the
> > > * structures of the surrounding characters. They are not directly
> > > * represented as characters.
> > > * The first character in a word has a positive value of blanks.
> > > * Missing information should be set to the defaults in the comments.
> > > * If word bounds are known, but not character bounds, then the top
> > > and
> > > * bottom of each character should be those of the word. The left of
> > > the
> > > * first and right of the last char in each word should be set. All
> > > other
> > > * lefts and rights should be set to -1.
> > > * If set, the values of right and bottom are left+width and top
> > > +height.
> > > * Most of the members come directly from the parameters to
> > > ocr_append_char.
> > > * The formatting member uses the enhancement parameter and combines
> > > the
> > > * line direction stuff into the top 3 bits.
> > > * The coding is 0=RL char, 1=LR char, 2=DR NL, 3=UL NL, 4=DR Para,
> > > * 5=UL Para, 6=TB char, 7=BT char. API users do not need to know what
> > > * the coding is, only that it is backwards compatible with the
> > > previous
> > > * version.
> > > public UInt16 char_code; /*character itself */
> > > public Int16 left; /*of char (-1) */
> > > public Int16 right; /*of char (-1) */
> > > public Int16 top; /*of char (-1) */
> > > public Int16 bottom; /*of char (-1) */
> > > public Int16 font_index; /*what font (0) */
> > > public Byte confidence; /*0=perfect, 100=reject
> > > (0/100) */
> > > public Byte point_size; /*of char, 72=i inch, (10) */
> > > public SByte blanks; /*no of spaces before this
> > > char (1) */
> > > public Byte formatting; /*char formatting (0) */
> > > } /*single character */
> > > [StructLayout(LayoutKind.Sequential)]
> > > public struct GeneralInfos /*output header */
> > > {
> > > public Int16 count; /*chars in this buffer(0) */
> > > public Int16 progress; /*percent complete
> > > increasing (0-100) */
> > > public SByte more_to_come; /*true if not last */
> > > public SByte ocr_alive; /*ocr sets to 1, HP 0 */
> > > public SByte err_code; /*for errcode use */
> > > public Byte cancelSignature;
> > > public unsafe void* cancel; /*returns true to cancel */
> > > public unsafe void* cancel_this; /*this or other data
> > > for cancel*/
> > > public Int32 end_time; /*time to stop if not 0*/
> > > }
> > > /// <summary>
> > > /// Used for returning a managed structure contains OCR extraction
> > > results
> > > /// </summary>
> > > [StructLayout(LayoutKind.Sequential)]
> > > public class AnalysisResults
> > > {
> > > public GeneralInfos generalInfos=new GeneralInfos();
> > > public List<CharDescription> charactersFound = new
> > > List<CharDescription>();
> > > public string stringFound = "";
> > > }
> > > namespace tesseractOCR
> > > {
> > > /// <summary>
> > > /// A wrapper that expose some fonctionnalies of TesseractOCR
> > > /// </summary>
> > > class WrapperTesseract
> > > {
Hi all,
I have written code that interacts with Tessdll.dll through PInvoke
but it is still too slow when it is passed a tiff image from an A4
page.
An article will soon be published in italian, on factory.wavegroup.it
and shortly after that, I will post my code there.
P.S.There are differences between my code and Eric's code and I can't
get all the fields of the
ETEXT_DESC structure although i get the fields of EANYCODE_CHAR
correctly.
Thanks Eric, I'll try this when I get home this eve. I tried creating
an uncompressed bmp and it didn't like that from the wrapper, though
it worked fine from dlltest. I have modified a copy of "dlltest" that
I am currently calling from my C# application. It's clunky, so
calling directly is preferred.
My application is actually quite simple, it grabs a grid of 25
characters from the screen and just needs to do OCR on these. I
currently take the color image, and convert to 1bpp, inverting the
black/white so that the background is white, and the actual text is
black. This I am writing out to a .bmp, and calling the modified exe
that returns a string of 25 chars (or so I hope for). I am getting 90%
+ accuracy this way so far....
On Mar 6, 12:05 pm, EricD <eri...@videotron.ca> wrote:
> // Get an ImageCodecInfo object that represents the TIFF
> codec.
> myImageCodecInfo = GetEncoder(ImageFormat.Tiff);
> // Create an Encoder object based on the GUID
> // for the Compression parameter category.
> myEncoder = System.Drawing.Imaging.Encoder.Compression;
> // Create an EncoderParameters object.
> // An EncoderParameters object has an array of
> EncoderParameter
> // objects. In this case, there is only one
> // EncoderParameter object in the array.
> myEncoderParameters = new EncoderParameters(1);
> // Save the bitmap as a TIFF file with no compression.
> myEncoderParameter = new EncoderParameter(myEncoder,
> (long)System.Drawing.Imaging.EncoderValue.CompressionNone);
> (this save the image to a file but you can easily just rebuild the
> image with the new compression infos without saving it)
> On Mar 5, 2:29 pm, twknox <twk...@gmail.com> wrote:
> > OK congrats on the progress so far! I can run all the way through now
> > without any memory errors :)
> > Now I just need to get my image to a point where it can be processed
> > correctly. I've tried reading a bitmap from a file and passing that,
> > but I never get the results expected. Usually I just get a single
> > tilde '~' back from the call.
> > Ultimately I want to be able to capture part of the screen and process
> > that. Any ideas on how to get this to work reliably? Any idea on
> > exactly what format the bitmap needs to be in to get tesseract to like
> > it?
> > Thanks!
> > On Mar 5, 11:50 am, EricD <eri...@videotron.ca> wrote:
> > > Ok before i start, i want to tell everyone that this code work to
> > > invoke only 3 fonctions of tesseract
> > > (TessDllBeginPageUpright,TessDllBeginPage and
> > > TessDllRecognize_all_Words) but it can be easily expanded if you
> > > follow the logic.
> > > Plus this code is only a startup, this is why i wont post the .cs to
> > > the group right now since its not finished (I'm posting it only to
> > > help those who need a wrapper fast)
> > > Another thing i realized is that SOME images will have different (and
> > > ugly) results than if you used tesseract.exe or the .dll. This is
> > > probably cause because tesseract.exe and the .dll must do some image
> > > preprocessing before it is analysed (am i right?)
> > > So the next version of the code will fix this problem
> > > BUGS: Here's a list of bugs that i found when using the wrapper
> > > 1-Changing language between some extraction make the application
> > > crash.
> > > 2-Results vary from the wrapper and the dlltest for SOME image
> > > (Preprocessing missing?)
> > > ...more to come
> > > And remember this is only a prototype of the wrapper and it may
> > > contains some bug so do not use it without testing it to make sure it
> > > does what you want.
> > > <CODE SNIPPET>
> > > using System;
> > > using System.Collections.Generic;
> > > using System.Text;
> > > using System.Drawing;
> > > using System.Runtime.InteropServices;
> > > using System.Drawing.Imaging;
> > > using System.IO;
> > > /
> > > **********************************************************************
> > > * CharDescription
> > > * Description of a single character. The character code is defined by
> > > * the character set of the current font.
> > > * Output text is sent as an array of these structures.
> > > * Spaces and line endings in the output are represented in the
> > > * structures of the surrounding characters. They are not directly
> > > * represented as characters.
> > > * The first character in a word has a positive value of blanks.
> > > * Missing information should be set to the defaults in the comments.
> > > * If word bounds are known, but not character bounds, then the top
> > > and
> > > * bottom of each character should be those of the word. The left of
> > > the
> > > * first and right of the last char in each word should be set. All
> > > other
> > > * lefts and rights should be set to -1.
> > > * If set, the values of right and bottom are left+width and top
> > > +height.
> > > * Most of the members come directly from the parameters to
> > > ocr_append_char.
> > > * The formatting member uses the enhancement parameter and combines
> > > the
> > > * line direction stuff into the top 3 bits.
> > > * The coding is 0=RL char, 1=LR char, 2=DR NL, 3=UL NL, 4=DR Para,
> > > * 5=UL Para, 6=TB char, 7=BT char. API users do not need to know what
> > > * the coding is, only that it is backwards compatible with the
> > > previous
> > > * version.
> > > public UInt16 char_code; /*character itself */
> > > public Int16 left; /*of char (-1) */
> > > public Int16 right; /*of char (-1) */
> > > public Int16 top; /*of char (-1) */
> > > public Int16 bottom; /*of char (-1) */
> > > public Int16 font_index; /*what font (0) */
> > > public Byte confidence; /*0=perfect, 100=reject
> > > (0/100) */
> > > public Byte point_size; /*of char, 72=i inch, (10) */
> > > public SByte blanks; /*no of spaces before this
> > > char (1) */
> > > public Byte formatting; /*char formatting (0) */
> > > } /*single character */
> > > [StructLayout(LayoutKind.Sequential)]
> > > public struct GeneralInfos /*output header */
> > > {
> > > public Int16 count; /*chars in this buffer(0) */
> > > public Int16 progress; /*percent complete
> > > increasing (0-100) */
> > > public SByte more_to_come; /*true if not last */
> > > public SByte ocr_alive; /*ocr sets to 1, HP 0 */
> > > public SByte err_code; /*for errcode use */
> > > public Byte cancelSignature;
> > > public unsafe void* cancel; /*returns true to cancel */
> > > public unsafe void* cancel_this; /*this or other data
> > > for cancel*/
> > > public Int32 end_time; /*time to stop if not 0*/
> > > }
> > > /// <summary>
> > > /// Used for returning a managed structure contains OCR extraction
> > > results
> > > /// </summary>
> > > [StructLayout(LayoutKind.Sequential)]
> > > public class AnalysisResults
> > > {
> > > public GeneralInfos generalInfos=new GeneralInfos();
> > > public List<CharDescription> charactersFound = new
> > > List<CharDescription>();
> > > public string stringFound = "";
> > > }
> > > namespace tesseractOCR
> > > {
> > > /// <summary>
> > > /// A wrapper that expose some fonctionnalies of TesseractOCR
> > > /// </summary>
> > > class WrapperTesseract
> > > {
> > > /// <summary>
> > > /// Take an image and extract any text found using the
> > > specified language with TesseractOCR.
> > > /// </summary>
> > > /// <param name="bmp">The image to analyse.</param>
> > > /// <param name="language">The language to be used to extract
> > > text.</param>
> > > /// <param name="bpp">The number of bits per pixel(bpp) of the
> > > image.</param>
> > > ///
Ok, there IS a difference between the way the .exe and the .dll
extract the data.
I've created a new dll fonction that does the same logic as the .exe.
(i wont post it right now because once again its not complete and ill
post it tomorow maybe)
But now i'm sure my wrapper doesnt convert the image to a const char*
correctly because whe i try to open from a file the result is correct
but when i pass the buffer, result is messed up.
I need help from anyone interested by the wrapper to see whats my
error in my code?
The dll requires that the pointer is the top pixel of the image, so
the header of the image must be removed!
Please help.
But the thing is
On Mar 7, 9:08 am, twknox <twk...@gmail.com> wrote:
> Thanks Eric, I'll try this when I get home this eve. I tried creating
> an uncompressed bmp and it didn't like that from the wrapper, though
> it worked fine from dlltest. I have modified a copy of "dlltest" that
> I am currently calling from my C# application. It's clunky, so
> calling directly is preferred.
> My application is actually quite simple, it grabs a grid of 25
> characters from the screen and just needs to do OCR on these. I
> currently take the color image, and convert to 1bpp, inverting the
> black/white so that the background is white, and the actual text is
> black. This I am writing out to a .bmp, and calling the modified exe
> that returns a string of 25 chars (or so I hope for). I am getting 90%
> + accuracy this way so far....
> On Mar 6, 12:05 pm, EricD <eri...@videotron.ca> wrote:
> > try this code to transform your image to a tiff file with no
> > compression :
> > // Get an ImageCodecInfo object that represents the TIFF
> > codec.
> > myImageCodecInfo = GetEncoder(ImageFormat.Tiff);
> > // Create an Encoder object based on the GUID
> > // for the Compression parameter category.
> > myEncoder = System.Drawing.Imaging.Encoder.Compression;
> > // Create an EncoderParameters object.
> > // An EncoderParameters object has an array of
> > EncoderParameter
> > // objects. In this case, there is only one
> > // EncoderParameter object in the array.
> > myEncoderParameters = new EncoderParameters(1);
> > // Save the bitmap as a TIFF file with no compression.
> > myEncoderParameter = new EncoderParameter(myEncoder,
> > (long)System.Drawing.Imaging.EncoderValue.CompressionNone);
> > (this save the image to a file but you can easily just rebuild the
> > image with the new compression infos without saving it)
> > On Mar 5, 2:29 pm, twknox <twk...@gmail.com> wrote:
> > > OK congrats on the progress so far! I can run all the way through now
> > > without any memory errors :)
> > > Now I just need to get my image to a point where it can be processed
> > > correctly. I've tried reading a bitmap from a file and passing that,
> > > but I never get the results expected. Usually I just get a single
> > > tilde '~' back from the call.
> > > Ultimately I want to be able to capture part of the screen and process
> > > that. Any ideas on how to get this to work reliably? Any idea on
> > > exactly what format the bitmap needs to be in to get tesseract to like
> > > it?
> > > Thanks!
> > > On Mar 5, 11:50 am, EricD <eri...@videotron.ca> wrote:
> > > > Ok before i start, i want to tell everyone that this code work to
> > > > invoke only 3 fonctions of tesseract
> > > > (TessDllBeginPageUpright,TessDllBeginPage and
> > > > TessDllRecognize_all_Words) but it can be easily expanded if you
> > > > follow the logic.
> > > > Plus this code is only a startup, this is why i wont post the .cs to
> > > > the group right now since its not finished (I'm posting it only to
> > > > help those who need a wrapper fast)
> > > > Another thing i realized is that SOME images will have different (and
> > > > ugly) results than if you used tesseract.exe or the .dll. This is
> > > > probably cause because tesseract.exe and the .dll must do some image
> > > > preprocessing before it is analysed (am i right?)
> > > > So the next version of the code will fix this problem
> > > > BUGS: Here's a list of bugs that i found when using the wrapper
> > > > 1-Changing language between some extraction make the application
> > > > crash.
> > > > 2-Results vary from the wrapper and the dlltest for SOME image
> > > > (Preprocessing missing?)
> > > > ...more to come
> > > > And remember this is only a prototype of the wrapper and it may
> > > > contains some bug so do not use it without testing it to make sure it
> > > > does what you want.
> > > > <CODE SNIPPET>
> > > > using System;
> > > > using System.Collections.Generic;
> > > > using System.Text;
> > > > using System.Drawing;
> > > > using System.Runtime.InteropServices;
> > > > using System.Drawing.Imaging;
> > > > using System.IO;
> > > > /
> > > > **********************************************************************
> > > > * CharDescription
> > > > * Description of a single character. The character code is defined by
> > > > * the character set of the current font.
> > > > * Output text is sent as an array of these structures.
> > > > * Spaces and line endings in the output are represented in the
> > > > * structures of the surrounding characters. They are not directly
> > > > * represented as characters.
> > > > * The first character in a word has a positive value of blanks.
> > > > * Missing information should be set to the defaults in the comments.
> > > > * If word bounds are known, but not character bounds, then the top
> > > > and
> > > > * bottom of each character should be those of the word. The left of
> > > > the
> > > > * first and right of the last char in each word should be set. All
> > > > other
> > > > * lefts and rights should be set to -1.
> > > > * If set, the values of right and bottom are left+width and top
> > > > +height.
> > > > * Most of the members come directly from the parameters to
> > > > ocr_append_char.
> > > > * The formatting member uses the enhancement parameter and combines
> > > > the
> > > > * line direction stuff into the top 3 bits.
> > > > * The coding is 0=RL char, 1=LR char, 2=DR NL, 3=UL NL, 4=DR Para,
> > > > * 5=UL Para, 6=TB char, 7=BT char. API users do not need to know what
> > > > * the coding is, only that it is backwards compatible with the
> > > > previous
> > > > * version.
My wrapper now use my new dll methods that actually call the same
thing as the exe would.
For the problem with the image, I've realized that i had to build the
byte[] myselft since that i have to remove the stride (padding added)
of the image.
So I would suggest adding and reviewing my dll methods to futur
release of Tesseract. What you guys think about that?
<CODE>
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using System.IO;
[StructLayout(LayoutKind.Sequential)]
public struct CharDescription /*single character */
{
public UInt16 char_code; /*character itself */
public Int16 left; /*of char (-1) */
public Int16 right; /*of char (-1) */
public Int16 top; /*of char (-1) */
public Int16 bottom; /*of char (-1) */
public Int16 font_index; /*what font (0) */
public Byte confidence; /*0=perfect, 100=reject
(0/100) */
public Byte point_size; /*of char, 72=i inch, (10) */
public SByte blanks; /*no of spaces before this
char (1) */
public Byte formatting; /*char formatting (0) */
} /*single character */
[StructLayout(LayoutKind.Sequential)]
public struct GeneralInfos /*output header */
{
public Int16 count; /*chars in this buffer(0) */
public Int16 progress; /*percent complete
increasing (0-100) */
public SByte more_to_come; /*true if not last */
public SByte ocr_alive; /*ocr sets to 1, HP 0 */
public SByte err_code; /*for errcode use */
public Byte cancelSignature;
public IntPtr cancel; /*returns true to cancel */
public IntPtr cancel_this; /*this or other data for
cancel*/
public Int32 end_time; /*time to stop if not 0*/
}
/// <summary>
/// Used for returning a managed structure contains OCR extraction
results
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public class AnalysisResults
{
public GeneralInfos generalInfos=new GeneralInfos();
public List<CharDescription> charactersFound = new
List<CharDescription>();
public string stringFound = "";
}
namespace tesseractOCR
{
/// <summary>
/// A wrapper that expose some fonctionnalies of TesseractOCR
/// </summary>
class WrapperTesseract
{
private static bool firstRun = true;
/// <summary>
/// Converts the image to byte array without Strides data..
/// </summary>
/// <param name="imageToConvert">The image to convert.</param>
/// <returns>A array of bytes</returns>
private static byte[]
ConvertImageToByteArray(System.Drawing.Bitmap imageToConvert, Byte
bpp)
{
//Create a BitmapData and Lock all pixels to be read
BitmapData bmpData = imageToConvert.LockBits(
new Rectangle(0, 0, imageToConvert.Width,
imageToConvert.Height),
ImageLockMode.ReadOnly,
imageToConvert.PixelFormat);
byte[] imgBytes = new byte[bmpData.Height * bmpData.Width
* 3];
unsafe
{
IntPtr imgPtr = (bmpData.Scan0);
int indexImg = 0;
int pointerOffset = 0;
for (int i = 0; i < bmpData.Height; i++)
{
for (int j = 0; j < bmpData.Width; j++)
{
imgBytes[indexImg] =
Marshal.ReadByte(imgPtr,pointerOffset);
indexImg++;
pointerOffset += (bpp / 8) / 3;
//Unlock the pixels
imageToConvert.UnlockBits(bmpData);
return imgBytes;
}
/// <summary>
/// Take an image and extract any text found using the
specified language with TesseractOCR DLL logic.
/// </summary>
/// <param name="bmp">The image to analyse.</param>
/// <param name="language">The language to be used to extract
text.</param>
/// <param name="bpp">The number of bits per pixel(bpp) of the
image.</param>
/// <returns>The extracted string </returns>
public static String RecognizeCharsDll(System.Drawing.Bitmap
bmp, string language)
{
if (firstRun)
firstRun = false;
else
TessDllEndPage();
Byte bpp = 0;
AnalysisResults tmp = new AnalysisResults();
IntPtr data = new IntPtr();
switch (bmp.PixelFormat)
{
case PixelFormat.Format1bppIndexed: bpp = 1; break;
case PixelFormat.Format8bppIndexed: bpp = 8; break;
case PixelFormat.Format48bppRgb: bpp = 48; break;
case PixelFormat.Format32bppRgb: bpp = 32; break;
case PixelFormat.Format24bppRgb: bpp = 24; break;
default: throw new BadImageFormatException("Please use
an image format of.... TODO");//TODO
/// <summary>
/// Take an image and extract any text found using the
specified language with TesseractOCR EXE Logic.
/// </summary>
/// <param name="bmp">The image to analyse.</param>
/// <param name="language">The language to be used to extract
text.</param>
/// <param name="bpp">The number of bits per pixel(bpp) of the
image.</param>
/// <returns>The extracted string </returns>
public static String RecognizeChars(System.Drawing.Bitmap bmp,
string language)
{
IntPtr res= new IntPtr();
Byte bpp = 0;
switch (bmp.PixelFormat)
{
case PixelFormat.Format1bppIndexed: bpp = 1; break;
case PixelFormat.Format8bppIndexed: bpp = 8; break;
case PixelFormat.Format48bppRgb: bpp = 48; break;
case PixelFormat.Format32bppRgb: bpp = 32; break;
case PixelFormat.Format24bppRgb: bpp = 24; break;
//TEMPORARY TEST
case PixelFormat.Format32bppArgb: bpp = 32; break;
default: throw new BadImageFormatException("Please use
an image format of.... TODO");//TODO
/// <summary>
/// Convert a pointer to a String.
/// </summary>
/// <param name="data">The pointer to be converted.</param>
/// <returns>The string converted.</returns>
private static String
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
namespace Wave.OCR.Test
{
public class WaveRec
{
const string dllfile = @"tessdll.dll";
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int TessDllBeginPageUprightBPPDelegate(uint
xsize, uint ysize, System.IntPtr buf,
[System.Runtime.InteropServices.InAttribute()]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropSe rvices.UnmanagedType.LPStr)]
string lang, byte bpp);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate System.IntPtr
TessDllRecognize_all_WordsDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void TessDllReleaseDelegate();
public delegate string TransformWordDelegate(string text);
static private int MAX_CHAR_RECOGNIZE = 32000;
static private int DISTANCE_WORDS = 5;
Release();
bool result = WrapperUnManaged.FreeLibrary(pDll);
}
return page;
}
catch (Exception)
{
throw;
}
finally
{
filetmp.Dispose();
ms.Dispose();
}
}
/// <summary>
/// Visita la struttura della pagina ed esegue la funzione
callback per ogni parola
/// </summary>
/// <param name="page"></param>
public static void VisitPage(OCRPage page,
TransformWordDelegate transformWord)
{
int countw = 1;
foreach (OCRRow riga in page.rows.Values)
{
foreach (OCRWord word in riga.words)
{
//delegate callback
//string s =
word.Text = transformWord(word.Text);
}
countw++;
}
}
/// <summary>
/// Estrae le parole contenute in una certa riga della pagina
e in un determinato intervallo di coordinata
/// </summary>
/// <param name="page">oggetto di tipo OCRPage che rappresenta
la pagina</param>
/// <param name="row">riga nella quale cercare</param>
/// <param name="inflim">limite inferiore dell'intervallo</
param>
/// <param name="suplim">limite superiore</param>
/// <returns>Array di parole trovate nell'intervallo</returns>
/// <author>Francesco Sinopoli</author>
public static List<OCRWord> ExtractWordsFromRange(OCRPage
page, int indexrow, decimal inflim, decimal suplim)
{
indexrow--; //l'indice ha base zero
List<OCRWord> wordsList = new List<OCRWord>();
if (!page.rows.ContainsKey(indexrow)) return wordsList;
OCRRow row = page.rows[indexrow];
foreach (OCRWord word in row.words)
{
if ((word.Left < inflim && word.Right < inflim) ||
(word.Left > suplim && word.Right > suplim)) continue;
wordsList.Add(word);
}
return wordsList;
}
/// <summary>
/// Riempie la struttura della pagina dopo il marshaling delle
strutture ritornate dal codice non gestito
/// </summary>
/// <param name="pagina">Oggetto di tipo OCRPage da popolare</
param>
/// <param name="words">Array di caratteri dal quale
estrapolare le parole</param>
/// <author>Francesco Sinopoli</author>
internal static void FillPageFromStruct(OCRPage page,
ETEXT_DESC[] words)
{
string word = string.Empty;
int numRow = 0;
int startRectWord = 0;
int endRectWord = 0;
int upRectWord = 0;
int downRectWord = 0;
decimal leftPre = 0;
decimal heightPre = 0;
Hi David,
compile it using the following command line
csc /target:library /out:WaveRec.dll WaveRec.cs /unsafe
and add the library as a reference into your project.
Francesco
On Apr 9, 4:45 pm, unknowner <struthers.da...@googlemail.com> wrote:
compiling is not the problem, the problem is i use vb.net, not c#. I
don't want to install c# extra to only compile this one. Can you
please upload the dll for me :)
thanks
david
On 11 Apr., 14:26, Francesco <francescosinop...@yahoo.it> wrote:
> Hi David,
> compile it using the following command line
> csc /target:library /out:WaveRec.dll WaveRec.cs /unsafe
> and add the library as a reference into your project.
> Francesco
> On Apr 9, 4:45 pm, unknowner <struthers.da...@googlemail.com> wrote:
> > Can you compile this to a DLL an put it up here for others using .NET?
I compiled the c# dll from Francesco and used it the following
(simple) way with VB.NET:
Dim s As String = ""
Dim pic As Image
pic = Image.FromFile("c:\test.tif")
Dim page As Wave.OCR.Test.OCRPage = WaveRec.CreatePageWD(pic)
Dim i, j As Integer
For i = 0 To page.rows.Count - 1
For j = 0 To page.rows(i).words.Count - 1
'MsgBox(page.rows(i).words(j).Text)
s += page.rows(i).words(j).Text & " "
Next
s += vbCrLf
Next
MsgBox(s)
It only works fine with the sample files from tesseract
(eurotext.tif). But any other file brings no useable result. The files
are wioking fine with the tesseract exe. The picture files all have
300 dpi and have 1 BitPerPixel (black & white)
Has anyone any suggestion / hint for me?
Best Regards,
Lothar
On 11 Apr., 18:33, unknowner <struthers.da...@googlemail.com> wrote:
> compiling is not the problem, the problem is i use vb.net, not c#. I
> don't want to install c# extra to only compile this one. Can you
> please upload the dll for me :)
> thanks
> david
> On 11 Apr., 14:26, Francesco <francescosinop...@yahoo.it> wrote:
> > Hi David,
> > compile it using the following command line
> > csc /target:library /out:WaveRec.dll WaveRec.cs /unsafe
> > and add the library as a reference into your project.
> > Francesco
> > On Apr 9, 4:45 pm, unknowner <struthers.da...@googlemail.com> wrote:
> > > Can you compile this to a DLL an put it up here for others using .NET?
> I compiled the c# dll from Francesco and used it the following
> (simple) way with VB.NET:
> Dim s As String = ""
> Dim pic As Image
> pic = Image.FromFile("c:\test.tif")
> Dim page As Wave.OCR.Test.OCRPage = WaveRec.CreatePageWD(pic)
> Dim i, j As Integer
> For i = 0 To page.rows.Count - 1
> For j = 0 To page.rows(i).words.Count - 1
> 'MsgBox(page.rows(i).words(j).Text)
> s += page.rows(i).words(j).Text & " "
> Next
> s += vbCrLf
> Next
> MsgBox(s)
> It only works fine with the sample files from tesseract
> (eurotext.tif). But any other file brings no useable result. The files
> are wioking fine with the tesseract exe. The picture files all have
> 300 dpi and have 1 BitPerPixel (black & white)
> Has anyone any suggestion / hint for me?
> Best Regards,
> Lothar
> On 11 Apr., 18:33, unknowner <struthers.da...@googlemail.com> wrote:
> > Hi Francesco,
> > compiling is not the problem, the problem is i use vb.net, not c#. I
> > don't want to install c# extra to only compile this one. Can you
> > please upload the dll for me :)
> > thanks
> > david
> > On 11 Apr., 14:26, Francesco <francescosinop...@yahoo.it> wrote:
> > > Hi David,
> > > compile it using the following command line
> > > csc /target:library /out:WaveRec.dll WaveRec.cs /unsafe
> > > and add the library as a reference into your project.
On Thu, May 22, 2008 at 12:20 PM, joku <JokuMu...@gmail.com> wrote:
> I've got the same issue... > I even tried using EricD's ExtractDataWithExeLogic function and I get > the same results.
> On May 18, 2:35 pm, Lothar <lot...@dornieden.org> wrote: > > I compiled the c# dll from Francesco and used it the following > > (simple) way with VB.NET:
> > Dim s As String = "" > > Dim pic As Image > > pic = Image.FromFile("c:\test.tif")
> > Dim page As Wave.OCR.Test.OCRPage = WaveRec.CreatePageWD(pic)
> > Dim i, j As Integer > > For i = 0 To page.rows.Count - 1 > > For j = 0 To page.rows(i).words.Count - 1 > > 'MsgBox(page.rows(i).words(j).Text) > > s += page.rows(i).words(j).Text & " " > > Next > > s += vbCrLf > > Next
> > MsgBox(s)
> > It only works fine with the sample files from tesseract > > (eurotext.tif). But any other file brings no useable result. The files > > are wioking fine with the tesseract exe. The picture files all have > > 300 dpi and have 1 BitPerPixel (black & white)
> > Has anyone any suggestion / hint for me?
> > Best Regards,
> > Lothar
> > On 11 Apr., 18:33, unknowner <struthers.da...@googlemail.com> wrote:
> > > Hi Francesco,
> > > compiling is not the problem, the problem is i use vb.net, not c#. I > > > don't want to install c# extra to only compile this one. Can you > > > please upload the dll for me :)
> > > thanks > > > david
> > > On 11 Apr., 14:26, Francesco <francescosinop...@yahoo.it> wrote:
> > > > Hi David, > > > > compile it using the following command line > > > > csc /target:library /out:WaveRec.dll WaveRec.cs /unsafe > > > > and add the library as a reference into your project.