【问题标题】:OpenCV binary adaptive threshold OCROpenCV二进制自适应阈值OCR
【发布时间】:2014-04-24 05:13:59
【问题描述】:

我需要将一些图像转换为二进制用于 OCR。

以下是我正在使用的功能:

Mat binarize(Mat & Img, Mat& res, float blocksize, bool inverse)
{
    Img.convertTo(Img,CV_32FC1,1.0/255.0);
    CalcBlockMeanVariance(Img,res, blocksize, inverse);
    res=1.0-res;
    res=Img+res;
    if (inverse) {
        cv::threshold(res,res,0.85,1,cv::THRESH_BINARY_INV);
    } else {
        cv::threshold(res,res,0.85,1,cv::THRESH_BINARY);
    }
    cv::resize(res,res,cv::Size(res.cols/2,res.rows/2));
    
    return res;
}

在哪里CalcBlockMeanVariance

void CalcBlockMeanVariance(Mat& Img,Mat& Res,float blockSide, bool inverse) //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());
    
    if (inverse) {
        cv::threshold(Res,inpaintmask,0.02,1.0,cv::THRESH_BINARY_INV);
    } else {
        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);
    
}

当将1 传递给CalcBlockMeanVariance 作为blockSide 时,我得到了这个结果,我试图提高blockSide 但它只会导致更糟糕的结果。

之前:

之后:

谁能建议一种不同的方法来将此图像转换为二进制文件以准备 OCR?

谢谢。

【问题讨论】:

标签: c++ opencv binary-data adaptive-threshold


【解决方案1】:

我认为您可以使用Otsu 方法进行阈值处理。您可以将其应用于整个图像或图像块。我做了以下步骤:

  • 使用Otsu 方法对所需输入设置阈值。
  • Closing 结果。

Python 代码

image = cv2.imread('image4.png', cv2.IMREAD_GRAYSCALE) # reading image
if image is None:
    print 'Can not find the image!'
    exit(-1)
# thresholding image using ostu method
ret, thresh = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) 
# applying closing operation using ellipse kernel
N = 3
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (N, N))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# showing the result
cv2.imshow('thresh', thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

说明

在第一部分中,我使用imread 读取输入图像并检查图像是否正确打开!。

image = cv2.imread('image4.png', cv2.IMREAD_GRAYSCALE) # reading image
if image is None:
    print 'Can not find the image!'
    exit(-1)

现在使用otsu 方法对图像进行阈值处理,方法是通过将THRESH_BINARY_INV | THRESH_OTSU 作为参数提供thresh 方法。 otsu 方法基于一个优化问题来寻找阈值的最佳值。所以我通过给它一个下限0和一个上限255来提供阈值的可能值范围。

ret, thresh = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)

并使用Ellipse 内核完成关闭操作以去除图像中的黑洞。

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (N, N))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

结果

【讨论】:

  • 你能解释一下关闭吗?谢谢。
  • @Constantine 这有什么区别?cv2.THRESH_OTSU 而不是cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU
  • 您可以使用cv2.THRESH_BINARY 来代替它!您会看到前景以黑色显示,而背景以白色显示!如果您使用cv2.THRESH_BINARY_INV,它会使输出反转。使用不同的选项运行它,您将看到结果!这是最佳实践;)
猜你喜欢
  • 2014-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-03
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
  • 2012-01-09
相关资源
最近更新 更多