目标识别

2021/5/12 18:26:28

本文主要是介绍目标识别,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目标识别:(银行发票)

模型选择BOW+SVM

什么是BOW?

在最初的文本分类问题中Bag of word模型, 用特征矢量表示文档。基本思想:忽略文本的句词、语序等细节而将其作为一个词汇集合,文本中的词都是互相独立。

举个例子:将对于一个物体的部分描述放到一个文本中,如果文本中红色,圆的,表面光滑,甜等词汇出现的多,而黄色,表面粗糙,酸等词出现的少,就可判断这个文本是苹果而不是菠萝。

BOW应用在视觉领域的图像分类中,基本思想将图像特征看为一个特征集合,然后通过统计图像中特征出现的次数来对图像进行分类。本文利用BOW对图像进行分类。以下代码参考猫狗分类问题参考源码

代码中的K值。

任务简述:

现有以下5类数据集: CDHP:承兑汇票   DZD:对账单  Tax:税单 YHHD:银行回单: ZZS:增值税发票

文件夹中为对应的各类票据图片,现在需要对新输入的图片进行粗分类出对应的类别。

首先我们来预览下数据集都是什么样子:

 (为避免有不必要的麻烦,原图信息已进行打码处理)

再看下原图的详细信息:

开始楼主试着直接将原数据集(一张图200多kb)丢进训练模型中去跑,可能是文件太大,只尝试着跑了100张图都花了不少时间,所以继续想解决方案:

将原图进行压缩,当然得看下原图的长宽比,否则图片会变形严重,原图:2480X1164  宽高比2.14:1:压缩到500X500中为:500X233.

下面是压缩代码:

pic_resize.py

# -*- code:utf-8 -*-
'''图片处理,修改大小和名字'''

import os
from PIL import Image


pwd = os.getcwd()
file_list = os.listdir(pwd)
image_list = []

for file in file_list:
    if os.path.isfile(file):
        name, expand = os.path.splitext(file)
        if expand == '.jpg' or expand == '.png' or expand == 'jpeg':
            image_list.append(file)

if image_list:
    width = int(input("请输入图片尺寸的宽度,默认200:"))
    if width == 0:
        width == 200
    else:
        pass
    height = int(input("请输入图片尺寸的高度,默认200:"))
    if height == 0:
        height == 200
    else:
        pass

    imagePrefix = str(input("请输入需要生产图片的前缀名:"))
    if imagePrefix is None:
        imagePrefix = "1"
    else:
        pass


else:
    input("目录下没有图片,请按任意键退出!")
    exit()

# 处理图片
outDir = os.path.join(pwd, 'outImage')
if os.path.exists(outDir):
    os.remove(outDir)
os.mkdir(outDir)

for imageFile in image_list:
    ima = Image.open(os.path.join(pwd, imageFile))
    im_out = ima.resize((width, height), Image.NEAREST)
    outPath = os.path.join(outDir, imagePrefix + imageFile)
    im_out.save(outPath)

试着将压缩后的图放入BOW模型中训练,但是实际预测结果并不理想。

 重回到原图,大致分析了下YHHD数据集的图片特征,特征分布比较有规律,所以思路为对源数据集进行定位裁剪,裁剪出图中的

裁剪代码如下:

pic_cut.py(放在需要裁减图片的同级目录下)

import numpy as np
import cv2
import os


def update(input_img_path, output_img_path):
    image = cv2.imread(input_img_path)
    print(image.shape)
    cropped = image[70:200, 1600:1750]  # 裁剪坐标为[y0:y1, x0:x1]
    cv2.imwrite(output_img_path, cropped)


dataset_dir = r'D:\Python_Learning\opencv_target_track\train_path\YHHD\JSYH'#建设银行
output_dir = r'D:\Python_Learning\opencv_target_track\train_path\YHHD\out'

# 获得需要转化的图片路径并生成目标路径
image_filenames = [(os.path.join(dataset_dir, x), os.path.join(output_dir, x))
                   for x in os.listdir(dataset_dir)]
# 转化所有图片
for path in image_filenames:
    update(path[0], path[1])

裁剪后的,思路:通过裁剪后的"回单"图片集进行训练,判别图片中是否存在"回单"目标。

为了方便训练的迭代所以统一命名,写了以下重命名脚本:

rename.py

#coding=gbk
import os
import sys
def rename():
    path=input("请输入路径(例如D:\\\\picture):")
    name=input("请输入开头名:")
    startNumber=input("请输入开始数:")
    fileType=input("请输入后缀名(如 .jpg、.txt等等):")
    print("正在生成以"+name+startNumber+fileType+"迭代的文件名")
    count=0
    filelist=os.listdir(path)
    for files in filelist:
        Olddir=os.path.join(path,files)
        if os.path.isdir(Olddir):
            continue
        Newdir=os.path.join(path,name+str(count+int(startNumber))+fileType)
        os.rename(Olddir,Newdir)
        count+=1
    print("一共修改了"+str(count)+"个文件")
rename()

以下为目标检测BOW+SVM模型 :

classify.py

'''
词袋模型BOW+SVM 目标识别
'''
import numpy as np
import cv2
import os


class BOW(object):

    def __init__(self, ):
        # 创建一个SIFT对象  用于关键点提取
        self.feature_detector = cv2.xfeatures2d.SIFT_create()
        # 创建一个SIFT对象  用于关键点描述符提取
        self.descriptor_extractor = cv2.xfeatures2d.SIFT_create()

    def path(self, cls, i):
        '''
        用于获取图片的全路径
        '''
        # train_path/zzsfp/out/zzsfp.i.jpg
        return '%s\%s\out\%s.%d.jpg' % (self.train_path, cls, cls, i + 1)

    def fit(self, train_path, k):
        '''
        开始训练
        args:
            train_path:训练集图片路径  我们使用的数据格式为 train_path/zzsfp/zzsfp.i.jpg  train_path/cat/cat.i.jpg
            k:k-means参数k
        '''
        self.train_path = train_path

        # FLANN匹配  参数algorithm用来指定匹配所使用的算法,可以选择的有LinearIndex、KTreeIndex、KMeansIndex、CompositeIndex和AutotuneIndex,这里选择的是KTreeIndex(使用kd树实现最近邻搜索)
        flann_params = dict(algorithm=1, tree=5)
        flann = cv2.FlannBasedMatcher(flann_params, {})

        # 创建BOW训练器,指定k-means参数k   把处理好的特征数据全部合并,利用聚类把特征词分为若干类,此若干类的数目由自己设定,每一类相当于一个视觉词汇
        bow_kmeans_trainer = cv2.BOWKMeansTrainer(k)

        pos = 'YHHD'
        neg = 'ZZS'

        # 指定用于提取词汇字典的样本数
        length = 50
        # 合并特征数据  每个类从数据集中读取length张图片,通过聚类创建视觉词汇
        for i in range(length):
            bow_kmeans_trainer.add(self.sift_descriptor_extractor(self.path(pos, i)))
            bow_kmeans_trainer.add(self.sift_descriptor_extractor(self.path(neg, i)))

        # 进行k-means聚类,返回词汇字典 也就是聚类中心
        voc = bow_kmeans_trainer.cluster()

        # 输出词汇字典  <class 'numpy.ndarray'> (40, 128)
        print(type(voc), voc.shape)

        # 初始化bow提取器(设置词汇字典),用于提取每一张图像的BOW特征描述
        self.bow_img_descriptor_extractor = cv2.BOWImgDescriptorExtractor(self.descriptor_extractor, flann)
        self.bow_img_descriptor_extractor.setVocabulary(voc)

        # 创建两个数组,分别对应训练数据和标签,并用BOWImgDescriptorExtractor产生的描述符填充
        # 按照下面的方法生成相应的正负样本图片的标签 1:正匹配  -1:负匹配
        traindata, trainlabels = [], []
        for i in range(100):  # 这里取50张图像做训练
            traindata.extend(self.bow_descriptor_extractor(self.path(pos, i)))
            trainlabels.append(1)
            traindata.extend(self.bow_descriptor_extractor(self.path(neg, i)))
            trainlabels.append(-1)

        # 创建一个SVM对象
        self.svm = cv2.ml.SVM_create()
        # 使用训练数据和标签进行训练
        self.svm.train(np.array(traindata), cv2.ml.ROW_SAMPLE, np.array(trainlabels))

    def predict(self, img_path):
        '''
        进行预测样本
        '''
        # 提取图片的BOW特征描述
        data = self.bow_descriptor_extractor(img_path)
        res = self.svm.predict(data)
        print(img_path, '\t', res[1][0][0])

        # 如果是YHHD 返回True
        if res[1][0][0] == 1.0:
            return True
        # 如果是ZZSFP,返回False
        else:
            return False

    def sift_descriptor_extractor(self, img_path):
        '''
        特征提取:提取数据集中每幅图像的特征点,然后提取特征描述符,形成特征数据(如:SIFT或者SURF方法);
        '''
        im = cv2.imread(img_path, 0)
        # cv2.imshow('imshow', im)
        # cv2.waitKey(0)
        # cv2.destroyAllWindows()
        return self.descriptor_extractor.compute(im, self.feature_detector.detect(im))[1]

    def bow_descriptor_extractor(self, img_path):
        '''
        提取图像的BOW特征描述(即利用视觉词袋量化图像特征)
        '''
        im = cv2.imread(img_path, 0)
        # cv2.imshow('imshow', im)
        # cv2.waitKey(0)
        # cv2.destroyAllWindows()
        return self.bow_img_descriptor_extractor.compute(im, self.feature_detector.detect(im))

    # def set_gpus(gpu_index):
    #     if type(gpu_index) == list:
    #         gpu_index = ','.join(str(_) for _ in gpu_index)
    #     if type(gpu_index) == int:
    #         gpu_index = str(gpu_index)
    #     os.environ["CUDA_VISIBLE_DEVICES"] = gpu_index


if __name__ == '__main__':
    # 测试样本数量,测试结果
    test_samples = 20
    test_results = np.zeros(test_samples, dtype=np.bool)

    # 训练集图片路径    进行训练
    train_path = r'D:\Python_Learning\opencv_target_track\train_path'
    bow = BOW()
    bow.fit(train_path, 40)

    # 指定测试图像路径
    for index in range(test_samples):
        zzsfp = "data_test/{0}.jpg".format(index+1)
        test_img = cv2.imread(zzsfp)

        # 预测
        zzsfp_predict = bow.predict(zzsfp)
        test_results[index] = zzsfp_predict
        print(test_results[index])
        #
        font = cv2.FONT_HERSHEY_SIMPLEX
        if test_results[index]:
            cv2.putText(test_img, 'YHHD', (10, 30), font, 1, (0, 255, 0), 2, cv2.LINE_AA)
        else:
            cv2.putText(test_img, 'ZZS', (10, 30), font, 1, (0, 255, 0), 2, cv2.LINE_AA)

        cv2.imshow('test_img', test_img)

        cv2.waitKey(0)
        cv2.destroyAllWindows()

    # 计算准确率
    accuracy = np.mean(test_results.astype(dtype=np.float32))
    print('测试准确率为:', accuracy)

楼主进行了测试,对于以两个数据集进行训练的模型,来预测

这些测试的图片效果并不理想

        if test_results[index]:
            cv2.putText(test_img, 'YHHD', (10, 30), font, 1, (0, 255, 0), 2, cv2.LINE_AA)
        else:
            cv2.putText(test_img, 'ZZS', (10, 30), font, 1, (0, 255, 0), 2, cv2.LINE_AA)

所有图片都会被认为是ZZS,分析了代码并不是识别成ZZS,而是因为不是YHHD所以上述代码意思为不是YHHD的所有都是ZZS,YHHD并未识别。还得继续找别的方案。


 



这篇关于目标识别的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程