基于sklearn svm支持向量机识别数字

本文介绍了一种使用支持向量机(SVM)构建字符识别模型的方法。通过对图片进行分区并计算各区域的平均灰度值来降低图片的自由度,从而提高模型的准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      在上一篇中,已经探讨了如何找出图片中轮廓,并将图片根据轮廓进行裁剪,做二值化处理,归一化大小。通过这样的一系列流程,我们已经能够得到了大小统一的二值图图片,在此基础上,可以构建字符识别的训练集。

       在本文中,将探讨如何基于支持向量机构建识别模型。本文的主要流程是:将统一大小的图片(尺寸为32*50)进行分区,如将之分为80个区域,每个区域的尺寸为4*5,计算每个区域内的平均灰度值,最后每个训练图片都得到一个长度为80的一维数组,以此作为训练集。之所以这样做主要是考虑降低训练图片的自由度,若直接将图片转化为32*50=1600的一维数组,这样每张图片所包含的自由度太高,由于训练集数量有限,太高的自由度会降低模型识别的准确度。以下是基于该思路定义的方法。

from eight_step import modeling
import os
import numpy as np
from sklearn.svm import SVC
from sklearn.externals import joblib
from sklearn import preprocessing
import cv2

def convImage(image,width,height):
    '''将图片分区,计算每个区域的hsv值'''
    '''image:被截取的图片;width和height分别为截取后每个区域的宽和高'''
    images = [] #用于保存每一个区域的平均灰度
    mount = width * height #计算每个区域有多少像素
    '''分别获得图片的宽和高'''
    w = len(image[0])
    h = len(image)
    '''定义宽高方向上截取的次数'''
    wm = int(w / width)
    hm = int(h / height)
    print('wm = ',wm,',hm = ',hm)
    '''截取的顺序是一行一行截取,每一行都是从左到右截取,截取完该行就截取该行的下一行'''
    for i in range(0,hm):
        for j in range(0,wm):
            crop = image[i*height:(i+1)*height,j*width:(j+1)*width] #截图
            '''说明:crop = image[y1:y2,x1:x2],
            其中(x1,y1),(x2,y2)分别为截图矩形的左上点,右下点的坐标,'''
            array_crop = np.ravel(crop)  #转为一维数组
            cropMean = sum(array_crop) / mount  #求平均灰度
            images.append(cropMean)
    return images

        构建训练集的流程就是读取指定路径下的图片,通过以上方法得到每一张图片每个区域的平均灰度值组成的数组(作为x_train),再通过图片的文件获取标签(作为y_train),然后构建模型。代码如下。

def getLabel(filename):
    '''根据图片名称得到图片对应的标签,如标签名A_resizeB.jpg,记标签为A'''
    labelStr = filename.split('_')[0]
    return labelStr

def getDataAndLabels(dir,width,height):
    '''获取训练模型所需的数据和标签,dir为训练图片的路径,
    width和height分别为截取后每个区域的宽和高'''
    data = []  #用于保存每张图片各个区域平均灰度的标签
    labels = [] #用于保存每张图片所对应的标签
    for filename in os.listdir(dir):    #遍历指定路径下的所有图片
        bins = modeling.bins_image(dir, filename, 180) #转化为二值图
        image = convImage(bins,width,height) #将图片分割成若干区域,计算每个区域的平均灰度值
        data.append(image)
        label = getLabel(filename)  #得到标签
        labels.append(label)
    return data,labels

def createModel(data,labels):
    '''训练支持向量机模型,data为一个二维数组,每一个元素是一个数组,表示每一张图片的信息,
    label是一个一维数组,每一个元素是一张图片的标签'''
    clf = SVC(decision_function_shape='ovo')  # ovo为一对一
    clf.fit(data, labels) #训练模型
    return clf

综合以上步骤:

def train(dir,width,height):
    data,labels = getDataAndLabels(dir,width,height)
    data_scale = preprocessing.scale(data) #对训练数据进行归一化
    clf = createModel(data_scale,labels)
    joblib.dump(clf,MODEL)  #将训练好的模型持久化,clf为模型对象,MODEL为模型持久化的路径和名称
    return clf

           以上就是训练模型的过程。构建了模型之后,就可以利用模型进行预测了,代码如下:

           

def simpleRead(dir,filename,width,height,convWidth,convHeight):
    '''读取图片,转化为指定大小的图片,最终转为为二值图,划分区域'''
    '''dir为图片的路径,filename为图片名称,width和height分别为将图片归一化的宽和高,
    convWidth和convHeight分别是切割区域的宽和高'''
    bins = modeling.bins_image(dir,filename,130)  #图片二值化
    arr_bins, image = modeling.normalize_bins(bins,width,height) #统一尺寸
    #image_open = opening(image)
    cv2.imwrite(dir+'bins_'+filename,image)
    x_test = convImage(image,convWidth,convHeight) #切割图片,计算每一个区域的平均灰度值
    return x_test

def getXtest(dir,filenames,width,height,convWidth,convHeight):
    '''读取指定路径dir下的所有图片,构建测试集,filenames为测试集图片名称的列表'''
    x_list = []
    for i in range(0,len(filenames)):
        array = simpleRead(dir,filenames[i],width,height,convWidth,convHeight)
        x_list.append(array)
    x_test = preprocessing.scale(x_list) #将测试集归一化,若不归一化,每次测试都会得到一个结果
    return x_test

def predict(filenames,width,height,convWidth,convHeight):
    '''对测试图片进行预测'''
    x_test = getXtest(TEST_DIR,filenames,width,height,convWidth,convHeight)
    clf = joblib.load(MODEL) #加载模型,MODEL为模型的路径和名称
    result = clf.predict(x_test)
    print('预测结果:')
    print(result)
    print('正确结果:')
    showTure(filenames)

需要注意的是,在对图片继续预测时,一定要将测试图片进行标准化处理,否则总是会得到一个结果。sklearn的preprocessing.scale()方法就可以提供这样一个功能,这样操作的本质就是将数据按其属性(按列进行)减去其均值,然后除以其方差,使得所有数据都聚集在0,附近,方差为1(参见点击打开链接)。用代码说明如下。

def standard():
    '''标准化'''
    a = np.array([[2.,3.,4.,5.],
                  [5.,3.,6.,7.],
                  [2.,1.,9.,3.]])
    mean = a.mean(axis=0) #计算每一列的平均值
    print('mean = ',mean)
    std = a.std(axis=0)  #计算每一列的方差
    print('std = ',std)

    x1 = (a-mean)/std
    print('x1 = ',x1)
    x2 = preprocessing.scale(a)
    print('x2 = ',x2)
    print(x1 == x2)

显示的结果为:


由此可见,x1和x2的结果完全相等。




           

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值