【问题标题】:How to implement imbinarize in OpenCV如何在 OpenCV 中实现 imbinarize
【发布时间】:2017-03-02 09:33:23
【问题描述】:

我在 Matlab 中开发了脚本,用于分析颜色窃取上的雕刻文本。我正在使用一系列形态学技术来提取文本并使用 OCR 阅读。我需要在 Raspberry Pi 上实现它,因此我决定将我的 Matlab 代码传输到 OpenCV(在 python 中)。我尝试转移一些方法,它们的工作方式类似,但是如何将 imreconstruct 和 imbinarize(如下所示)实现到 OpenCV? (这里的挑战是适当区分前景和背景)。

也许我应该尝试添加grabCutgetStructuringElementmorphologyExdilate?我尝试了各种组合,但没有找到完美的解决方案。

如果有人可以就如何普遍改进 OCR 过程的提取和准确性提出建议,我将把整个脚本都放在上面,我将不胜感激。

基于灰度图像的 bin 值。我改变了一些参数 这些功能:

Matlab:

se = strel('disk', 300);
img = imtophat(img, se);
maker = imerode(img, strel('line',100,0)); %for whiter ones
maker = imerode(img, strel('line',85,0)); %for medium
maker = imerode(img, strel('line',5,0));

imgClear = imreconstruct(maker, img);

imgBlur = imgaussfilt(imgClear,1); %less blur for whiter frames

BW = imbinarize(imgBlur,'adaptive','ForegroundPolarity','Bright',...
    'Sensitivity',0.7);   %process for medium

BW = imbinarize(imgBlur, 'adaptive', 'ForegroundPolarity',...
        'Dark', 'Sensitivity', 0.4); % process for black and white

res = ocr(BW, 'CharacterSet', '0123456789', 'TextLayout', 'Block');
res.Text;

OpenCv

kernel = numpy.ones((5,5),numpy.uint8)

blur = cv2.GaussianBlur(img,(5,5),0)
erosion = cv2.erode(blur,kernel,iterations = 1)
opening = cv2.morphologyEx(erosion, cv2.MORPH_OPEN, kernel)

#bremove = cv2.grabCut(opening,mask,rect,bgdModelmode==GC_INIT_WITH_MASK)
#th3 = cv2.adaptiveThreshold(opening,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU,11,2)

ret, thresh= cv2.threshold(opening,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

ocr = pytesseract.image_to_string(Image.open('image2.png'),config='stdout -c tessedit_char_whitelist=0123456789')

这是输入图像:

【问题讨论】:

    标签: python matlab opencv ocr threshold


    【解决方案1】:

    当 matlab 和 opencv 似乎都使用相同的算法时,它们之间的差异之大让我感到惊讶。为什么你运行imbinarize 两次?敏感度关键字实际上做了什么(数学上,在背景后面)。因为他们显然比光秃秃的 OTSU 多了几个步骤。

    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    def show(img):
        plt.imshow(img, cmap="gray")
        plt.show()
    
    img = cv2.imread("letters.jpg", cv2.IMREAD_GRAYSCALE)
    
    kernel = np.ones((3,3), np.uint8)
    
    blur = cv2.GaussianBlur(img,(3,3), 0)
    erosion = cv2.erode(blur, kernel, iterations=3)
    opening = cv2.dilate(erosion, kernel)
    
    th3 = cv2.adaptiveThreshold(opening, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                cv2.THRESH_BINARY, 45, 2)
    show(th3)
    
    kernel2 = cv2.getGaussianKernel(6, 2) #np.ones((6,6))
    kernel2 = np.outer(kernel2, kernel2)
    th3 = cv2.dilate(th3, kernel2)
    th3 = cv2.erode(th3, kernel)
    show(th3)
    

    显示的图像是:

    稍作整理后:

    所以总的来说不一样,当然不如matlab好。但基本原理似乎是一样的,只是数字需要玩。

    更好的方法可能是通过图像的平均值做一个阈值,然后使用它的输出作为掩码来自适应阈值原始图像。希望结果会比 opencv 和 matlab 都好。

    尝试使用 ADAPTIVE_THRESH_MEAN_C 执行此操作,您可以获得一些非常好的结果,但周围有更多垃圾。同样,也许如果您可以将其用作掩码来隔离文本,然后再次进行阈值处理,结果可能会更好。腐蚀和膨胀内核的形状也会在这里产生很大的不同。

    【讨论】:

    • 我是 OpenCV 的初学者。感谢您对我在下面给出的答案的任何评论。
    • 我对不同色调的图像运行imbinarize 两次,一次用于较暗的图像用于较亮,这只是从上下文中获取的代码,我根据平均灰度值在两者之间进行决策过程。这就是我不知道sensitivity 做了什么,找不到它的方程式。我尝试了不同的自适应阈值方法,但正如你所说,它留下了更多 OCR 不喜欢的垃圾,它给出了误报。你如何改变侵蚀的形状,就像我在 MatLab 中的 squareline 一样。
    【解决方案2】:

    我根据您的雕刻文本示例编写了代码以获得肯定的结果。

    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    %matplotlib inline
    
    def show(img):
        plt.imshow(img, cmap="gray")
        plt.show()
    
    # load the input image
    img = cv2.imread('./imagesStackoverflow/engraved_text.jpg',0);
    show(img)
    
    ret, mask = cv2.threshold(img, 60, 120, cv2.THRESH_BINARY)  # turn 60, 120 for the best OCR results
    kernel = np.ones((5,3),np.uint8)
    mask = cv2.erode(mask,kernel,iterations = 1)
    show(mask)
    
    # I used a version of OpenCV with Tesseract, you may use your pytesseract and set the modes as:
    #   OCR Enginer Mode (OEM) = 3 (defualt = 3)
    #   Page Segmentation mode (PSmode) = 11 (defualt = 3)
    tesser = cv2.text.OCRTesseract_create('C:/Program Files/Tesseract 4.0.0/tessdata/','eng','0123456789',11,3)
    retval = tesser.run(mask, 0) # return string type
    
    print 'OCR:' + retval
    

    处理后的图像和 OCR 输出:

    如果您能用更多示例图像反馈您的测试结果,那就太好了。

    【讨论】:

    • 是的,这为我指明了正确的方向,我可以更好地控制我的二值化过程,但是当涉及到较轻的图像时,我仍然缺少一些东西。我需要以某种方式消除图像中的反射,这在 MatLab 中是通过imreconstruct 实现的
    • 我将继续试验您的实现并添加其他人的建议。
    • 此阈值适用于深色图像,但不适用于稍亮的图像。阈值的值在图像上总是有很大的差异。我在这里提供的样本的平均值是 110,但是当我给出 139 时,我需要将 thresh 降低到 40,这不好,因为我会有大量的 if 语句并且必须为每个值调整 thresh。我需要更智能的东西。在 Matlab 中,我为所有 255 个值提供了 3 个 binarization 技术。
    • @UZIERSKI 查看我在打火机上的新帖子。
    【解决方案3】:

    我从您的代码中可以看出,您首先在 Matlab 代码中使用了 tophat 过滤。但是,我在您的 python OpenCV 代码中看不到相同的内容。 Python 内置了 tophat 过滤器,尝试应用它以获得类似的结果

    kernel = np.ones((5,5),np.uint8) tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)

    另外,尝试使用 CLAHE,它可以为您的图像提供更好的对比度,然后应用黑帽过滤掉小细节。

    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) cl1 = clahe.apply(img) 通过应用这些转换,我得到了更好的结果。

    【讨论】:

    • 我也注意到了,现在我在我的代码中添加了TOPHAT,谢谢。对于clahe,我收到一个错误:error: /build/opencv-ISmtkH/opencv-2.4.9.1+dfsg/modules/imgproc/src/clahe.cpp:260: error: (-215) src.type() == CV_8UC1 in function apply
    【解决方案4】:

    在下面尝试,它可以识别较浅的雕刻文本样本。希望对您有所帮助。

    def show(img):
        plt.imshow(img, cmap="gray")
        plt.show()
    
    # load the input image
    img = cv2.imread('./imagesStackoverflow/engraved_text2.jpg',0);
    show(img)
    
    # apply CLAHE to adjust the contrast
    clahe = cv2.createCLAHE(clipLimit=5.1, tileGridSize=(5,3))
    cl1 = clahe.apply(img)
    img = cl1.copy()
    show(img)
    
    img = cv2.GaussianBlur(img,(3,3), 1)
    ret, mask = cv2.threshold(img, 125, 150, cv2.THRESH_BINARY)  # turn 125, 150 for the best OCR results
    
    kernel = np.ones((5,3),np.uint8)
    mask = cv2.erode(mask,kernel,iterations = 1)
    show(mask)
    
    # I used a version of OpenCV with Tesseract, you may use your pytesseract and set the modes as:
    #   Page Segmentation mode (PSmode) = 11 (defualt = 3)
    #   OCR Enginer Mode (OEM) = 3 (defualt = 3)
    tesser = cv2.text.OCRTesseract_create('C:/Program Files/Tesseract 4.0.0/tessdata/','eng','0123456789',11,3)
    retval = tesser.run(mask, 0) # return string type
    
    print 'OCR:' + retval
    

    【讨论】:

      猜你喜欢
      • 2021-11-16
      • 1970-01-01
      • 2014-07-02
      • 2015-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-23
      相关资源
      最近更新 更多