Tesseract not reading single value and some values - c#

private void GetOCRValue(Bitmap image)
{
string ocrValue = "";
try
{
using (var engine = new TesseractEngine(Application.StartupPath + "\\tessdata", "eng", EngineMode.Default))
{
using (var imager = new System.Drawing.Bitmap(image))
{
using (var pix = PixConverter.ToPix(imager))
{
using (var page = engine.Process(pix))
{
ocrValue = page.GetText();
}
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
I'm trying to retrieve values from a bitmap.But Tesseract not returning the single number values and some other numbers like "13".I'm using Tesseract 3.3.0 Nuget package.How can I resolve this problem?

Related

How to create zip file in memory?

I have to create a zip file from set of urls. and it should have a proper folder structure.
So i tried like
public async Task<byte[]> CreateZip(Guid ownerId)
{
try
{
string startPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "zipFolder");//base folder
if (Directory.Exists(startPath))
{
DeleteAllFiles(startPath);
Directory.Delete(startPath);
}
Directory.CreateDirectory(startPath);
string zipPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{ownerId.ToString()}"); //folder based on ownerid
if (Directory.Exists(zipPath))
{
DeleteAllFiles(zipPath);
Directory.Delete(zipPath);
}
Directory.CreateDirectory(zipPath);
var attachemnts = await ReadByOwnerId(ownerId);
attachemnts.Data.ForEach(i =>
{
var fileLocalPath = $"{startPath}\\{i.Category}";
if (!Directory.Exists(fileLocalPath))
{
Directory.CreateDirectory(fileLocalPath);
}
using (var client = new WebClient())
{
client.DownloadFile(i.Url, $"{fileLocalPath}//{i.Flags ?? ""}_{i.FileName}");
}
});
var zipFilename = $"{zipPath}//result.zip";
if (File.Exists(zipFilename))
{
File.Delete(zipFilename);
}
ZipFile.CreateFromDirectory(startPath, zipFilename, CompressionLevel.Fastest, true);
var result = System.IO.File.ReadAllBytes(zipFilename);
return result;
}
catch (Exception ex)
{
var a = ex;
return null;
}
}
currently im writing all files in my base directory(may be not a good idea).corrently i have to manually delete all folders and files to avoid exception/unwanted files. Can everything be written in memory?
What changes required to write all files and folder structure in memory?
No you can't. Not with the built in Dotnet any way.
As per my comment I would recommend storing the files in a custom location based on a Guid or similar. Eg:
"/xxxx-xxxx-xxxx-xxxx/Folder-To-Zip/....".
This would ensure you could handle multiple requests with the same files or similar file / folder names.
Then you just have to cleanup and delete the folder again afterwards so you don't run out of space.
Hope the below code does the job.
public async Task<byte[]> CreateZip(Guid ownerId)
{
try
{
string startPath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}_zipFolder");//folder to add
Directory.CreateDirectory(startPath);
var attachemnts = await ReadByOwnerId(ownerId);
attachemnts.Data = filterDuplicateAttachments(attachemnts.Data);
//filtering youtube urls
attachemnts.Data = attachemnts.Data.Where(i => !i.Flags.Equals("YoutubeUrl", StringComparison.OrdinalIgnoreCase)).ToList();
attachemnts.Data.ForEach(i =>
{
var fileLocalPath = $"{startPath}\\{i.Category}";
if (!Directory.Exists(fileLocalPath))
{
Directory.CreateDirectory(fileLocalPath);
}
using (var client = new WebClient())
{
client.DownloadFile(i.Url, $"{fileLocalPath}//{i.Flags ?? ""}_{i.FileName}");
}
});
using (var ms = new MemoryStream())
{
using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
System.IO.DirectoryInfo di = new DirectoryInfo(startPath);
var allFiles = di.GetFiles("",SearchOption.AllDirectories);
foreach (var attachment in allFiles)
{
var file = File.OpenRead(attachment.FullName);
var type = attachemnts.Data.Where(i => $"{ i.Flags ?? ""}_{ i.FileName}".Equals(attachment.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
var entry = zipArchive.CreateEntry($"{type.Category}/{attachment.Name}", CompressionLevel.Fastest);
using (var entryStream = entry.Open())
{
file.CopyTo(entryStream);
}
}
}
var result = ms.ToArray();
return result;
}
}
catch (Exception ex)
{
var a = ex;
return null;
}
}

Digit recognition with Tesseract OCR and c#

I use Tesseract and C# to read digits. Everything works well except for the number "8". Tesseract can not read the "8" Digit.
This is the picture I send to tesseract :
And tesseract reads "50005550055".
this is my method :
public string Process(Bitmap bitmap, MetaTraderObjects metaObjects, bool isNumber = false)
{
try
{
var graphicLib = new GraphicLib();
bitmap = graphicLib.PerformReadingTextEffects(bitmap.ToBytes(), metaObjects).ToBitmap();
var result = "";
var enginePath = Const.BaseAppPath + "\\tessdata";
using (var engine = new TesseractEngine(enginePath, "eng", EngineMode.Default))
{
var ver = engine.Version;
using (var img = Pix.LoadTiffFromMemory(graphicLib.ConvertBitMapToByteArray(bitmap.ToBytes())))
{
using (var page = engine.Process(img,(PageSegMode)8))
{
var text = page.GetText();
result = TextReformer.Reform(text, isNumber);
MemoryStream ms = new MemoryStream(bitmap.ToBytes());
Image i = Image.FromStream(ms);
}
}
}
return result;
}
catch (Exception ex)
{
ExceptionLog.Handel(ex);
return null;
}
}
How can I tell Tesseract that the vertical rod is a "8"?
I recommend you use the latest version of Tesseract. It could perform better.
Tesseract 4.1.0

Dynamic resource from MemoryStream with ResourceWriter

I'm developing an app with C# and WPF;
I'm creating a resource to a MemoryStream.
var ms = new MemoryStream();
var rWriter = new ResourceWriter(ms);
rWriter.AddResource("key1", "value1");
rWriter.AddResource("key2", "value2");
rWriter.AddResource("key3", "value3");
rWriter.Generate();
rWriter.Close();
Everything works fine untill here but, I don't know how to use this Resource?
Can you help me with using ?
Once you have read the resource into the stream you need to add it to the MergedDictionaries in order to make it available in the application. An example of this might look like this:
var resourceInfo = skinAssembly.GetManifestResourceInfo(resourceName);
if (resourceInfo.ResourceLocation != ResourceLocation.ContainedInAnotherAssembly)
{
var resourceStream = skinAssembly.GetManifestResourceStream(resourceName);
using (var resourceReader = new ResourceReader(resourceStream))
{
foreach (DictionaryEntry entry in resourceReader)
{
if (IsRelevantResource(entry, bamlResourceName))
{
skinBamlStreams.Add(entry.Value as Stream);
}
}
}
}
The code above was taken from my demo application which you can see the full source code for on GitHub.
protected override sealed void LoadResources()
{
var skinResolver = PreLoadResources();
try
{
var skinBamlStreams = skinResolver.GetSkinBamlStreams(_fullName, _resourceName);
foreach (var resourceStream in skinBamlStreams)
{
var skinResource = BamlHelper.LoadBaml<ResourceDictionary>(resourceStream);
if (skinResource != null)
{
Resources.Add(skinResource);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
PostLoadResources();
}
}

Display RDL in C#

I have an RDL file designed in ReportBuilder 2. I need to show it in my C# application. I know there is an RdlViewer example at gotreportviewer.com but it is not what I really want (For example it can not handle parameters with multiple values). Instead, I'm curious about the way ReportBuilder itself shows report previews. Looking at its installation directory, I found several interesting DLLs. Using ILSpy, I saw that inside MSReportBuilder.exe, there is a method called "StartPreview()" which is called when you the "Run" button in ReportBuilder. Here is the code:
private void StartPreview()
{
try
{
if (!this.m_layoutEditor.AtBookmark("ReportPreview"))
{
using (MemoryStream memoryStream = new MemoryStream())
{
this.m_layoutEditor.CommitPendingChanges(false);
this.m_preview.Reset();
Report report;
if (this.ActiveServer != null)
{
this.m_preview.ProcessingMode = ProcessingMode.Remote;
report = this.m_preview.ServerReport;
string text = this.ActiveServer.ServerUrl;
if (this.ActiveServer.IsInSharePointMode)
{
text = Util.RemoveTrailingSlash(text) + "/_vti_bin/reportserver";
}
AuthenticationInfo authenticationInfo = this.ActiveServer.GetAuthenticationInfo();
if (authenticationInfo.IsFormsAuth)
{
this.m_preview.ServerReport.ReportServerCredentials.SetFormsCredentials(authenticationInfo.AuthCookie, authenticationInfo.UserName, authenticationInfo.Password, authenticationInfo.Domain);
}
this.m_preview.ServerReport.ReportServerUrl = new Uri(text);
using (this.m_layoutEditor.UndoManager.BeginTempGroup())
{
Report rdlObject = this.m_layoutEditor.Report.GetRdlObject();
if (this.CurrentReportInfo.IsServerReport)
{
this.m_reportProject.ResolveServerReferences(rdlObject);
}
RdlSerializer rdlSerializer = LayoutEditor.CreateSerializer();
rdlSerializer.Serialize(memoryStream, rdlObject);
}
memoryStream.Position = 0L;
this.m_preview.ServerReport.LoadReportDefinition(memoryStream);
DataSourceCredentials[] storedCredentialsForCurrentReport = this.GetStoredCredentialsForCurrentReport();
if (storedCredentialsForCurrentReport.Length > 0)
{
this.m_preview.ServerReport.SetDataSourceCredentials(storedCredentialsForCurrentReport);
}
}
else
{
this.m_preview.ProcessingMode = ProcessingMode.Local;
report = this.m_preview.LocalReport;
using (this.m_layoutEditor.UndoManager.BeginTempGroup())
{
Report rdlObject2 = this.m_layoutEditor.Report.GetRdlObject();
this.m_reportProject.FixUpDataSourceCredentialsForLocalPreview(rdlObject2);
RdlSerializer rdlSerializer2 = LayoutEditor.CreateSerializer();
rdlSerializer2.Serialize(memoryStream, rdlObject2);
}
memoryStream.Position = 0L;
this.m_preview.LocalReport.LoadReportDefinition(memoryStream);
DataSourceCredentials[] storedCredentialsForCurrentReport2 = this.GetStoredCredentialsForCurrentReport();
if (storedCredentialsForCurrentReport2.Length > 0)
{
bool flag;
this.m_preview.LocalReport.GetDataSources(out flag);
if (!flag)
{
this.m_preview.LocalReport.SetDataSourceCredentials(storedCredentialsForCurrentReport2);
}
}
}
report.DisplayName = this.CurrentReportInfo.ReportName;
this.m_preview.RefreshReport();
this.m_layoutEditor.SetBookmark("ReportPreview");
}
}
}
catch (Exception ex)
{
string message;
this.m_reportProject.ParseException(ex, out message);
ErrorDialog.Show(this, Strings.Error_Preview, message, ex);
this.SetDisplayMode(DisplayMode.Design);
}
}
Interesting point is that the code for server-side processing is very clear. But I can't understand how the client-side processing (my need) works! Can you help me do the same thing in my application?
I'm using VS 2010 / .Net 4.0

How to implement and do OCR in a C# project?

I ve been searching for a while and all that i ve seen some OCR library requests. I would like to know how to implement the purest, easy to install and use OCR library with detailed info for installation into a C# project.
If posible, I just wanna implement it like a usual dll reference...
Example:
using org.pdfbox.pdmodel;
using org.pdfbox.util;
Also a little OCR code example would be nice, such as:
public string OCRFromBitmap(Bitmap Bmp)
{
Bmp.Save(temppath, System.Drawing.Imaging.ImageFormat.Tiff);
string OcrResult = Analyze(temppath);
File.Delete(temppath);
return OcrResult;
}
So please consider that I'm not familiar to OCR projects and give me an answer like talking to a dummy.
Edit:
I guess people misunderstood my request. I wanted to know how to implement those open source OCR libraries to a C# project and how to use them. The link given as dup is not giving answers that I requested at all.
If anyone is looking into this, I've been trying different options and the following approach yields very good results. The following are the steps to get a working example:
Add .NET Wrapper for tesseract to your project. It can be added via NuGet package Install-Package Tesseract(https://github.com/charlesw/tesseract).
Go to the Downloads section of the official Tesseract project (https://code.google.com/p/tesseract-ocr/ EDIT: It's now located here: https://github.com/tesseract-ocr/langdata).
Download the preferred language data, example: tesseract-ocr-3.02.eng.tar.gz English language data for Tesseract 3.02.
Create tessdata directory in your project and place the language data files in it.
Go to Properties of the newly added files and set them to copy on build.
Add a reference to System.Drawing.
From .NET Wrapper repository, in the Samples directory copy the sample phototest.tif file into your project directory and set it to copy on build.
Create the following two files in your project (just to get started):
Program.cs
using System;
using Tesseract;
using System.Diagnostics;
namespace ConsoleApplication
{
class Program
{
public static void Main(string[] args)
{
var testImagePath = "./phototest.tif";
if (args.Length > 0)
{
testImagePath = args[0];
}
try
{
var logger = new FormattedConsoleLogger();
var resultPrinter = new ResultPrinter(logger);
using (var engine = new TesseractEngine(#"./tessdata", "eng", EngineMode.Default))
{
using (var img = Pix.LoadFromFile(testImagePath))
{
using (logger.Begin("Process image"))
{
var i = 1;
using (var page = engine.Process(img))
{
var text = page.GetText();
logger.Log("Text: {0}", text);
logger.Log("Mean confidence: {0}", page.GetMeanConfidence());
using (var iter = page.GetIterator())
{
iter.Begin();
do
{
if (i % 2 == 0)
{
using (logger.Begin("Line {0}", i))
{
do
{
using (logger.Begin("Word Iteration"))
{
if (iter.IsAtBeginningOf(PageIteratorLevel.Block))
{
logger.Log("New block");
}
if (iter.IsAtBeginningOf(PageIteratorLevel.Para))
{
logger.Log("New paragraph");
}
if (iter.IsAtBeginningOf(PageIteratorLevel.TextLine))
{
logger.Log("New line");
}
logger.Log("word: " + iter.GetText(PageIteratorLevel.Word));
}
} while (iter.Next(PageIteratorLevel.TextLine, PageIteratorLevel.Word));
}
}
i++;
} while (iter.Next(PageIteratorLevel.Para, PageIteratorLevel.TextLine));
}
}
}
}
}
}
catch (Exception e)
{
Trace.TraceError(e.ToString());
Console.WriteLine("Unexpected Error: " + e.Message);
Console.WriteLine("Details: ");
Console.WriteLine(e.ToString());
}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
private class ResultPrinter
{
readonly FormattedConsoleLogger logger;
public ResultPrinter(FormattedConsoleLogger logger)
{
this.logger = logger;
}
public void Print(ResultIterator iter)
{
logger.Log("Is beginning of block: {0}", iter.IsAtBeginningOf(PageIteratorLevel.Block));
logger.Log("Is beginning of para: {0}", iter.IsAtBeginningOf(PageIteratorLevel.Para));
logger.Log("Is beginning of text line: {0}", iter.IsAtBeginningOf(PageIteratorLevel.TextLine));
logger.Log("Is beginning of word: {0}", iter.IsAtBeginningOf(PageIteratorLevel.Word));
logger.Log("Is beginning of symbol: {0}", iter.IsAtBeginningOf(PageIteratorLevel.Symbol));
logger.Log("Block text: \"{0}\"", iter.GetText(PageIteratorLevel.Block));
logger.Log("Para text: \"{0}\"", iter.GetText(PageIteratorLevel.Para));
logger.Log("TextLine text: \"{0}\"", iter.GetText(PageIteratorLevel.TextLine));
logger.Log("Word text: \"{0}\"", iter.GetText(PageIteratorLevel.Word));
logger.Log("Symbol text: \"{0}\"", iter.GetText(PageIteratorLevel.Symbol));
}
}
}
}
FormattedConsoleLogger.cs
using System;
using System.Collections.Generic;
using System.Text;
using Tesseract;
namespace ConsoleApplication
{
public class FormattedConsoleLogger
{
const string Tab = " ";
private class Scope : DisposableBase
{
private int indentLevel;
private string indent;
private FormattedConsoleLogger container;
public Scope(FormattedConsoleLogger container, int indentLevel)
{
this.container = container;
this.indentLevel = indentLevel;
StringBuilder indent = new StringBuilder();
for (int i = 0; i < indentLevel; i++)
{
indent.Append(Tab);
}
this.indent = indent.ToString();
}
public void Log(string format, object[] args)
{
var message = String.Format(format, args);
StringBuilder indentedMessage = new StringBuilder(message.Length + indent.Length * 10);
int i = 0;
bool isNewLine = true;
while (i < message.Length)
{
if (message.Length > i && message[i] == '\r' && message[i + 1] == '\n')
{
indentedMessage.AppendLine();
isNewLine = true;
i += 2;
}
else if (message[i] == '\r' || message[i] == '\n')
{
indentedMessage.AppendLine();
isNewLine = true;
i++;
}
else
{
if (isNewLine)
{
indentedMessage.Append(indent);
isNewLine = false;
}
indentedMessage.Append(message[i]);
i++;
}
}
Console.WriteLine(indentedMessage.ToString());
}
public Scope Begin()
{
return new Scope(container, indentLevel + 1);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
var scope = container.scopes.Pop();
if (scope != this)
{
throw new InvalidOperationException("Format scope removed out of order.");
}
}
}
}
private Stack<Scope> scopes = new Stack<Scope>();
public IDisposable Begin(string title = "", params object[] args)
{
Log(title, args);
Scope scope;
if (scopes.Count == 0)
{
scope = new Scope(this, 1);
}
else
{
scope = ActiveScope.Begin();
}
scopes.Push(scope);
return scope;
}
public void Log(string format, params object[] args)
{
if (scopes.Count > 0)
{
ActiveScope.Log(format, args);
}
else
{
Console.WriteLine(String.Format(format, args));
}
}
private Scope ActiveScope
{
get
{
var top = scopes.Peek();
if (top == null) throw new InvalidOperationException("No current scope");
return top;
}
}
}
}
Here's one: (check out http://hongouru.blogspot.ie/2011/09/c-ocr-optical-character-recognition.html or http://www.codeproject.com/Articles/41709/How-To-Use-Office-2007-OCR-Using-C for more info)
using MODI;
static void Main(string[] args)
{
DocumentClass myDoc = new DocumentClass();
myDoc.Create(#"theDocumentName.tiff"); //we work with the .tiff extension
myDoc.OCR(MiLANGUAGES.miLANG_ENGLISH, true, true);
foreach (Image anImage in myDoc.Images)
{
Console.WriteLine(anImage.Layout.Text); //here we cout to the console.
}
}
I'm using tesseract OCR engine with TessNet2 (a C# wrapper - http://www.pixel-technology.com/freeware/tessnet2/).
Some basic code:
using tessnet2;
...
Bitmap image = new Bitmap(#"u:\user files\bwalker\2849257.tif");
tessnet2.Tesseract ocr = new tessnet2.Tesseract();
ocr.SetVariable("tessedit_char_whitelist", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,$-/#&=()\"':?"); // Accepted characters
ocr.Init(#"C:\Users\bwalker\Documents\Visual Studio 2010\Projects\tessnetWinForms\tessnetWinForms\bin\Release\", "eng", false); // Directory of your tessdata folder
List<tessnet2.Word> result = ocr.DoOCR(image, System.Drawing.Rectangle.Empty);
string Results = "";
foreach (tessnet2.Word word in result)
{
Results += word.Confidence + ", " + word.Text + ", " + word.Left + ", " + word.Top + ", " + word.Bottom + ", " + word.Right + "\n";
}
Some online API's work pretty well: ocr.space and Google Cloud Vision. Both of these are free, as long as you do less than 1000 OCR's per month. You can drag & drop an image to do a quick manual test to see how they perform for your images.
I find OCR.space easier to use (no messing around with nuget libraries), but, for my purpose, Google Cloud Vision provided slightly better results than OCR.space.
Google Cloud Vision example:
GoogleCredential cred = GoogleCredential.FromJson(json);
Channel channel = new Channel(ImageAnnotatorClient.DefaultEndpoint.Host, ImageAnnotatorClient.DefaultEndpoint.Port, cred.ToChannelCredentials());
ImageAnnotatorClient client = ImageAnnotatorClient.Create(channel);
Image image = Image.FromStream(stream);
EntityAnnotation googleOcrText = client.DetectText(image).First();
Console.Write(googleOcrText.Description);
OCR.space example:
string uri = $"https://api.ocr.space/parse/imageurl?apikey=helloworld&url={imageUri}";
string responseString = WebUtilities.DoGetRequest(uri);
OcrSpaceResult result = JsonConvert.DeserializeObject<OcrSpaceResult>(responseString);
if ((!result.IsErroredOnProcessing) && !String.IsNullOrEmpty(result.ParsedResults[0].ParsedText))
return result.ParsedResults[0].ParsedText;
A new API is OcrEngine.RecognizeAsync from WinRT/UWP. It can also be used in WinForms:
...
//for AsBuffer
using System.Runtime.InteropServices.WindowsRuntime;
...
async private void button5_Click(object sender, EventArgs e)
{
OcrEngine ocrEngine = null;
ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages();
if (ocrEngine == null) return;
//convert the image to BGRA8 format which is needed by SoftwareBitmap
//is there a better method for this?
Bitmap img = new Bitmap(#"1.png");
byte[] ba = new byte[img.Width * img.Height * 4];
int o = 0;
for (int y = 0; y < img.Height; y++)
{
for (int x = 0; x < img.Width; x++)
{
var p = img.GetPixel(x, y);
ba[o++] = p.B;
ba[o++] = p.G;
ba[o++] = p.R;
ba[o++] = p.A;
}
}
var buffer = ba.AsBuffer();
var outputBitmap = SoftwareBitmap.CreateCopyFromBuffer(
buffer,
BitmapPixelFormat.Bgra8,
img.Width,
img.Height);
var ocrResult = await ocrEngine.RecognizeAsync(outputBitmap);
}
To use WinRT/UWP API in WinForms, add Nuget package "Microsoft.Windows.SDK.Contracts" (version 10.0.17134.100 for Win10 1803 SDK tested here) as described here.

Categories

Resources