使用 Python 在图像验证码中去除线条

rut*_*0_1 5 python opencv numpy image-processing

我使用过此链接 -如何从验证码中完全删除行并编辑提供的代码以从我在下面给出的虚拟验证码中删除行

虚拟验证码

行移除.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)
Run Code Online (Sandbox Code Playgroud)

代码没有错误,但是输出图像没有删除任何行,看起来有点像这样:

输出图像

我希望输出完全没有任何形式的线条,或者至少降低它们的强度,以便以后可以与 pytesseract 一起使用来识别验证码中提到的字母。

更新

验证码数据集中几乎没有异常,其中线条具有相同的强度,如下所示

图片1
图片2

在对这些图像进行阈值处理后,其中仍有一些线条

进程图像1
进程图像2

在网上冲浪后,我发现您可以对这些图像使用腐蚀和膨胀技术来删除这些线条,但是使用这些技术,pytesseract 无法识别这些字符,因为我没有得到非常清晰的输出。

是否有任何其他建议的技术可以应用于这些图像集,以便以后的 pytesseract 可以识别这些字符?

Sal*_*man 2

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

例如,下面的行给你这个:

在此输入图像描述

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

稍后通过应用一些噪声消除方法,例如中位数(来自您自己的代码),您可以获得以下结果:

在此输入图像描述