公司前些日子准备在项目中使用 光学字符识别技术,
(也就是我们经常听说的,你拿着相机,照一下,之后就能直接显示图片中的文字是什么)
之后我在 GIT 上找了一个歪果友仁的 Demo, 对他的项目进行简单地解析,以此来帮助其他小伙伴,简单的了解一下.
Demo: https://github.com/hatena-iti/tesseract-sample
首先来介绍一下 OCR 到底是什么.
OCR是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,
通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程.
其中 通过检测暗、亮的模式确定其形状 在我们的开发中,就涉及到图片的二值化等一系列操作,设计 OPEN_CV或 OPEN_GL等.
ps:图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果.
例如这样:
而经过二值化处理的图片,
是不是觉得很像复印的照片呢.233...
了解了图片的基本原理,接下来就到了介绍工具的部分.
我们程序中最重要的第三方库 TesseractOCR.framework
工具下载地址:
TesseractOCR.framework: https://github.com/gali8/Tesseract-OCR-iOS
@interface Tesseract : NSObject
+ (NSString *)version;
@property (nonatomic, strong) NSString* language;
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, assign) CGRect rect;
@property (nonatomic, readonly) short progress; // from 0 to 100
@property (nonatomic, readonly) NSString *recognizedText;
@property (nonatomic, weak) id delegate;
它的代理方法如下
- (id)initWithDataPath:(NSString *)dataPath language:(NSString *)language DEPRECATED_ATTRIBUTE;
- (id)initWithLanguage:(NSString*)language;
- (void)setVariableValue:(NSString *)value forKey:(NSString *)key;
- (BOOL)recognize;
- (void)clear DEPRECATED_ATTRIBUTE;
需要注意的是,TesseractOCR默认支持英文和数字,毕竟人家才26个字母外加0-9这几个数字,
如果需要识别额外的语言,则需要在 tessdata 文件下 添加对应的语言包.
首先在 StroyBoard 中 创建我们需要的图像展示区和文字展示区.
之后将其拉入 ViewController.h 中 作为属性.
#import
#import
@interface ViewController : UIViewController
@property (nonatomic, strong) IBOutlet UIImageView *imageView;
@property (nonatomic, strong) IBOutlet UILabel *label;
@end
// kImageFileName の値を @"ocr-sample-japanese"(日本語文字サンプル)に指定した場合は、
// kLanguage の値を @"jpn" に指定します。
// kImageFileName == @"ocr-sample-english" の場合は、kLanguage = @"eng" とします。)
//static NSString * const kImageFileName = @"ocr-sample-japanese"; // 日本語文字サンプル
//static NSString * const kImageFileName = @"ocr-sample-english"; // 英数字サンプル
static NSString * const kImageFileName = @"ocr-sample-chinese"; // 汉文サンプル
//static NSString * const kLanguage = @"jpn"; // 解析対象言語:日本語
//static NSString * const kLanguage = @"eng"; // 解析対象言語:英語
static NSString * const kLanguage = @"chi_sim"; // 解析対象言語:中文
@implementation ViewController {
// 文字解析用に加工したイメージデータを保持するフィールド
UIImage *adjustedImage_;
}
//@synthesize是在m文件中定义setter和getter方法的实现
@synthesize imageView=imageView_;
@synthesize label=label_;
接下来到程序的运行阶段.
- (void)viewDidLoad {
[super viewDidLoad];
// 文字解析対象の画像を表示する
self.imageView.image = [UIImage imageNamed:kImageFileName];
// 文字解析を実行する
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self analyze];
}
- (void)dealloc {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
文字的清晰度对文字的检测的成功率有很大的影响.
对图片进行了简单的处理之后,我们就将我们处理之后的图片传入我们的第三方库.并将识别出的文字返回,展示给我们.
代理方法可以展示我们对当前图片的解析程度达到了多少.
// 文字解析を実行する
- (void)analyze {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
CIImage *ciImage = [[CIImage alloc] initWithImage:self.imageView.image];
//文字を読みやすくするため、白黒にして、コントラストを強めに、また輪郭をくっきりさせるよう設定する
CIFilter *ciFilter =
[CIFilter filterWithName:@"CIColorMonochrome"
keysAndValues:kCIInputImageKey, ciImage,
@"inputColor", [CIColor colorWithRed:0.75 green:0.75 blue:0.75],
@"inputIntensity", [NSNumber numberWithFloat:1.0],
nil];
ciFilter =
[CIFilter filterWithName:@"CIColorControls"
keysAndValues:kCIInputImageKey, [ciFilter outputImage],
@"inputSaturation", [NSNumber numberWithFloat:0.0],
@"inputBrightness", [NSNumber numberWithFloat:-1.0],
@"inputContrast", [NSNumber numberWithFloat:4.0],
nil];
ciFilter =
[CIFilter filterWithName:@"CIUnsharpMask"
keysAndValues:kCIInputImageKey, [ciFilter outputImage],
@"inputRadius", [NSNumber numberWithFloat:2.5],
@"inputIntensity", [NSNumber numberWithFloat:0.5],
nil];
CIContext *ciContext = [CIContext contextWithOptions:nil];
CGImageRef cgImage =
[ciContext createCGImage:[ciFilter outputImage] fromRect:[[ciFilter outputImage] extent]];
// 文字解析対象の画像の色、コントラストを調整したものを変数に保存する
UIImage *adjustedImage = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
//----------------------------------------------------------------------------------------------
Tesseract* tesseract = [[Tesseract alloc] initWithLanguage:kLanguage];
tesseract.delegate = self;
[tesseract setImage:adjustedImage]; //image to check
[tesseract recognize];
NSString *recognizedText = [tesseract recognizedText];
tesseract = nil; //deallocate and free all memory
dispatch_async(dispatch_get_main_queue(), ^{
// 解析結果を画面に表示する
self.label.text = recognizedText;
NSLog(@"\n\n%@",recognizedText);
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
});
});
}
#pragma mark - TesseractDelegate methods
- (BOOL)shouldCancelImageRecognitionForTesseract:(Tesseract*)tesseract {
NSLog(@"progress: %d", tesseract.progress);
return NO; // return YES, if you need to interrupt tesseract before it finishes
}
完结撒花!~
更多精彩文章,尽在我的公众号.