设为首页收藏本站
开启辅助访问

创星网络[分享知识 传递快乐]

 找回密码
 立即注册

QQ登录

只需一步,快速开始

用新浪微博登录

只需一步,快速搞定

搜索

浅谈OCR之Tesseract

2012-8-8 12:50| 发布者: cryinglily| 查看: 608| 评论: 0|原作者: luinstein

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

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项目主页下载命令行工具、源代码、中文语言包:
[attach]404[/attach]
1.2、命令行工具解压缩后如下(不含1.jpg、1.txt):
[attach]405[/attach]

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

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

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

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

输入:tesseract.exe 1.jpg 1 -l chi_sim,然后回车,几秒钟就OCR完成了:
这里注意命令的格式:imagename要加上扩展名.jpg,输出文件和语言包不需要加扩展名。
[attach]409[/attach]

OCR结果:
[attach]410[/attach]

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

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

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

2.2、为了使得图片预览支持缩放、移动,原本打算使用微软的Zoom It API,可惜不支持WPF,于是使用了一个第三方的类:
  1. 图片缩放、移动工具类Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->using System;
  2. using System.Windows.Controls;
  3. using System.Windows.Input;
  4. using System.Windows.Media.Animation;
  5. using System.Windows;
  6. using System.Windows.Media;

  7. namespace PanAndZoom
  8. {
  9.     public class PanAndZoomViewer : ContentControl
  10.     {
  11.         public double DefaultZoomFactor { get; set; }
  12.         private FrameworkElement source;
  13.         private Point ScreenStartPoint = new Point(0, 0);
  14.         private TranslateTransform translateTransform;
  15.         private ScaleTransform zoomTransform;
  16.         private TransformGroup transformGroup;
  17.         private Point startOffset;

  18.         public PanAndZoomViewer()
  19.         {
  20.             this.DefaultZoomFactor = 1.4;
  21.         }

  22.         public override void OnApplyTemplate()
  23.         {
  24.             base.OnApplyTemplate();
  25.             Setup(this);
  26.         }

  27.         void Setup(FrameworkElement control)
  28.         {
  29.             this.source = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;

  30.             this.translateTransform = new TranslateTransform();
  31.             this.zoomTransform = new ScaleTransform();
  32.             this.transformGroup = new TransformGroup();
  33.             this.transformGroup.Children.Add(this.zoomTransform);
  34.             this.transformGroup.Children.Add(this.translateTransform);
  35.             this.source.RenderTransform = this.transformGroup;
  36.             this.Focusable = true;
  37.             this.KeyDown += new KeyEventHandler(source_KeyDown);
  38.             this.MouseMove += new MouseEventHandler(control_MouseMove);
  39.             this.MouseDown += new MouseButtonEventHandler(source_MouseDown);
  40.             this.MouseUp += new MouseButtonEventHandler(source_MouseUp);
  41.             this.MouseWheel += new MouseWheelEventHandler(source_MouseWheel);
  42.         }

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

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

  56.         }

  57.         void source_MouseUp(object sender, MouseButtonEventArgs e)
  58.         {
  59.             if (this.IsMouseCaptured)
  60.             {
  61.                 // we're done.  reset the cursor and release the mouse pointer
  62.                 this.Cursor = Cursors.Arrow;
  63.                 this.ReleaseMouseCapture();
  64.             }
  65.         }

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


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


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


  98.         /// <summary>Helper to create the zoom double animation for scaling.</summary>
  99.         /// <param name="toValue">Value to animate to.</param>
  100.         /// <returns>Double animation.</returns>
  101.         private DoubleAnimation CreateZoomAnimation(double toValue)
  102.         {
  103.             var da = new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(500)));
  104.             da.AccelerationRatio = 0.1;
  105.             da.DecelerationRatio = 0.9;
  106.             da.FillBehavior = FillBehavior.HoldEnd;
  107.             da.Freeze();
  108.             return da;
  109.         }

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

  123.         /// <summary>Reset to default zoom level and centered content.</summary>
  124.         public void Reset()
  125.         {
  126.             this.translateTransform.BeginAnimation(TranslateTransform.XProperty, CreateZoomAnimation(0));
  127.             this.translateTransform.BeginAnimation(TranslateTransform.YProperty, CreateZoomAnimation(0));
  128.             this.zoomTransform.BeginAnimation(ScaleTransform.ScaleXProperty, CreateZoomAnimation(1));
  129.             this.zoomTransform.BeginAnimation(ScaleTransform.ScaleYProperty, CreateZoomAnimation(1));
  130.         }
  131.     }
  132. }
复制代码
2.3、除了使用鼠标。还可以使用滚动条调节图片预览效果:
  1. 数据绑定Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->            <WrapPanel Grid.Row="2" Grid.Column="0">
  2.                 <Label Name="lab长度" Content="长度:" Margin="3" />
  3.                 <Slider Name="sl长度" MinWidth="50" Margin="3" VerticalAlignment="Center" Maximum="400" Value="{Binding ElementName=img图片, Path=Width, Mode=TwoWay}" />

  4.                 <Label Name="lab宽度" Content="宽度:" Margin="3" />
  5.                 <Slider Name="sl宽度" MinWidth="50" Margin="3" VerticalAlignment="Center" Maximum="400" Value="{Binding ElementName=img图片, Path=Height, Mode=TwoWay}" />

  6.                 <Label Name="lab透明度" Content="透明度:" Margin="3" />
  7.                 <Slider Name="sl透明度" MinWidth="50" Margin="3" VerticalAlignment="Center" Maximum="1" Value="{Binding ElementName=img图片, Path=Opacity, Mode=TwoWay}" />

  8.                 <Label Name="lab拉伸方式" Content="拉伸方式:" Margin="3" />
  9.                 <ComboBox Name="txt拉伸方式" Margin="3" MinWidth="85">
  10.                     <ComboBoxItem Content="Fill" />
  11.                     <ComboBoxItem Content="None" IsSelected="True" />
  12.                     <ComboBoxItem Content="Uniform" />
  13.                     <ComboBoxItem Content="UniformToFill" />
  14.                 </ComboBox>
  15.             </WrapPanel>

  16.             <local:PanAndZoomViewer Grid.Row="3" Grid.Column="0" Height="300" Margin="3">
  17.                 <Image Name="img图片" Stretch="{Binding ElementName=txt拉伸方式, Path=Text, Mode=TwoWay}" />
  18.             </local:PanAndZoomViewer>
复制代码
2.4、由于Tesseract命令行不支持直接OCR网络图片,故先下载:
  1. 图片下载Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->        private void fnStartDownload(string v_strImgPath, string v_strOutputDir, out string v_strTmpPath)
  2.         {
  3.             int n = v_strImgPath.LastIndexOf('/');
  4.             string URLAddress = v_strImgPath.Substring(0, n);
  5.             string fileName = v_strImgPath.Substring(n + 1, v_strImgPath.Length - n - 1);
  6.             this.__OutputFileName = v_strOutputDir + "\\" + fileName.Substring(0, fileName.LastIndexOf("."));

  7.             if (!Directory.Exists(System.Configuration.ConfigurationManager.AppSettings["tmpPath"]))
  8.             {
  9.                 Directory.CreateDirectory(System.Configuration.ConfigurationManager.AppSettings["tmpPath"]);
  10.             }

  11.             string Dir = System.Configuration.ConfigurationManager.AppSettings["tmpPath"];
  12.             v_strTmpPath = Dir + "\\" + fileName;

  13.             WebRequest myre = WebRequest.Create(URLAddress);
  14.             client.DownloadFile(v_strImgPath, v_strTmpPath);


  15.             //Stream str = client.OpenRead(v_strImgPath);
  16.             //StreamReader reader = new StreamReader(str);
  17.             //byte[] mbyte = new byte[Int32.Parse(System.Configuration.ConfigurationManager.AppSettings["MaxDownloadImgLength"])];
  18.             //int allmybyte = (int)mbyte.Length;
  19.             //int startmbyte = 0;
  20.             //while (allmybyte > 0)
  21.             //{
  22.             //    int m = str.Read(mbyte, startmbyte, allmybyte);
  23.             //    if (m == 0)
  24.             //    {
  25.             //        break;
  26.             //    }

  27.             //    startmbyte += m;
  28.             //    allmybyte -= m;
  29.             //}

  30.             //FileStream fstr = new FileStream(v_strTmpPath, FileMode.Create, FileAccess.Write);
  31.             //fstr.Write(mbyte, 0, startmbyte);
  32.             //str.Close();
  33.             //fstr.Close();
  34.         }
复制代码
2.5、使用Process来调用Tesseract命令行:
  1. 调用Tesseract命令行Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->        private void fnOCR(string v_strTesseractPath, string v_strSourceImgPath, string v_strOutputPath, string v_strLangPath)
  2.         {
  3.             using (Process process = new System.Diagnostics.Process())
  4.             {
  5.                 process.StartInfo.FileName = v_strTesseractPath;
  6.                 process.StartInfo.Arguments = v_strSourceImgPath + " " + v_strOutputPath + " -l " + v_strLangPath;
  7.                 process.StartInfo.UseShellExecute = false;
  8.                 process.StartInfo.CreateNoWindow = true;
  9.                 process.StartInfo.RedirectStandardOutput = true;
  10.                 process.Start();
  11.                 process.WaitForExit();
  12.             }
  13.         }
复制代码
2.6、测试本地图片:
[attach]412[/attach]

2.7、测试网络图片:
[attach]413[/attach]

小结:
本次我们简单讨论了下Tesseract的用法,作为一款开源、免费的OCR引擎,能够支持中文十分难得。虽然其识别效果不是很理想,但是对于要求不高的中小型项目来说,已经足够用了。这里有一份免费OCR工具列表,感兴趣的朋友可以研究一下。下一次将测试一下Onenote 2010中OCR功能,以及如何调用其API,为项目所用。

from:http://www.cnblogs.com/brooks-do ... /10/05/1844203.html


鲜花

握手

雷人

路过

鸡蛋

相关分类

QQ|Archiver|手机版|小黑屋|创星网络 ( 苏ICP备11027519号|网站地图  

GMT+8, 2024-5-17 13:48 , Processed in 0.057088 second(s), 16 queries .

Powered by Discuz! X3

© 2001-2013 Comsenz Inc.

返回顶部