如何在OpenCV中实现imbinarize

时间:2017-03-02 09:33:24

标签: python matlab opencv ocr threshold

我在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')

这是输入图像:

enter image description here

Matlab outcome (result 573702)

OpenCV outcome (result 573102

Light colour image

Matlab process full detection rate

4 个答案:

答案 0 :(得分: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输出:

enter image description here

如果您能用更多的样本图像反馈您的测试结果,那就太棒了。

答案 1 :(得分: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)

显示的图像是:

First image, the immediate result of thresholding

经过一番清理后:

A bit more cleaned up and lean. Not really as nice as matlab output.

所有这一切都不一样,当然不如matlab好。但基本原则似乎是一样的,只是数字需要玩。

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

尝试使用ADAPTIVE_THRESH_MEAN_C,你可以得到一些非常好的结果,但周围有更多的垃圾。同样,也许如果你可以用它作为掩码来隔离文本然后再次进行阈值处理,那么它可能会变得更好。侵蚀和膨胀核的形状也会在这里产生很大的不同。

答案 2 :(得分:1)

我可以从您的代码中看到,您已经在Matlab代码中使用了tophat过滤作为第一步。但是,我在你的python OpenCV代码中看不到相同的东西。 Python内置了tophat过滤器尝试应用它来获得类似的结果

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

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

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

答案 3 :(得分:0)

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

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

enter image description here