Deep Learning (7) - Image Verification Code Cracking (Number Addition and Subtraction Verification Code)

       During this period of internship and job hunting, I was very busy. Now that I have time, I still hope to share my recent work experience and completed project experience with everyone. It can also be regarded as a summary of myself. In the long career of learning, my position as an algorithm engineer is very important. I also hope that everyone will urge each other to develop good discipline habits. A project I want to share today is a project often used by crawlers in the company to crack verification codes. The blogger will have to crack a lot of verification codes. Students who like it can follow my blog. I will share everything I make. Now that the cracking of the two verification codes has been completed, let me first introduce to you the cracking of the digital addition and subtraction verification codes.

1. Data display:

             

2. Scenario and purpose

    In the era of big data, how to obtain the maximum data with the help of the Internet is a resource pursued by many TOB companies. Through this data we can obtain many effective intelligent recommendations.

However, during the process of crawling data online, verification codes will be entered, causing the interruption of crawling data and affecting the progress of the work. It would be expensive and laborious to hire a dedicated employee to enter the verification code. Therefore, a machine is required to automatically identify and crack the verification code that appears. For example, knowing the first picture, I can get 28. Automatically enter numbers (we will not explore this part) and complete the continuous crawling of data.

3. Algorithm analysis

   You may have some thoughts at the beginning like me, but you don’t know which one is more effective. For this situation, different application scenarios have different solutions. Our thoughts on this issue are as follows:

  1. Slicing + recognition: This method is the most commonly used method. Its advantage is that the algorithm foundation is complete. We only need to complete the slicing of the verification code, and then we can proceed to the next step of deep learning model training. But the disadvantage is that deep learning requires a lot of data, and we also need to label the cut data. This process requires a lot of managers. You probably know a lot about this method online, so I won’t introduce it here.

2. The method of CNN and CTC. This method has a scene where the previous method cannot do it, that is, it can recognize the entangled data. The CTC method comes from the idea in speech recognition. This method can perform a reasonable separation of entangled data and achieve good results. However, the disadvantage is that it is not suitable for the separation of large images, and its application is also limited. However, it has a good effect on long verification codes. In addition, a large number of annotations are required.

4. Algorithm of this paper

 The algorithm I shared today may sound very simple in theory, but the idea is not easy to think of. I used a method combined with traditional opencv. The idea behind this method is still combined with the analysis of data. We can see earlier that the form of the verification code is the same. Including information such as shape position size. This also showed that the technical content of a certain game was a bit low and gave me a way to take shortcuts.

   Data analysis, through its own binarization processing and grayscale reading method to analyze the data, it is found that the pixel positions and heights of the characters in the verification code are exactly the same. Therefore, I created a PKL file to save the characters at each position for retrieval and matching. This method does not require training, has high accuracy and fast results. But there is a drawback, the value can be applied to this scenario or equivalent scenarios.

5. Source code and analysis

#!/usr/bin/env python3
# coding=utf-8

"""    
    @File: Patent-Crack.py
    @Desc: 
    @Author: lv junling
    @Date Created: 2018/10/22
"""
import os
import pickle
import cv2
import numpy as np
from PIL import Image


class PatentCrack(object):
    def __init__(self, pkl_fn=None):
        if pkl_fn is None:
            print('[error]Must specify the pickle filename.')
            return
        self.pkl_fn = pkl_fn
        if os.path.exists(pkl_fn):
            self._load_pkl()
        else:
            self.gen_pkl_fn()

    def gen_pkl_fn(self):
        imgs_path = u'./data'      
        # 从下面这些数字截取第一个位置的数字
        chi_1_imgs = ['1.jpeg', '2.jpeg', '3.jpeg', '4.jpeg', '5.jpeg',
                      '6.jpeg', '7.jpeg', '8.jpeg', '9.jpeg']

        chi_2_imgs = ['10.jpeg', '11.jpeg', '12.jpeg', '13.jpeg', '14.jpeg', '15.jpeg',
                      '16.jpeg', '17.jpeg', '18.jpeg', '19.jpeg']
        # 截取第三个位置,也就是加减的矩阵数据
        op_imgs    = ['1.jpeg', '7.jpeg']

        chi_3_imgs = ['100.jpeg', '101.jpeg', '102.jpeg', '103.jpeg', '104.jpeg', '105.jpeg',
                      '106.jpeg', '107.jpeg', '108.jpeg', '109.jpeg']

        chi_1_arr = np.zeros([10, 20, 11], dtype=np.bool)
        # 把每个位置的字符保存成矩阵的形式
        for idx, img_fn in enumerate(chi_1_imgs):
            c1, _, _, _ = self._get_split_img(os.path.join(imgs_path, img_fn))
            chi_1_arr[idx+1] = c1

        chi_2_arr = np.zeros([10, 20, 9], dtype=np.bool)
        for idx, img_fn in enumerate(chi_2_imgs):
            _, c2, _, _ = self._get_split_img(os.path.join(imgs_path, img_fn))
            chi_2_arr[idx] = c2

        op_arr = np.zeros([3, 20, 12], dtype=np.bool)
        for idx, img_fn in enumerate(op_imgs):
            _, _, op, _ = self._get_split_img(os.path.join(imgs_path, img_fn))
            op_arr[idx] = op

        chi_3_arr = np.zeros([10, 20, 10], dtype=np.bool)
        for idx, img_fn in enumerate(chi_3_imgs):
            _, _, _, c3 = self._get_split_img(os.path.join(imgs_path, img_fn))
            chi_3_arr[idx] = c3
        # 把每个位置的矩阵和标签储存到pkl文件中
        fout = open(self.pkl_fn, 'wb')
        data = {'chi_1': chi_1_arr, 'chi_2': chi_2_arr, 'op': op_arr, 'chi_3': chi_3_arr}
        pickle.dump(data, fout)
        fout.close()

        self._load_pkl()

    def _load_pkl(self):
        data = pickle.load(open(self.pkl_fn, 'rb'))
        self.chi_1_arr = data['chi_1']
        self.op_arr = data['op']
        self.chi_2_arr = data['chi_2']
        self.chi_3_arr = data['chi_3']

    @staticmethod
    def _get_split_img(img_fn):
        img_arr = np.array(Image.open(img_fn).convert('L'))
        img_arr[img_arr < 156] = 1
        img_arr[img_arr >= 156] = 0
        img_arr = img_arr.astype(np.bool)
        chi_1_arr = img_arr[:,  6:17]
        chi_2_arr = img_arr[:, 19:28]
        op_arr    = img_arr[:, 32:44]
        chi_3_arr = img_arr[:, 45:55]
        return chi_1_arr, chi_2_arr, op_arr, chi_3_arr

    @staticmethod
    def _cal_result(num1, num2, num3,op):
        if op == 0:
            return num1*10 + num2 + num3
        elif op == 1:
            return num1*10 + num2 - num3
        elif op == 2:
            return num1 * num2
        else:
            return int(num1 / num2)
   # 获得结果的方法
    def feed(self, img_fn):
        chi_1_arr, chi_2_arr, op_arr, chi_3_arr = self._get_split_img(img_fn)
        chi_1_arr = np.tile(chi_1_arr[np.newaxis, :], [10, 1, 1])
        op_arr = np.tile(op_arr[np.newaxis, :], [3, 1, 1])
        chi_2_arr = np.tile(chi_2_arr[np.newaxis, :], [10, 1, 1])
        chi_1_sum = np.sum(
            np.sum(np.bitwise_and(chi_1_arr, self.chi_1_arr), axis=2), axis=1)
        chi_2_sum = np.sum(
            np.sum(np.bitwise_and(chi_2_arr, self.chi_2_arr), axis=2), axis=1)
        op_sum = np.sum(
            np.sum(np.bitwise_and(op_arr, self.op_arr), axis=2), axis=1)
        op_sum[1] += 1   # 区分减号和加号
        chi_3_sum = np.sum(
            np.sum(np.bitwise_and(chi_3_arr, self.chi_3_arr), axis=2), axis=1)
        num1 = chi_1_sum.argmax()
        num2 = chi_2_sum.argmax()
        op = op_sum.argmax()
        num3 = chi_3_sum.argmax()
        result = self._cal_result(num1, num2,num3, op)
        print (result)


def test():
    crack = PatentCrack('Patent.pkl')
    crack.feed(os.path.join('86-0.jpeg'))
    # fn_list = [fn for fn in os.listdir(u'../04_data/企业证书/cnca')]
    # fn_list.sort()
    # for fn in fn_list[:50]:
    #     crack.feed(os.path.join(u'../04_data/企业证书/cnca', fn))


if __name__=='__main__':
    test()

5. Summary

 The above is my analysis of theory and code. If you want to get a complete project, please download it from my github ( https://github.com/machine-lv/Verification-code-cracking )

Guess you like

Origin blog.csdn.net/qq_37100442/article/details/84024484