OpenCV自适应阈值OCR

我正在使用OpenCV从iPhone摄像头为OCR准备图像,而我一直无法获得准确的OCR扫描所需的结果。 这里是我现在使用的代码。

cv::cvtColor(cvImage, cvImage, CV_BGR2GRAY); cv::medianBlur(cvImage, cvImage, 0); cv::adaptiveThreshold(cvImage, cvImage, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 5, 4); 

这种方法需要太长时间,并没有提供给我好的结果。 在这里输入图像说明在这里输入图像说明

关于如何使这个更有效的任何build议? 图像来自iPhone相机。

在使用Andry的build议之后。

在这里输入图像说明

  cv::Mat cvImage = [self cvMatFromUIImage:image]; cv::Mat res; cv::cvtColor(cvImage, cvImage, CV_RGB2GRAY); cvImage.convertTo(cvImage,CV_32FC1,1.0/255.0); CalcBlockMeanVariance(cvImage,res); res=1.0-res; res=cvImage+res; cv::threshold(res,res, 0.85, 1, cv::THRESH_BINARY); cv::resize(res, res, cv::Size(res.cols/2,res.rows/2)); image = [self UIImageFromCVMat:cvImage]; 

方法:

 void CalcBlockMeanVariance(cv::Mat Img,cv::Mat Res,float blockSide=21) // blockSide - the parameter (set greater for larger font on image) { cv::Mat I; Img.convertTo(I,CV_32FC1); Res=cv::Mat::zeros(Img.rows/blockSide,Img.cols/blockSide,CV_32FC1); cv::Mat inpaintmask; cv::Mat patch; cv::Mat smallImg; cv::Scalar m,s; for(int i=0;i<Img.rows-blockSide;i+=blockSide) { for (int j=0;j<Img.cols-blockSide;j+=blockSide) { patch=I(cv::Rect(j,i,blockSide,blockSide)); cv::meanStdDev(patch,m,s); if(s[0]>0.01) // Thresholding parameter (set smaller for lower contrast image) { Res.at<float>(i/blockSide,j/blockSide)=m[0]; }else { Res.at<float>(i/blockSide,j/blockSide)=0; } } } cv::resize(I,smallImg,Res.size()); cv::threshold(Res,inpaintmask,0.02,1.0,cv::THRESH_BINARY); cv::Mat inpainted; smallImg.convertTo(smallImg,CV_8UC1,255); inpaintmask.convertTo(inpaintmask,CV_8UC1); inpaint(smallImg, inpaintmask, inpainted, 5, cv::INPAINT_TELEA); cv::resize(inpainted,Res,Img.size()); Res.convertTo(Res,CV_32FC1,1.0/255.0); } 

任何想法,为什么我得到这个结果? OCR结果非常好,但是如果我能得到类似于您所得到的图像,效果会更好。 如果有问题,我正在为iOS开发。 我不得不使用cvtColor因为该方法需要一个单通道图像。

这是我的结果: 在这里输入图像说明

这里是代码:

 #include <iostream> #include <vector> #include <stdio.h> #include <stdarg.h> #include "opencv2/opencv.hpp" #include "fstream" #include "iostream" using namespace std; using namespace cv; //----------------------------------------------------------------------------------------------------- // //----------------------------------------------------------------------------------------------------- void CalcBlockMeanVariance(Mat& Img,Mat& Res,float blockSide=21) // blockSide - the parameter (set greater for larger font on image) { Mat I; Img.convertTo(I,CV_32FC1); Res=Mat::zeros(Img.rows/blockSide,Img.cols/blockSide,CV_32FC1); Mat inpaintmask; Mat patch; Mat smallImg; Scalar m,s; for(int i=0;i<Img.rows-blockSide;i+=blockSide) { for (int j=0;j<Img.cols-blockSide;j+=blockSide) { patch=I(Range(i,i+blockSide+1),Range(j,j+blockSide+1)); cv::meanStdDev(patch,m,s); if(s[0]>0.01) // Thresholding parameter (set smaller for lower contrast image) { Res.at<float>(i/blockSide,j/blockSide)=m[0]; }else { Res.at<float>(i/blockSide,j/blockSide)=0; } } } cv::resize(I,smallImg,Res.size()); cv::threshold(Res,inpaintmask,0.02,1.0,cv::THRESH_BINARY); Mat inpainted; smallImg.convertTo(smallImg,CV_8UC1,255); inpaintmask.convertTo(inpaintmask,CV_8UC1); inpaint(smallImg, inpaintmask, inpainted, 5, INPAINT_TELEA); cv::resize(inpainted,Res,Img.size()); Res.convertTo(Res,CV_32FC1,1.0/255.0); } //----------------------------------------------------------------------------------------------------- // //----------------------------------------------------------------------------------------------------- int main( int argc, char** argv ) { namedWindow("Img"); namedWindow("Edges"); //Mat Img=imread("D:\\ImagesForTest\\BookPage.JPG",0); Mat Img=imread("Test2.JPG",0); Mat res; Img.convertTo(Img,CV_32FC1,1.0/255.0); CalcBlockMeanVariance(Img,res); res=1.0-res; res=Img+res; imshow("Img",Img); cv::threshold(res,res,0.85,1,cv::THRESH_BINARY); cv::resize(res,res,cv::Size(res.cols/2,res.rows/2)); imwrite("result.jpg",res*255); imshow("Edges",res); waitKey(0); return 0; } 

JAVA代码 :这个问题已经过了很长一段时间,但是我已经把这个代码从C ++重写到Java,以防有人需要它(我需要用它来在android studio上开发一个应用程序)。

 public Bitmap Thresholding(Bitmap bitmap) { Mat imgMat = new Mat(); Utils.bitmapToMat(bitmap, imgMat); imgMat.convertTo(imgMat, CvType.CV_32FC1, 1.0 / 255.0); Mat res = CalcBlockMeanVariance(imgMat, 21); Core.subtract(new MatOfDouble(1.0), res, res); Imgproc.cvtColor( imgMat, imgMat, Imgproc.COLOR_BGRA2BGR); Core.add(imgMat, res, res); Imgproc.threshold(res, res, 0.85, 1, Imgproc.THRESH_BINARY); res.convertTo(res, CvType.CV_8UC1, 255.0); Utils.matToBitmap(res, bitmap); return bitmap; } public Mat CalcBlockMeanVariance (Mat Img, int blockSide) { Mat I = new Mat(); Mat ResMat; Mat inpaintmask = new Mat(); Mat patch; Mat smallImg = new Mat(); MatOfDouble mean = new MatOfDouble(); MatOfDouble stddev = new MatOfDouble(); Img.convertTo(I, CvType.CV_32FC1); ResMat = Mat.zeros(Img.rows() / blockSide, Img.cols() / blockSide, CvType.CV_32FC1); for (int i = 0; i < Img.rows() - blockSide; i += blockSide) { for (int j = 0; j < Img.cols() - blockSide; j += blockSide) { patch = new Mat(I,new Rect(j,i, blockSide, blockSide)); Core.meanStdDev(patch, mean, stddev); if (stddev.get(0,0)[0] > 0.01) ResMat.put(i / blockSide, j / blockSide, mean.get(0,0)[0]); else ResMat.put(i / blockSide, j / blockSide, 0); } } Imgproc.resize(I, smallImg, ResMat.size()); Imgproc.threshold(ResMat, inpaintmask, 0.02, 1.0, Imgproc.THRESH_BINARY); Mat inpainted = new Mat(); Imgproc.cvtColor(smallImg, smallImg, Imgproc.COLOR_RGBA2BGR); smallImg.convertTo(smallImg, CvType.CV_8UC1, 255.0); inpaintmask.convertTo(inpaintmask, CvType.CV_8UC1); Photo.inpaint(smallImg, inpaintmask, inpainted, 5, Photo.INPAINT_TELEA); Imgproc.resize(inpainted, ResMat, Img.size()); ResMat.convertTo(ResMat, CvType.CV_32FC1, 1.0 / 255.0); return ResMat; }