使用Python删除图像验证码中的行 [英] Line removal in image captcha using Python

查看:185
本文介绍了使用Python删除图像验证码中的行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我曾使用此链接 -

$ b来自PIL导入的
$ b

lineRemoval.py

 图片,ImageFilter 
来自scipy.misc导入toimage
来自运营商导入itemgetter
来自skimage导入措施
import numpy as np
import heapq
import cv2
import matplotlib.pyplot作为plt
来自scipy.ndimage.filters import median_filter



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

类预处理:
def pre_proc_image(self,img):
img_removed_noise = self.apply_median_fil ter(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)
返回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,如果x在范围内(max_color-15,max_color + 1),则为0,np.asarray(img_gray.getdata())))
img = np.reshape(row_img,[h,w] )
返回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
返回img_bw

def elimination_zeros(self,vector):
在枚举中返回[(dex,v)for(dex,v) rate(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 ]或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]]
返回p1,p2,line_length

def remove_line(self,p1, p2,LL,img):
m =(p2 [0] -p1 [0])/(p2 [1] -p1 [1])如果p2 [1]!= p1 [1]否则np.inf $ b $体重,H = LEN(IMG),乐n(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)
dex范围(h):
i,j = y [dex],x [dex]
i = int(i)
j = int(j)
rlist = []
而i> = 0且i< len(img_removed_line)-1:
f1 = i
如果img_removed_line [i] [j] == 0和img_removed_line [i-1] [j] == 0:
中断
rlist.append(i)
i = i-1
i,j = y [dex],x [dex]
i = int(i)
j = int(j)
而i> = 0且i< len(img_removed_line) -1:
f2 = i
如果img_removed_line [i] [j] == 0且img_removed_line [i + 1] [j] == 0:
中断
rlist。如果[LL + 1,LL,LL-1]中的np.abs(f2-f1):
rl,则追加(i)
i = i + 1
ist = list(set(rlist))
for r 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(输入,np.array(image))
cv2.imshow('输出',np.array(imgNew,dtype = np.uint8))
cv2.waitKey(0)

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





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



更新



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







在对这些图像进行阈值处理后,它们中还有一些线条





< a href =https://i.stack.imgur.com/TDiM2.png =nofollow noreferrer>



上网后我发现你可以在这些图像上使用侵蚀和扩张技术来移除这些线条但是我们这些技术中,pytesseract无法识别这些字符,因为我没有得到非常明确的输出。



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

解决方案

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



例如,以下行为您提供:





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



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




I had used this link - How to remove line from captcha completely and edited the code provided to remove lines from a dummy captcha that I have given below

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)

The code has no errors however the output image has none of the lines removed and looks somewhat like this:

I want the output to be completely free of any form of lines or at least reduce their intensity so that later it can be used with pytesseract to identify the letters mentioned in the captcha.

Update

There were few anomalies in the captcha data set where the lines had the same intensity such as given below


And after thresholding these images yet had some lines in them


After surfing the net I found that you can use techniques of erosion and dilation on these images to remove such lines however using these techniques, pytesseract is not able to recognize these characters since I do not get a very clear output.

Are there any other suggested techniques which can be applied for these sets of images so that later pytesseract can identify these characters ?

解决方案

In this special case it seems density of lines is less than characters density. so by applying some thresholding methods you can remove line:

For example the following line give you this:

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

later by applying some noise removal methods, like median (from your own code), you can get this result:

这篇关于使用Python删除图像验证码中的行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆