光学字符识别(OCR,Optical Character Recognition)是指对文本资料进行扫描,然后对图像文件进行分析处理,获取文字及版面信息的过程。OCR技术非常专业,一般多是印刷、打印行业的从业人员使用,可以快速的将纸质资料转换为电子资料。关于中文OCR,目前国内水平较高的有清华文通、汉王、尚书,其产品各有千秋,价格不菲。国外OCR发展较早,像一些大公司,如IBM、微软、HP等,即使没有推出单独的OCR产品,但是他们的研发团队早已掌握核心技术,将OCR功能植入了自身的软件系统。对于我们程序员来说,一般用不到那么高级的,主要在开发中能够集成基本的OCR功能就可以了。这两天我查找了很多免费OCR软件、类库,特地整理一下,今天首先来谈谈Tesseract,下一次将讨论下Onenote 2010中的OCR API实现。可以在这里查看OCR技术的发展简史。

测试代码下载

转载请注明出处:http://www.cnblogs.com/brooks-dotnet/archive/2010/10/05/1844203.html 

 

1、Tesseract概述

Tesseract的OCR引擎最先由HP实验室于1985年开始研发,至1995年时已经成为OCR业内最准确的三款识别引擎之一。然而,HP不久便决定放弃OCR业务,Tesseract也从此尘封。

数年以后,HP意识到,与其将Tesseract束之高阁,不如贡献给开源软件业,让其重焕新生--2005年,Tesseract由美国内华达州信息技术研究所获得,并求诸于Google对Tesseract进行改进、消除Bug、优化工作。

Tesseract目前已作为开源项目发布在Google Project,其项目主页在这里查看,其最新版本3.0已经支持中文OCR,并提供了一个命令行工具。本次我们来测试一下Tesseract 3.0,由于命令行对最终用户不太友好,我用WPF简单封装了一下,就可以方便的进行中文OCR了。

 

1.1、首先到Tesseract项目主页下载命令行工具、源代码、中文语言包:

浅谈OCR之Tesseract

 

1.2、命令行工具解压缩后如下(不含1.jpg、1.txt):

浅谈OCR之Tesseract

 

1.3、为了进行中文OCR,将简体中文语言包复制到【tessdata】目录下:

浅谈OCR之Tesseract

 

1.4、在DOS下切换到Tesseract的命令行目录,查看一下tesseract.exe的命令格式:

浅谈OCR之Tesseract

 

Imagename为待OCR的图片,outputbase为OCR后的输出文件,默认是文本文件(.txt),lang为使用的语言包,configfile为配置文件。

 

1.5、下面来测试一下,准备一张jpg格式的图片,这里我是放到了和Tesseract同一个目录中:

浅谈OCR之Tesseract

 

输入:tesseract.exe 1.jpg 1 -l chi_sim,然后回车,几秒钟就OCR完成了:

这里注意命令的格式:imagename要加上扩展名.jpg,输出文件和语言包不需要加扩展名。

浅谈OCR之Tesseract

 

OCR结果:

浅谈OCR之Tesseract

 

可以看到结果不是很理想,中文识别还说的过去,但是英文、数字大都乱码。不过作为老牌的OCR引擎,能做到这种程度已经相当不错了,期待Google的后续升级吧,支持一下。

 

2、使用WPF封装Tesseract命令行

2.1、鉴于命令行书写容易出错,且对最终用户很不友好,我做了一个简单的WPF小程序,将Tesseract的命令行封装了一下:

浅谈OCR之Tesseract

 

左边选择图片、预览,右边选择输出目录,显示OCR结果,支持本地及网络图片的预览。

 

2.2、为了使得图片预览支持缩放、移动,原本打算使用微软的Zoom It API,可惜不支持WPF,于是使用了一个第三方的类:

using System;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows;
using System.Windows.Media;

namespace PanAndZoom
{
    
public class PanAndZoomViewer : ContentControl
    {
        
public double DefaultZoomFactor { getset; }
        
private FrameworkElement source;
        
private Point ScreenStartPoint = new Point(00);
        
private TranslateTransform translateTransform;
        
private ScaleTransform zoomTransform;
        
private TransformGroup transformGroup;
        
private Point startOffset;

        
public PanAndZoomViewer()
        {
            
this.DefaultZoomFactor = 1.4;
        }

        
public override void OnApplyTemplate()
        {
            
base.OnApplyTemplate();
            Setup(
this);
        }

        
void Setup(FrameworkElement control)
        {
            
this.source = VisualTreeHelper.GetChild(this0as FrameworkElement;

            
this.translateTransform = new TranslateTransform();
            
this.zoomTransform = new ScaleTransform();
            
this.transformGroup = new TransformGroup();
            
this.transformGroup.Children.Add(this.zoomTransform);
            
this.transformGroup.Children.Add(this.translateTransform);
            
this.source.RenderTransform = this.transformGroup;
            
this.Focusable = true;
            
this.KeyDown += new KeyEventHandler(source_KeyDown);
            
this.MouseMove += new MouseEventHandler(control_MouseMove);
            
this.MouseDown += new MouseButtonEventHandler(source_MouseDown);
            
this.MouseUp += new MouseButtonEventHandler(source_MouseUp);
            
this.MouseWheel += new MouseWheelEventHandler(source_MouseWheel);
        }

        
void source_KeyDown(object sender, KeyEventArgs e)
        {
            
// hit escape to reset everything
            if (e.Key == Key.Escape) Reset();
        }

        
void source_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            
// zoom into the content.  Calculate the zoom factor based on the direction of the mouse wheel.
            double zoomFactor = this.DefaultZoomFactor;
            
if (e.Delta <= 0) zoomFactor = 1.0 / this.DefaultZoomFactor;
            
// DoZoom requires both the logical and physical location of the mouse pointer
            var physicalPoint = e.GetPosition(this);
            DoZoom(zoomFactor, 
this.transformGroup.Inverse.Transform(physicalPoint), physicalPoint);

        }

        
void source_MouseUp(object sender, MouseButtonEventArgs e)
        {
            
if (this.IsMouseCaptured)
            {
                
// we're done.  reset the cursor and release the mouse pointer
                this.Cursor = Cursors.Arrow;
                
this.ReleaseMouseCapture();
            }
        }

        
void source_MouseDown(object sender, MouseButtonEventArgs e)
        {
            
// Save starting point, used later when determining how much to scroll.
            this.ScreenStartPoint = e.GetPosition(this);
            
this.startOffset = new Point(this.translateTransform.X, this.translateTransform.Y);
            
this.CaptureMouse();
            
this.Cursor = Cursors.ScrollAll;
        }


        
void control_MouseMove(object sender, MouseEventArgs e)
        {
            
if (this.IsMouseCaptured)
            {
                
// if the mouse is captured then move the content by changing the translate transform.  
                
// use the Pan Animation to animate to the new location based on the delta between the 
                
// starting point of the mouse and the current point.
                var physicalPoint = e.GetPosition(this);
                
this.translateTransform.BeginAnimation(TranslateTransform.XProperty, CreatePanAnimation(physicalPoint.X - this.ScreenStartPoint.X + this.startOffset.X), HandoffBehavior.Compose);
                
this.translateTransform.BeginAnimation(TranslateTransform.YProperty, CreatePanAnimation(physicalPoint.Y - this.ScreenStartPoint.Y + this.startOffset.Y), HandoffBehavior.Compose);
            }
        }


        
/// <summary>Helper to create the panning animation for x,y coordinates.</summary>
        
/// <param name="toValue">New value of the coordinate.</param>
        
/// <returns>Double animation</returns>
        private DoubleAnimation CreatePanAnimation(double toValue)
        {
            var da 
= new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(300)));
            da.AccelerationRatio 
= 0.1;
            da.DecelerationRatio 
= 0.9;
            da.FillBehavior 
= FillBehavior.HoldEnd;
            da.Freeze();
            
return da;
        }


        
/// <summary>Helper to create the zoom double animation for scaling.</summary>
        
/// <param name="toValue">Value to animate to.</param>
        
/// <returns>Double animation.</returns>
        private DoubleAnimation CreateZoomAnimation(double toValue)
        {
            var da 
= new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(500)));
            da.AccelerationRatio 
= 0.1;
            da.DecelerationRatio 
= 0.9;
            da.FillBehavior 
= FillBehavior.HoldEnd;
            da.Freeze();
            
return da;
        }

        
/// <summary>Zoom into or out of the content.</summary>
        
/// <param name="deltaZoom">Factor to mutliply the zoom level by. </param>
        
/// <param name="mousePosition">Logical mouse position relative to the original content.</param>
        
/// <param name="physicalPosition">Actual mouse position on the screen (relative to the parent window)</param>
        public void DoZoom(double deltaZoom, Point mousePosition, Point physicalPosition)
        {
            
double currentZoom = this.zoomTransform.ScaleX;
            currentZoom 
*= deltaZoom;
            
this.translateTransform.BeginAnimation(TranslateTransform.XProperty, CreateZoomAnimation(-1 * (mousePosition.X * currentZoom - physicalPosition.X)));
            
this.translateTransform.BeginAnimation(TranslateTransform.YProperty, CreateZoomAnimation(-1 * (mousePosition.Y * currentZoom - physicalPosition.Y)));
            
this.zoomTransform.BeginAnimation(ScaleTransform.ScaleXProperty, CreateZoomAnimation(currentZoom));
            
this.zoomTransform.BeginAnimation(ScaleTransform.ScaleYProperty, CreateZoomAnimation(currentZoom));
        }

        
/// <summary>Reset to default zoom level and centered content.</summary>
        public void Reset()
        {
            
this.translateTransform.BeginAnimation(TranslateTransform.XProperty, CreateZoomAnimation(0));
            
this.translateTransform.BeginAnimation(TranslateTransform.YProperty, CreateZoomAnimation(0));
            
this.zoomTransform.BeginAnimation(ScaleTransform.ScaleXProperty, CreateZoomAnimation(1));
            
this.zoomTransform.BeginAnimation(ScaleTransform.ScaleYProperty, CreateZoomAnimation(1));
        }
    }
}

相关文章: