使用Python去除图像验证码中的干扰线

6
我曾使用这个链接 - 如何完全去除验证码中的线条,并编辑提供的代码以从下面给出的虚拟验证码中删除线条。

Dummy Captcha

lineRemoval.py

from PIL import Image,ImageFilter
from scipy.misc import toimage
from operator import itemgetter
from skimage import measure
import numpy as np
import heapq
import cv2
import matplotlib.pyplot as plt
from scipy.ndimage.filters import median_filter



#----------------------------------------------------------------

class preprocessing:
    def pre_proc_image(self,img):
        img_removed_noise=self.apply_median_filter(img)
        #img_removed_noise=self.remove_noise(img)
        p1,p2,LL=self.get_line_position(img_removed_noise)
        img=self.remove_line(p1,p2,LL,img_removed_noise)
        img=median_filter(np.asarray(img),1)
        return img

    def remove_noise(self,img):
        img_gray=img.convert('L')
        w,h=img_gray.size
        max_color=np.asarray(img_gray).max()
        pix_access_img=img_gray.load()
        row_img=list(map(lambda x:255 if x in range(max_color-15,max_color+1) else 0,np.asarray(img_gray.getdata())))
        img=np.reshape(row_img,[h,w])
        return img

    def apply_median_filter(self,img):
        img_gray=img.convert('L')
        img_gray=cv2.medianBlur(np.asarray(img_gray),3)
        img_bw=(img_gray>np.mean(img_gray))*255
        return img_bw

    def eliminate_zeros(self,vector):
        return [(dex,v) for (dex,v) in enumerate(vector) if v!=0 ]

    def get_line_position(self,img):
        sumx=img.sum(axis=0)
        list_without_zeros=self.eliminate_zeros(sumx)
        min1,min2=heapq.nsmallest(2,list_without_zeros,key=itemgetter(1))
        l=[dex for [dex,val] in enumerate(sumx) if val==min1[1] or val==min2[1]]
        mindex=[l[0],l[len(l)-1]]
        cols=img[:,mindex[:]]
        col1=cols[:,0]
        col2=cols[:,1]
        col1_without_0=self.eliminate_zeros(col1)
        col2_without_0=self.eliminate_zeros(col2)
        line_length=len(col1_without_0)
        dex1=col1_without_0[round(len(col1_without_0)/2)][0]
        dex2=col2_without_0[round(len(col2_without_0)/2)][0]
        p1=[dex1,mindex[0]]
        p2=[dex2,mindex[1]]
        return p1,p2,line_length

    def remove_line(self,p1,p2,LL,img):
        m=(p2[0]-p1[0])/(p2[1]-p1[1]) if p2[1]!=p1[1] else np.inf
        w,h=len(img),len(img[0])
        x=list(range(h))
        y=list(map(lambda z : int(np.round(p1[0]+m*(z-p1[1]))),x))
        img_removed_line=list(img)
        for dex in range(h):
            i,j=y[dex],x[dex]
            i=int(i)
            j=int(j)
            rlist=[]
            while i>=0 and i<len(img_removed_line)-1:
                f1=i
                if img_removed_line[i][j]==0 and img_removed_line[i-1][j]==0:
                    break
                rlist.append(i)
                i=i-1
            i,j=y[dex],x[dex]
            i=int(i)
            j=int(j)
            while i>=0 and i<len(img_removed_line)-1:
                f2=i
                if img_removed_line[i][j]==0 and img_removed_line[i+1][j]==0:
                    break
                rlist.append(i)
                i=i+1
            if np.abs(f2-f1) in [LL+1,LL,LL-1]:
                rlist=list(set(rlist))
                for k in rlist:
                    img_removed_line[k][j]=0

        return img_removed_line

if __name__ == '__main__':
    image = cv2.imread("captcha.png")
    img = Image.fromarray(image)
    p = preprocessing()
    imgNew = p.pre_proc_image(img)
    cv2.imshow("Input", np.array(image))
    cv2.imshow('Output', np.array(imgNew, dtype=np.uint8))
    cv2.waitKey(0)

代码没有错误,但输出的图像没有任何线条被删除,看起来有点像这样:

Output Image

我希望输出完全没有任何形式的线条,或者至少减少它们的强度,以便稍后可以与pytesseract一起使用来识别验证码中提到的字母。
更新
在验证码数据集中有一些异常情况,其中线条具有相同的强度,例如下面所示。

Image1
Image2

在对这些图像进行阈值处理后,它们仍然存在一些线条。

ProcImage1
ProcImage2

在浏览网络后,我发现可以使用腐蚀和膨胀技术来消除这些图像中的线条,但是使用这些技术,pytesseract 无法识别这些字符,因为输出不够清晰。是否有其他建议的技术可应用于这些图像集,以便稍后 pytesseract 可以识别这些字符?
1个回答

2
在这种特殊情况下,线的密度似乎小于字符的密度。因此,通过应用一些阈值方法,您可以删除线条:
例如,以下行会给您这个:

enter image description here

retval,image = cv2.threshold(image, 12, 255, cv2.THRESH_BINARY)

稍后通过应用一些噪声去除方法,如中值滤波(从您自己的代码中),您可以获得这个结果:

enter image description here


一行代码解决了我之前想要做的一切,但是我并不明白在此之前我做错了什么。 - rut_0_1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接