1. 程式人生 > >利用hog特徵訓練svm識別位置固定驗證碼

利用hog特徵訓練svm識別位置固定驗證碼

RT(純做記錄)

說要了解github但是還沒邁出艱難的第一步,主要是程式碼太水。今天整理了一下,並且用了sklearn模組的svm進行hog特徵提取來識別驗證碼,一個原因是上一篇部落格的svm訓練出來的模型,對於z的識別一直錯誤,一直識別成S。所以對特徵這塊來試試hog特徵,對於我的樣本集,效果非常好。 專門挑了一張帶Z的

訓練集

首先制定訓練集,上一篇部落格 中有說到,如何手工製作驗證碼訓練集,但是沒有圖,這裡詳細帶圖做下記錄。

第一步爬圖片

import itertools
import time
from os import walk
from os.path import splitext

import
requests header = { 'Host': 'xxxxxxxxxxxxxx', 'Referer': 'xxxxxxxxxxxxx', 'Connection': 'xxxxxxxxxx' } def max_file_name(): filenames_list = [int(splitext(i)[0]) for dirpath, dirnames, filenames in walk('CAPTCHA') for i in filenames] return max(filenames_list + [0, ]) def get_img
(filename): response = requests.get(f'xxxxxxxxx', headers=header) response.raise_for_status() with open(f'CAPTCHA/{filename}.gif', 'wb') as f: f.write(response.content) if __name__ == '__main__': filename = max_file_name()+1 for i in itertools.count(filename): get_img(
i) print(i-filename+1) time.sleep(5)

別問,問就上網查。還是不會就手動儲存。手動儲存的話,需要儲存的圖片必須包含所有字母數字。也就是0-9,A-Z都出現過。 假設完美情況就是9張圖就可以了。不完美就慢慢扣。

第二步轉換png

因為cv2不支援讀取gif,我就轉換了。

# 檔名:gif2png.py
from PIL import Image
from numpy import *
def iter_frames(im):
    try:
        i= 0
        while 1:
            im.seek(i)
            imframe = im.copy()
            if i == 0:
                palette = imframe.getpalette()
            else:
                imframe.putpalette(palette)
            yield imframe
            i += 1
    except EOFError:
        pass
def open_dir(dirpath, savepath):
    i = 0
    for root, dirs, filenames in os.walk(dirpath):
        for file in filenames:
            i += 1
            img = Image.open(dirpath+"/"+ file)
            for b, frame in enumerate(iter_frames(img)):
                frame.save(savepath + f'{i}.png')
if __name__ == '__main__':
	path = r"D:\project\tenssact\data\gif_path"
	save_path = r"D:\project\tenssact\data\ong_path/"
	open_dir(path,save_path)        

第三步二值化一下

檔名png2thre
import cv2 as cv
import os
import numpy as np
def custom_threshold(path):
    # path = r"D:\project\tenssact\svm\png_path"  + "/" + image
    image = cv.imread(path)
    gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)  #把輸入影象灰度化
    h, w =gray.shape[:2]
    m = np.reshape(gray, [1,w*h])
    mean = m.sum()/(w*h)
    print("mean:",mean)
    ret, binary =  cv.threshold(gray, 240, 255, cv.THRESH_BINARY)
    # cv.namedWindow("binary2", cv.WINDOW_NORMAL)
    # cv.imshow("binary2", binary)
    return binary
def png2thre(dirpath,savepath):
    i = 0
    for root,dirs,filenames in os.walk(dirpath):
        for file in filenames:
            path = dirpath + "/" + file
            # i += 1
            img = custom_threshold(path)
            cv.imwrite(savepath+ f'{i}.png',img)
if __name__ == '__main__':
	path = r"D:\project\tenssact\data\png_path/"
	save_path = r"D:\project\tenssact\data\thre_path/"
	open_dir(path,save_path)

第四步分割一下

from PIL import Image
from numpy import *
def cutImg(img):  #影象切割
    s = 5
    w = 11
    h = 16
    t = 3
    cut_img = []
    for i in range(4):
        pic = img.crop((s + w * i+i, t, s + w * (i + 1)+i, h))
        cut_img.append(pic)
    return cut_img

def split_img(dirpath, savepath):
    i = 0
    for root, dirs, filenames in os.walk(dirpath):
        for file in filenames:
            img = Image.open(dirpath+"/"+file)
            imgs = cutImg(img)
            for im in imgs:
                im.save(savepath+f'{i}.png')
                i += 1
path = r"D:\project\tenssact\data\thre_path"
savepath = r"D:\project\tenssact\data\test/"
split_img(path,savepath)

分割之後會出現一堆被分割的圖片,這時建立36個資料夾,然後命名為0-36,按照0-9,A-Z的順序,一張張圖塞到對應的資料夾裡。塞完了,訓練集建立成功了!!。

訓練

import cv2
from skimage import feature as ft
from sklearn import svm
import os
from sklearn.externals import joblib
feat = []
labels = []
for file in os.listdir(r"D:\project\tenssact\data\test/"):
    file_path = os.path.join(r"D:\project\tenssact\data\test/", file)
    label = file
    for _,dirs,filenames in os.walk(file_path):
        for file in filenames:
            img = cv2.imread(_+"/"+file)
            im = cv2.resize(img,(64,64))

            features = ft.hog(im,  # input image
                              block_norm = 'L1', #  block norm : str {‘L1’, ‘L1-sqrt’, ‘L2’, ‘L2-Hys’}, optional
                              transform_sqrt = True, # power law compression (also known as gamma correction)
                              feature_vector=True, # flatten the final vectors
                              visualise=False) #
            feat.append(features)
            labels.append(label)
clf = svm.SVC()
clf.fit(feat,labels)
joblib.dump(clf, "./model")

預測

from gif2png import *
from split_train_img import *
from skimage import feature as ft
from sklearn.externals import joblib

def swich_num(num):
    if num <= 9:
        out = int(num)
    else:
        for i in range(27):
            if num == 10+i:
                num = chr(65+i)
                out = num
    return (out)

path = r"D:\project\sklearn_svm\gif"
save_path = r"D:\project\sklearn_svm\png/"
save1_path = r"D:\project\sklearn_svm\thre/"
save2_path = r"D:\project\sklearn_svm\split/"
open_dir(path,save_path)
png2thre(save_path,save1_path)
split_img(save1_path,save2_path)
feat = []
for _,dirs,filenames in os.walk(save2_path):
    fet = []
    for file in filenames:
        img = cv2.imread(save2_path+file)
        im = cv2.resize(img,(64,64))
        features = ft.hog(im,  # input image
                          block_norm='L1',  # block norm : str {‘L1’, ‘L1-sqrt’, ‘L2’, ‘L2-Hys’}, optional
                          transform_sqrt=True,  # power law compression (also known as gamma correction)
                          feature_vector=True,  # flatten the final vectors
                          visualise=False)  #
        fet.append(features)
    feat.append(fet)

clf = joblib.load("./model")
final = []
for fet in feat:
    pred = clf.predict(fet)
    for num in pred:
        pred = swich_num(int(num))
        final.append(pred)
print (final)