Tesseract OCR: very inaccurate result - c#

Below is my very simple program to test Tesseract performance. The result I got was not as expected though the picture was a high quality and very clear screenshot (not a complex picture with colors). Please take a look at my code and the result below. I'm not sure if I did something wrong or the Tesseract engine can not handle this?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using tessnet2;
namespace ImageProcessTesting
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int up_lef_x = 1075;
int up_lef_y = 0070;
int bo_rig_x = 1430;
int bo_rig_y = 0095;
int width = bo_rig_x - up_lef_x;
int height = bo_rig_y - up_lef_y;
var bmpScreenshot = new Bitmap(width, height, PixelFormat.Format32bppArgb);
var gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(
1075,
0070,
0,
0,
Screen.PrimaryScreen.Bounds.Size,
CopyPixelOperation.SourceCopy);
// bmpScreenshot.Save("C:\\Users\\Exa\\Screenshot.png", ImageFormat.Png);
var image = bmpScreenshot;
var ocr = new Tesseract();
ocr.Init(#"C:\Users\Exa\Desktop\tessdata", "eng", false);
var result = ocr.DoOCR(image, Rectangle.Empty);
string result_str = "";
foreach (Word word in result)
result_str += word.Text;
MessageBox.Show(result_str);
}
}
}

96DPI screen shots are typically not adequate for OCR. As written in Tesseract wiki:
There is a minimum text size for reasonable accuracy. You have to consider resolution as well as point size. Accuracy drops off below 10pt x 300dpi, rapidly below 8pt x 300dpi. A quick check is to count the pixels of the x-height of your characters. (X-height is the height of the lower case x.) At 10pt x 300dpi x-heights are typically about 20 pixels, although this can vary dramatically from font to font. Below an x-height of 10 pixels, you have very little chance of accurate results, and below about 8 pixels, most of the text will be "noise removed".
However, if you know what exact font it is, you can try re-train tesseract to get better result.

Related

Find Point from a Given Point (x,y) up to half of the width of a rectangle C#

I don't know how to express my problem in layman's term but supposed I have a rectangle that starts in Point (0,0) and its width is 32 (any measurement can be feet or pixel), I want to know what Point(x,y) (straight line) from StartPoint(0,0) up to half of the width. Is it possible in C#? Please see the attached image for illustration. Link of screenshot https://i.stack.imgur.com/HC962.png
C# Code
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ShapeDemo
{
class Program
{
static void Main(string[] args)
{
var startPoint = new Point(0,0);
var width = 32;//32 feet or pixel or any measurement
//var targetPoint=startPoint up to 16 (half of width or 32/2)
}
}
}
Do you mean this?
var width = 32;
var targetPoint = new Point(startPoint.X + (width / 2), startPoint.Y);

Take screenshot of multiple desktops of all visible applications and forms

I'm working with a system that has 4 outputs (monitors) with e.g. 1280x1024 pixels for each output. I need a screenshot of the whole desktop and all open applications on it.
I tried GetDesktopWindow() (MSDN) but it doesn't work properly. Some forms don't shown on the captured picture.
i tried GetDesktopWindow() function but it doesn't work properly.
Of course not.
The GetDesktopWindow function returns a handle to the desktop window. It doesn't have anything to do with capturing an image of that window.
Besides, the desktop window is not the same thing as "the entire screen". It refers specifically to the desktop window. See this article for more information and what can go wrong when you abuse the handle returned by this function.
i'm working with a system that have 4 outputs (monitors) with 1280x1024(e.g) for each output. i need a screenshot from whole desktop and all open applications on it.
This is relatively simple to do in the .NET Framework using the Graphics.CopyFromScreen method. You don't even need to do any P/Invoke!
The only trick in this case is making sure that you pass the appropriate dimensions. Since you have 4 monitors, passing only the dimensions of the primary screen won't work. You need to pass the dimensions of the entire virtual screen, which contains all of your monitors. Retrieve this by querying the SystemInformation.VirtualScreen property, which returns the bounds of the virtual screen. As the documentation indicates, this is the bounds of the entire desktop on a multiple monitor system.
Sample code:
// Determine the size of the "virtual screen", which includes all monitors.
int screenLeft = SystemInformation.VirtualScreen.Left;
int screenTop = SystemInformation.VirtualScreen.Top;
int screenWidth = SystemInformation.VirtualScreen.Width;
int screenHeight = SystemInformation.VirtualScreen.Height;
// Create a bitmap of the appropriate size to receive the screenshot.
using (Bitmap bmp = new Bitmap(screenWidth, screenHeight))
{
// Draw the screenshot into our bitmap.
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(screenLeft, screenTop, 0, 0, bmp.Size);
}
// Do something with the Bitmap here, like save it to a file:
bmp.Save(savePath, ImageFormat.Jpeg);
}
Edit:
please check your solution with a wpf application in a thread that is not your main thread. i tried it. it doesn't work!
Hmm, I didn't see a WPF tag on the question or mentioned anywhere in the body.
No matter, though. The code I posted works just fine in a WPF application, as long as you add the appropriate references and using declarations. You will need System.Windows.Forms and System.Drawing. There might be a more WPF-esque way of doing this that doesn't require a dependency on these WinForms assemblies, but I wouldn't know what it is.
It even works on another thread. There is nothing here that would require the UI thread.
Yes, I tested it. Here is my full test code:
using System.Windows;
using System.Windows.Forms; // also requires a reference to this assembly
using System.Drawing; // also requires a reference to this assembly
using System.Drawing.Imaging;
using System.Threading;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
// Create a new thread for demonstration purposes.
Thread thread = new Thread(() =>
{
// Determine the size of the "virtual screen", which includes all monitors.
int screenLeft = SystemInformation.VirtualScreen.Left;
int screenTop = SystemInformation.VirtualScreen.Top;
int screenWidth = SystemInformation.VirtualScreen.Width;
int screenHeight = SystemInformation.VirtualScreen.Height;
// Create a bitmap of the appropriate size to receive the screenshot.
using (Bitmap bmp = new Bitmap(screenWidth, screenHeight))
{
// Draw the screenshot into our bitmap.
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(screenLeft, screenTop, 0, 0, bmp.Size);
}
// Do something with the Bitmap here, like save it to a file:
bmp.Save("G:\\TestImage.jpg", ImageFormat.Jpeg);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
}
I have created a tiny helper because I needed this case today and tried many different functions. Independently of the number of monitors, you can save it as a file on the disk or store it in a binary field in db with the following code blocks.
ScreenShotHelper.cs
using System.ComponentModel;//This namespace is required for only Win32Exception. You can remove it if you are catching exceptions from another layer.
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace Company.Core.Helpers.Win32 {
public static class ScreenShotHelper {
private static Bitmap CopyFromScreen(Rectangle bounds) {
try {
var image = new Bitmap(bounds.Width, bounds.Height);
using var graphics = Graphics.FromImage(image);
graphics.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
return image;
}
catch(Win32Exception) {//When screen saver is active
return null;
}
}
public static Image Take(Rectangle bounds) {
return CopyFromScreen(bounds);
}
public static byte[] TakeAsByteArray(Rectangle bounds) {
using var image = CopyFromScreen(bounds);
using var ms = new MemoryStream();
image.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
public static void TakeAndSave(string path, Rectangle bounds, ImageFormat imageFormat) {
using var image = CopyFromScreen(bounds);
image.Save(path, imageFormat);
}
}
}
Usage - Binary Field
var bounds = new Rectangle();
bounds = Screen.AllScreens.Aggregate(bounds, (current, screen)
=> Rectangle.Union(current, screen.Bounds));
_card.ScreenShot = Convert.ToBase64String(ScreenShotHelper.TakeAsByteArray(bounds));
Usage - Disk file
var bounds = new Rectangle();
bounds = Screen.AllScreens.Aggregate(bounds, (current, screen)
=> Rectangle.Union(current, screen.Bounds));
ScreenShotHelper.TakeAndSave(#"d:\screenshot.png", bounds, ImageFormat.Png);

How to to shrink(scale) an entire graphics structure?

I’m trying to fit a lot of rectangles into a Bitmap, which will be displayed in a picturebox. In my real code, I figure out the total width and height of a rectangle that can encompass all them, and then I divide that by the size of the Bitmap, to get my scaling factor. The problem is I can’t figure out how to perform the scaling. The code below is a simple version of what I need to do.
Please keep in mind that I cannot rely on the picturebox’s scaling abilities (stretch), and I don’t want to simply apply the scale to the width and height of all the rectangles, because in my real code it wouldn’t work very well. I need a way to shrink it down in Graphics. It is important the Bitmap stays the same size that it is (300 X 300). Thanks. The below code is what I've gotten so far, but nothing changes with the size.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication22
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Bitmap BM = new System.Drawing.Bitmap(300, 300);
Pen PenTest = new System.Drawing.Pen(Brushes.Red);
private void Form1_Load(object sender, EventArgs e)
{
using (Graphics GR = Graphics.FromImage(BM))
{
GR.DrawRectangle(PenTest, new Rectangle(0,0,500,500));
// I need a scale of 0.60 in this example, because 300/500 = .6
GR.ScaleTransform(.6F, .6F);//Doesn't Work. No Change at all in the size of the rectangle.
}
pictureBox1.Image = BM;
}
}
}
Graphics.ScaleTransform performs the transformation but it does not draw anything.
You would need to then draw a rectangle after performing the transform on the graphics object:
using (Graphics GR = Graphics.FromImage(BM))
{
// ....
GR.ScaleTransform(.6F, .6F);
GR.DrawRectangle(PenTest, new Rectangle(0,0,500,500));
}

Load jpg then on top of it write some text at a 90 degree angle. then convert to pdf?

Using the pdfsharp.net library -- Im trying to load a big background jpg then on top of it write some text at a 90 degree angle. then save as a pdf
Why does my c# code below not work.
using System.Diagnostics;
using System.IO;
using System.Drawing;
using PdfSharp;
using PdfSharp.Drawing;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
using System.Drawing.Imaging;
namespace test
{
class Program
{
static void Main(string[] args)
{
PdfDocument myDoc = new PdfDocument();
PdfPage myPage = myDoc.AddPage();
myPage.Size = PdfSharp.PageSize.A4;
XGraphics g = XGraphics.FromPdfPage(myPage);
XImage image = XImage.FromFile(#"myjpg.jpg");
g.DrawImage(image, 0, 0, myPage.Width, myPage.Height);
XFont font = new XFont("Verdana", 20, XFontStyle.BoldItalic);
g.RotateAtTransform(90,new XPoint(0,0));
g.DrawString("test text!", font, XBrushes.Black, new XRect(0, 0, 200, 50), XStringFormats.Center);
myDoc.Save(#"test.pdf");
Process.Start(#"test.pdf");
}
}
}
Just a wild guess: your rotating at (0,0) - maybe you're rotating the text out of the page. Just presuming you see the picture but not the text.
See here for a working sample that uses rotation:
http://www.pdfsharp.net/wiki/XForms-sample.ashx
Center of rotation is not (0,0) in the sample.
If my guess is wrong, please provide more information what your code does.

Are vector based generators the best way to create barcodes?

Is vector based generators the best way to generate barcodes? If yes, what are the namespaces that it will make use of? How is it used? Can anyone share some knowledge on this?
Assuming that we are talking about UPC like barcodes, vector based generation is not a must. It's the matter of representing some bits as vertical lines. So, you can easily do this using any graphic library or even using direct access to video buffer. You can represent a single bit with multiple pixels if you need a larger barcode. You don't need to use any interpolation I guess. But if you need a certain size (in pixels/centimeters etc.), vector based solution might be handful but still not a must.
C# source code example for generating scalable barcode graphics.
Steps:
1) Open a new C# Windows Forms sample project named BarCode.
2) Add a PictureBox and change BackColor to White and Dock to Fill.
3) Add Load and Resize events to Form1.
4) Copy & Paste the source code below over Form1.cs file.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace BarCode
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public bool[] barCodeBits;
private void Form1_Load(object sender, EventArgs e)
{
Random r = new Random();
int numberOfBits = 100;
barCodeBits = new bool[numberOfBits];
for(int i = 0; i < numberOfBits; i++) {
barCodeBits[i] = (r.Next(0, 2) == 1) ? true : false;
}
Form1_Resize(null, null);
}
private void Form1_Resize(object sender, EventArgs e)
{
int w = pictureBox1.Width;
int h = pictureBox1.Height;
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(pictureBox1.Image);
Brush b = new SolidBrush(Color.Black);
for(int pos = 0; pos < barCodeBits.Length; pos++) {
if(barCodeBits[pos]) {
g.FillRectangle(b, ((float)pos / (float)barCodeBits.Length) * w, 0, (1.0f / (float)barCodeBits.Length) * w, h);
}
}
}
}
}
You don't have to develop barcodes using vector based graphics. I fact have a look at this link on codeproject as most of the work is already done for you. This genrates a bitmap of the required barcode.

Categories

Resources