我刚开始接触 Tesseract 库,但结果真的很糟糕。
我遵循了 Git 存储库 ( https://github.com/gali8/Tesseract-OCR-iOS ) 中的说明。我的 ViewController 使用以下方法开始识别:
Tesseract *t = [[Tesseract alloc] initWithLanguage:@"deu"];
t.delegate = self;
[t setVariableValue:@"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" forKey:@"tessedit_char_whitelist"];
[t setImage:img];
[t recognize];
NSLog( @"Recognized text: %@", [t recognizedText] );
labelRecognizedText.text = [t recognizedText];
t = nil;
效果很好(这告诉我项目本身设置正确),但每当我尝试使用其他图像时,识别的文本都是一团糟。例如,我试图为显示示例图像的取景器拍照:
https://dl.dropboxusercontent.com/u/607872/tesseract.jpg (1,5 MB)
但 Tesseract 识别:
Recognized text: s f l TO if v Ysssifss f
ssqxizg ss sfzzlj z
s N T IYIOGY Z I l EY s s
k Es ETL ZHE s UEY
z xhks Fsjs Es z VIII c
s I XFTZT c s h V Ijzs
L s sk sisijk J
s f s ssj Jss sssHss H VI
s s H
i s H st xzs
s s k 4 is x2 IV
Illlsiqss sssnsiisfjlisszxiij s
K
即使字符白名单只包含数字,我也不会得到与图像看起来更接近的结果:
Recognized text: 3 74 211
1
1 1 1
3 53 379 1
3 1 33 5 3 2
3 9 73
1 61 2 2
3 1 6 5 212 7
1
4 9 4
1 17
111 11 1 1 11 1 1 1 1
我假设我目前使用的 iPad mini 相机拍摄照片的方式有问题,但我不知道是什么原因。
有什么提示吗?
更新 #1
回应托马斯:
我按照您帖子中的教程进行操作,但在此过程中遇到了一些错误...
- 我的 ARC 项目中不能使用
UIImage+OpenCV
类别 - 我无法在我的 Controller 中导入
<opencv2/...>
,自动完成不提供它(因此未定义[UIImage CVMat]
)
我认为我的 OpenCV 集成有问题,即使我遵循了 Hello-tutorial 并添加了框架。我是否也需要在我的 Mac 上构建 OpenCV,或者仅将框架包含在我的 Xcode 项目中就足够了吗?
由于目前我真的不知道您可能认为什么是“重要的”(我已经阅读了几篇文章和教程并尝试了不同的步骤),请随时提问 :)
更新#2
@Tomas:谢谢,ARC 部分是必不可少的。我的 ViewController 已经重命名为 .mm
。忘记关于“无法导入 opencv2/”的部分,因为我已经将它包含在我的 TestApp-Prefix.pch
中(如 Hello-tutorial 中所述)。
迎接下一个挑战;)
我注意到当我使用相机拍摄的图像时,roi
对象的边界计算不成功。我玩弄了设备方向并在我的 View 中放置了一个 UIImage
以查看图像处理步骤,但有时(即使图像正确对齐)值是负的,因为 if
- bounds.size()
-loop 中的 for
-condition 不是'没见过面。我遇到的最坏情况:minX/Y 和 maxX/Y 从未被触及。长话短说:以 Mat roi = inranged(cv::Rect(
开头的行抛出异常(断言失败,因为值为 < 0
)。我不知道轮廓的数量是否重要,但我假设是这样,因为图像越大,断言异常的可能性就越大。
老实说:我没有时间阅读 OpenCV 的文档并理解您的代码的作用,但截至目前,我认为没有解决的办法。对我来说不幸的是,我的初始任务(扫描收据、运行 OCR、在表格中显示项目)似乎比我想象的需要更多的资源(=时间)。
最佳答案
您从 iPad 本身拍摄照片的方式没有任何问题。但是您不能只是输入如此复杂的图像并期望 Tesseract 神奇地确定要提取的文本。仔细观察图像,您会发现它没有均匀的闪电,它非常嘈杂,因此它可能不是开始玩的最佳样本。
在这种情况下,必须对图像进行预处理,以便为 tesseract 库提供更易于识别的内容。
下面是一个非常简单的预处理示例,它使用了 OpenCV (http://www.opencv.org),一种流行的图像处理框架。它应该为您提供入门的想法。
#import <TesseractOCR/TesseractOCR.h>
#import <opencv2/opencv.hpp>
#import "UIImage+OpenCV.h"
using namespace cv;
...
// load source image
UIImage *img = [UIImage imageNamed:@"tesseract.jpg"];
Mat mat = [img CVMat];
Mat hsv;
// convert to HSV (better than RGB for this task)
cvtColor(mat, hsv, CV_RGB2HSV_FULL);
// blur is slightly to reduce noise impact
const int blurRadius = img.size.width / 250;
blur(hsv, hsv, cv::Size(blurRadius, blurRadius));
// in range = extract pixels within a specified range
// here we work only on the V channel extracting pixels with 0 < V < 120
Mat inranged;
inRange(hsv, cv::Scalar(0, 0, 0), cv::Scalar(255, 255, 120), inranged);
Mat inrangedforcontours;
inranged.copyTo(inrangedforcontours); // findContours alters src mat
// now find contours to find where characters are approximately located
vector<vector<cv::Point> > contours;
vector<Vec4i> hierarchy;
findContours(inrangedforcontours, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
int minX = INT_MAX;
int minY = INT_MAX;
int maxX = 0;
int maxY = 0;
// find all contours that match expected character size
for (size_t i = 0; i < contours.size(); i++)
{
cv::Rect brect = cv::boundingRect(contours[i]);
float ratio = (float)brect.height / brect.width;
if (brect.height > 250 && ratio > 1.2 && ratio < 2.0)
{
minX = MIN(minX, brect.x);
minY = MIN(minY, brect.y);
maxX = MAX(maxX, brect.x + brect.width);
maxY = MAX(maxY, brect.y + brect.height);
}
}
// Now we know where our characters are located
// extract relevant part of the image adding a margin that enlarges area
const int margin = img.size.width / 50;
Mat roi = inranged(cv::Rect(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin));
cvtColor(roi, roi, CV_GRAY2BGRA);
img = [UIImage imageWithCVMat:roi];
Tesseract *t = [[Tesseract alloc] initWithLanguage:@"eng"];
[t setVariableValue:@"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" forKey:@"tessedit_char_whitelist"];
[t setImage:img];
[t recognize];
NSString *recognizedText = [[t recognizedText] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([recognizedText isEqualToString:@"1234567890"])
NSLog(@"Yeah!");
else
NSLog(@"Epic fail...");
注意事项
关于iOS 超正方体 : bad results,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23626756/