2013-02-22 86 views
2

我写了一个数字OCR为IOS。 我有两个数字5和4 我找到轮廓测试图像PNG文件。如何在tesseract上传输轮廓?的iOS +正方体OCR + OpenCV的

初始化的Tesseract:

tess = new tesseract::TessBaseAPI(); 
    tess->Init([dataPath cStringUsingEncoding:NSUTF8StringEncoding], "eng"); 
    tess->SetPageSegMode(tesseract::PSM_SINGLE_CHAR); //<-- !!!! 
    tess->tesseract::TessBaseAPI::SetVariable("tessedit_char_whitelist", ""); 

功能用于检测轮廓:

- (std::vector<std::vector<cv::Point> >)findSquaresInImage:(cv::Mat)_image { 
std::vector<std::vector<cv::Point> > squares; 
cv::Mat pyr, timg, gray0(_image.size(), CV_8U), gray; 
int thresh = 50, N = 11; 
cv::pyrDown(_image, pyr, cv::Size(_image.cols/2, _image.rows/2)); 
cv::pyrUp(pyr, timg, _image.size()); 
std::vector<std::vector<cv::Point> > contours; 
    int ch[] = {0, 0}; 
    mixChannels(&timg, 1, &gray0, 1, ch, 1); 
    for(int l = 0; l < N; l++) { 
     if(l == 0) { 
      cv::Canny(gray0, gray, 0, thresh, 5); 
      cv::dilate(gray, gray, cv::Mat(), cv::Point(-1,-1)); 
     } 
     else { 
      gray = gray0 >= (l+1)*255/N; 
     } 
     cv::findContours(gray, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); 
     std::vector<cv::Point> approx; 

     CvRect rec1; 
     std::string str; 
     std::map<int,IplImage*> pic_list; 

     for(size_t i = 0; i < contours.size(); i++) 
     { 

      rec1 = cv::boundingRect(contours[i]); 

      if (rec1.height > 0.5*gray.rows && rec1.width < 0.756*gray.cols) { 
       NSLog(@"%d %d %d %d", rec1.width, rec1.height, rec1.x, rec1.y); 
       cv::approxPolyDP(cv::Mat(contours[i]), approx, arcLength(cv::Mat(contours[i]), true)*0.02, true); 
       squares.push_back(approx); 
      } 
     } 
    } 

return squares; } 

对于平局轮廓功能:

- (IBAction)onMath:(id)sender { 
    UIImage *image = [UIImage imageNamed:@"test1.png"]; 

    cv::Mat iMat = [self cvMatFromUIImage:image]; 
    std::vector<std::vector<cv::Point> > sq = [self findSquaresInImage:iMat]; 
    cv::Mat hui = debugSquares(sq, iMat); 

    image = [self UIImageFromCVMat:hui]; 
    self.imView.image = image; 
} 
012:

cv::Mat debugSquares(std::vector<std::vector<cv::Point> > squares, cv::Mat image) { 
for (int i = 0; i< squares.size(); i++) { 
    // draw contour 
    cv::drawContours(image, squares, i, cv::Scalar(255,0,0), 1, 8, std::vector<cv::Vec4i>(), 0, cv::Point()); 

    // draw bounding rect 
    cv::Rect rect = boundingRect(cv::Mat(squares[i])); 
    cv::rectangle(image, rect.tl(), rect.br(), cv::Scalar(0,255,0), 2, 8, 0); 

    // draw rotated rect 
    cv::RotatedRect minRect = minAreaRect(cv::Mat(squares[i])); 
    cv::Point2f rect_points[4]; 
    minRect.points(rect_points); 
    for (int j = 0; j < 4; j++) { 
     cv::line(image, rect_points[j], rect_points[(j+1)%4], cv::Scalar(0,0,255), 1, 8); // blue 
    } 
} 

return image; 
} 

的BTN Click方法

图像后:

链接到项目在GitHub上:https://github.com/MaxPatsy/iORC

+0

您可以使用SetImage,然后使用SetRectangle和轮廓边界框;你知道如何给tesseract一个它可以读取的图像吗? – 2013-05-18 01:01:21

+0

你能更新你的问题吗?在Internet Archive上,github用户/项目被删除,没有任何痕迹。我能找到的最佳相关链接是http://www.cyberforum.ru/ios-dev/thread788840.html – 2017-06-15 05:31:22

回答

0

你可以检查这个答案here

我描述了一些技巧,这里准备图像为正方体:使用超正方体识别车牌

在你的榜样,有几件事情怎么回事...

你需要获取文本是黑色和白色图像(而不是相反)的其余部分。这就是字符识别所关注的。灰度是好的,只要背景大部分是全白的,文本大部分是全黑的;文本的边缘可能是灰色的(反锯齿),这可能有助于识别(但不一定 - 您必须尝试)

您看到的一个问题是,在图像的某些部分,文字是真正的“薄”(在字母的差距显示阈值处理后),而在其他地方真的很“厚”(和字母开始合并)。正方体不会喜欢:)这是因为输入图像不均匀的光线,所以单一的门槛不工作无处不在。解决方案是做“局部自适应阈值”,其中为图像的每个邻域计算不同的阈值。有这样做的方法很多,但检查出来,例如:

自适应高斯阈值在OpenCV中与cv2.adaptiveThreshold(...,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,...) 局部大津算法 本地自适应直方图均衡 你有另一个问题是线条不直。根据我的经验,Tesseract可以处理非直线的非常有限的程度(透视失真,倾斜或倾斜的几个百分比),但它不适用于波浪线。如果可以的话,确保源图像有直线:)不幸的是,现在没有简单的现成答案。您必须查看研究文献并自行实施最先进的算法之一(如果可能的话,开放源代码 - 真正需要开源解决方案)。一个谷歌学术搜索“曲线OCR提取”将让你开始,例如:弯曲的文档图像 最后的

文本行分割:我想你会做的更好使用Python生态系统的工作(ndimage,skimage )比在C++中的OpenCV。OpenCV python包装对于简单的东西是可以的,但是对于你想要做的事情他们不会做这项工作,你需要抓住很多不在OpenCV中的东西(当然你可以混合搭配)。在C++中执行类似曲线检测的操作将比Python中的要长一个数量级(*即使您不知道python,也是如此)。

祝你好运!