文章目录

  • 第八章 图像内容分类
    • (一)K邻近分类法(KNN)
    • (二)贝叶斯分类器
    • (三)支持向量机
    • (四)光学字符识别

第八章 图像内容分类

本章介绍图像分类和图像内容分类算法。

先介绍一些简单而有效的方法和一些性能最好的分类器,运用它们解决两类和多类分类问题,再展示两个用于手势识别和目标识别的应用实例。

(一)K邻近分类法(KNN)

在分类方法中,最简单且用的最多的一种方法之一是KNN。

这种方法把要分类的对象(例如一个特征向量)与训练集中已知类标记的所有对象进行对比,并由k近邻对指派到哪个类进行投票。

缺点:需要预先设定k值,k值得选择会影响分类得性能;这种方法要求将整个训练集存储起来,如果训练集非常大,搜索起来就非常慢;可并行性一般

优点:这种方法在采用何种距离度量方面没有限制

实现最基本的KNN形式:给定训练样本集和对应的标记列表,这些训练样本和标记可以在一个数组里成行摆放或者干脆摆放到列表里,训练样本可能是数字、字符串等任何形状。将定义的对象添加到名为knn.py的文件里。(此处采用的是欧氏距离进行度量)

一个简单的二维示例

首先建立一些简单的二维示例数据集来说明并可视化分类器的工作原理。

下面的脚本将创建两个不同的二维点集,每个点集有两类,用Pickle模块来保存创建的数据。我们需要四个二维数据集文件,每个分布都有两个文件,一个用来训练,另一个用来做测试。

如图中所示:

先用Pickle模块创建一个KNN分类器模型,再载入另一个数据集(测试数据集),并在控制台上打印第一个数据点估计出来的类标记。为了可视化所有测试数据点的分类,并展示分类器将两个不同的类分开的怎么样,可以创建一个简短的辅助函数以获取x和y二维坐标数组和分类器,并返回一个预测的类标记数组。

绘制出的结果如下图所示:

可以看到,KNN决策边界适用于没有任何明确模型的类分布

代码为:

# -*- coding: utf-8 -*-
from numpy.random import randn
import pickle
from pylab import *# create sample data of 2D points
n = 200
# two normal distributions
class_1 = 0.6 * randn(n,2)
class_2 = 1.2 * randn(n,2) + array([5,1])
labels = hstack((ones(n),-ones(n)))
# save with Pickle
#with open('points_normal.pkl', 'w') as f:
with open('points_normal.pkl', 'wb') as f:pickle.dump(class_1,f)pickle.dump(class_2,f)pickle.dump(labels,f)
# normal distribution and ring around it
class_1 = 0.6 * randn(n,2)
r = 0.8 * randn(n,1) + 5
angle = 2*pi * randn(n,1)
class_2 = hstack((r*cos(angle),r*sin(angle)))
labels = hstack((ones(n),-ones(n)))
# save with Pickle
#with open('points_ring.pkl', 'w') as f:
with open('points_ring.pkl', 'wb') as f:pickle.dump(class_1,f)pickle.dump(class_2,f)pickle.dump(labels,f)
# -*- coding: utf-8 -*-
import pickle
from pylab import *
import knn
import imtoolspklist=['points_normal.pkl','points_ring.pkl']figure()# load 2D points using Pickle
for i, pklfile in enumerate(pklist):with open(pklfile, 'rb') as f:class_1 = pickle.load(f)class_2 = pickle.load(f)labels = pickle.load(f)# load test data using Picklewith open(pklfile[:-4]+'_test.pkl', 'rb') as f:class_1 = pickle.load(f)class_2 = pickle.load(f)labels = pickle.load(f)model = knn.KnnClassifier(labels,vstack((class_1,class_2)))# test on the first pointprint(model.classify(class_1[0]))#define function for plottingdef classify(x,y,model=model):return array([model.classify([xx,yy]) for (xx,yy) in zip(x,y)])# lot the classification boundarysubplot(1,2,i+1)imtools.plot_2D_boundary([-6,6,-6,6],[class_1,class_2],classify,[1,-1])titlename=pklfile[:-4]title(titlename)
show()

用稠密SIFT作为图像特征

上一节是对点进行分类,这一节学习如何对图像进行分类。

要对图像进行分类,需要一个特征向量来表示一幅图像,这节学的是稠密SIFT特征向量。

创建名为dsift.py文件,将帧数组存储在一个文本文件中。例如用下面的代码来计算稠密SIFT描述子,并可视化它们的位置:

# -*- coding: utf-8 -*-
import sift, dsift
from pylab import  *
from PIL import Imagedsift.process_image_dsift('empire.jpg','empire.dsift',90,40,True)
l,d = sift.read_features_from_file('empire.dsift')
im = array(Image.open('empire.jpg'))
sift.plot_features(im,l,True)
title('dense SIFT')
show()

得到的结果为:

图像分类:手势识别

在此应用中,我们使用稠密SIFT描述子来表示这些收拾图像,并建立一个简单的手势识别系统。

我们使用静态手势数据库中的一些图像进行演示。

如下图所示:

代码为:

# -*- coding: utf-8 -*-
import os
import sift, dsift
from pylab import  *
from PIL import Imageimlist=['train/A-uniform01.ppm','train/B-uniform01.ppm','train/C-uniform02.ppm','train/Five-uniform01.ppm','train/Point-uniform01.ppm','train/V-uniform01.ppm']figure()
for i, im in enumerate(imlist):dsift.process_image_dsift(im,im[:-3]+'dsift',30,15,True)l,d = sift.read_features_from_file(im[:-3]+'dsift')dirpath, filename=os.path.split(im)im = array(Image.open(im))#显示手势含义titletitlename=filename[:-14]subplot(2,3,i+1)sift.plot_features(im,l,True)title(titlename)
show()

得到的准确率和混淆矩阵为:

说明该例中有81%的图像是正确的,混淆矩阵可以显示每类有多少个样本被分在每一类中的矩阵,它可以显示错误的分布情况,以及哪些类是经常“混淆”的。

代码为:

#得到每幅图的稠密sift特征
import dsift
# 将图像尺寸调为 (50,50),然后进行处理
for filename in imlist:featfile = filename[:-3]+'dsift'dsift.process_image_dsift(filename,featfile,10,5,resize=(50,50))
#辅助函数,用于从文件中读取稠密SIFT描述子
import os
import sift
def read_gesture_features_labels(path):# create list of all files ending in .dsiftfeatlist = [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.dsift')]# read the featuresfeatures = []for featfile in featlist:l,d = sift.read_features_from_file(featfile)features.append(d.flatten())features = array(features)# create labelslabels = [featfile.split('/')[-1][0] for featfile in featlist]return features,array(labels)
#读取训练集、测试集的特征和标记信息
features,labels = read_gesture_features_labels('gesture/train/')
test_features,test_labels = read_gesture_features_labels('gesture/test/')
classnames = unique(labels)
#使用过前面的K近邻代码
# test kNN
import knn
k = 1
knn_classifier = knn.KnnClassifier(labels,features)
res = array([knn_classifier.classify(test_features[i],k) for i in range(len(test_labels))])
# accuracy
acc = sum(1.0*(res==test_labels)) / len(test_labels)
print('Accuracy:', acc)
#打印标记及相应的混淆矩阵
def print_confusion(res,labels,classnames):n = len(classnames)# confusion matrixclass_ind = dict([(classnames[i],i) for i in range(n)])confuse = zeros((n,n))for i in range(len(test_labels)):confuse[class_ind[res[i]],class_ind[test_labels[i]]] += 1print('Confusion matrix for')print(classnames)print(confuse)
print_confusion(res,test_labels,classnames)

(二)贝叶斯分类器

另一个简单而有效的分类器是贝叶斯分类器(或称朴素贝叶斯分类器),它是一种基于贝叶斯条件概率定理的概率分类器,它假设特征是彼此独立不相关的。一旦学习了这个模型,就没有必要存储训练数据,只需存储模型的参数。

原理:该分类器是通过将各个特征的条件概率相乘得到一个类的总概率,然后选取概率最高的那个类构造出来的。

实例:创建名为bayes.py的文件,添加Classifier类。该模型每一类都有两个变量,类均值和协方差。将该贝叶斯分类器用于上一节的二维数据,下面的脚本载入上一节的二维数据,并训练出一个分类器:

import pickle
import bayes
import imtools
# 用 Pickle 模块载入二维样本点
with open('points_normal.pkl', 'rb') as f:class_1 = pickle.load(f)class_2 = pickle.load(f)labels = pickle.load(f)
# 训练贝叶斯分类器
bc = bayes.BayesClassifier()
bc.train([class_1,class_2],[1,-1])

载入上一节中的二维测试数据对分类器进行测试:

import pickle
import bayes
import imtools
# 用 Pickle 模块载入二维样本点
with open('points_normal.pkl', 'rb') as f:class_1 = pickle.load(f)class_2 = pickle.load(f)labels = pickle.load(f)
# 训练贝叶斯分类器
bc = bayes.BayesClassifier()
bc.train([class_1,class_2],[1,-1])

该脚本将前10个二维数据点的分类结果打印输出到控制台,结果为:

两个数据集的分类结果如下图所示:

该例中,决策边界是一个椭圆,类似于二维高斯函数的等值线。

接下来尝试手势识别问题。由于稠密SIFT描述子的特征向量十分庞大,所以在数据拟合模型之前需要进行降维处理,此时,采用PCA(主成分分析)来降维。创建名为pca.py的文件。

在本例中,我们在训练数据上用PCA降维,并保持在这50维具有最大的方差。

#辅助函数,用于从文件中读取稠密SIFT描述子
import os
import sift
from numpy import *
def read_gesture_features_labels(path):# create list of all files ending in .dsiftfeatlist = [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.dsift')]# read the featuresfeatures = []for featfile in featlist:l,d = sift.read_features_from_file(featfile)features.append(d.flatten())features = array(features)# create labelslabels = [featfile.split('/')[-1][0] for featfile in featlist]return features,array(labels)
#读取训练集、测试集的特征和标记信息
features,labels = read_gesture_features_labels('gesture/train/')
test_features,test_labels = read_gesture_features_labels('gesture/test/')
classnames = unique(labels)
# PCA降维
import pca
V,S,m = pca.pca(features)
# 保持最重要的成分
V = V[:50]
features = array([dot(V,f-m) for f in features])
test_features = array([dot(V,f-m) for f in test_features])

训练并测试贝叶斯分类器如下:

import bayes
# 测试贝叶斯分类器
bc = bayes.BayesClassifier()
blist = [features[where(labels==c)[0]] for c in classnames]
bc.train(blist,classnames)
res = bc.classify(test_features)[0]

检查分类准确率:

import knn
k = 1
knn_classifier = knn.KnnClassifier(labels,features)
res = array([knn_classifier.classify(test_features[i],k) for i in range(len(test_labels))])
acc = sum(1.0*(res==test_labels)) / len(test_labels)
print('Accuracy:', acc)

输出为:

检查混淆矩阵:

#打印标记及相应的混淆矩阵
def print_confusion(res,labels,classnames):n = len(classnames)# confusion matrixclass_ind = dict([(classnames[i],i) for i in range(n)])confuse = zeros((n,n))for i in range(len(test_labels)):confuse[class_ind[res[i]],class_ind[test_labels[i]]] += 1print('Confusion matrix for')print(classnames)print(confuse)
print_confusion(res,test_labels,classnames)

输出结果为:

虽然分类效果不如K近邻分类器,但贝叶斯分类器不需要保存任何训练数据,而且只需保存每个类的模型参数。

(三)支持向量机

支持向量机(SVM)是一类强大的分类器,可以在很多分类问题中给出现有水准很高的分类结果。

方法:最简单的SVM通过在高维空间中寻找一个最优线性分类面,尽可能地将两类数据分开。

对于一特征向量x的决策函数为:
f(x)=w⋅x−bf(x)=w·x-b f(x)=w⋅x−b
其中w是常规的超平面,b是偏移量常数。

可以写成:
f(x)=∑iαiyixi⋅x−bf(x)=\sum_{i} \alpha_{i} y_{i} \boldsymbol{x}_{i} \cdot \boldsymbol{x}-b f(x)=i∑​αi​yi​xi​⋅x−b
这里的i是从训练集中选出的部分样本,这里选择的样本称为支持向量,因为它们
可以帮助定义分类的边界

优点:可以使用核函数。核函数能够将特征向量映射到另外一个不同维度的空间中,比如高维度空间。通过核函数映射,依然可以保持对决策函数的控制,从而可以有效地解决非线性或者很难的分类问题。

最常见的核函数:
线性是最简单的情况,即在特征空间中的超平面是线性的,K(xi,x)=xi⋅xK\left(\boldsymbol{x}_{i}, \boldsymbol{x}\right)=\boldsymbol{x}_{i} \cdot \boldsymbol{x}K(xi​,x)=xi​⋅x;
多项式用次数为 d 的多项式对特征进行映射,K(xi,x)=(γxi⋅x+r)d,γ>0K\left(\boldsymbol{x}_{i}, \boldsymbol{x}\right)=\left(\gamma \boldsymbol{x}_{i} \cdot \boldsymbol{x}+r\right)^{d}, \quad \gamma>0K(xi​,x)=(γxi​⋅x+r)d,γ>0;
径向基函数,通常指数函数是一种极其有效的选择,K(xi,x)=e(−γ∣∣xi−x∥2),γ>0K\left(\boldsymbol{x}_{i}, \boldsymbol{x}\right)=\mathrm{e}^{\left(-\gamma|| \boldsymbol{x}_{i}-x \|^{2}\right)}, \quad \gamma>0K(xi​,x)=e(−γ∣∣xi​−x∥2),γ>0
Sigmoid 函数,一个更光滑的超平面替代方案,K(xi,x)=tanh⁡(γxi⋅x+r)K\left(\boldsymbol{x}_{i}, \boldsymbol{x}\right)=\tanh \left(\gamma \boldsymbol{x}_{i} \cdot \boldsymbol{x}+r\right)K(xi​,x)=tanh(γxi​⋅x+r)。

每个核函数的参数都是在训练阶段确定的

使用LibSVM
LibSVM下载地址:http://www.csie.ntu.edu.tw/~cjlin/libsvm/index.html#download
LibSVM载入在前面KNN范例分类中用到的数据点,并用径向基函数训练一个SVM分类器:

import pickle
from svmutil import *
import imtools
# 用 Pickle 载入二维样本点
with open('points_ring.pkl', 'rb') as f:class_1 = pickle.load(f)class_2 = pickle.load(f)labels = pickle.load(f)
# 转换成列表,便于使用 libSVM
class_1 = list(map(list,class_1))
class_2 = list(map(list,class_2))
labels = list(labels)
samples = class_1+class_2 # 连接两个列表
# 创建 SVM
prob = svm_problem(labels,samples)
param = svm_parameter('-t 2')
# 在数据上训练 SVM
m = svm_train(prob,param)
# 在训练数据上分类效果如何?
res = svm_predict(labels,samples,m)

打印输出结果如下:

现在,载入其他数据集,并对该分类器进行测试:

# 用 Pickle 模块载入测试数据
with open('points_normal_test.pkl', 'r') as f:class_1 = pickle.load(f)class_2 = pickle.load(f)labels = pickle.load(f)
# 转换成列表,便于使用 LibSVM
class_1 = map(list,class_1)
class_2 = map(list,class_2)
# 定义绘图函数
def predict(x,y,model=m):return array(svm_predict([0]*len(x),zip(x,y),model)[0])
# 绘制分类边界
imtools.plot_2D_boundary([-6,6,-6,6],[array(class_1),array(class_2)],predict,[-1,1])
show()

(四)光学字符识别

光学字符识别(OCR)是一个多类问题实例,是一个理解手写或机写文本图像的处理过程。常见的例子是通过扫描文件来提取文本。本节主要理解数度图像。

流程:我们假设数独图像是已经对齐的,其水平和垂直网格线平行于图像的边,在这些条件下,可以对图像进行阈值处理,并在水平和垂直方向上分别对像素值求和由于这些经阈值处理的边界值为 1,而其他部分值为 0,所以这些边界处会给出很强的响应,可以告诉我们从何处进行裁剪。

# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
from scipy.ndimage import measurementsdef find_sudoku_edges(im, axis=0):""" 寻找对齐后数独图像的的单元边线 """# threshold and sum rows and columns#阈值化,像素值小于128的阈值处理后为1,大于128的为0trim = 1*(128 > im)#阈值处理后对行(列)相加求和s = trim.sum(axis=axis)
#     print(s)# find center of strongest lines# 寻找连通区域s_labels, s_nbr = measurements.label((0.5*max(s)) < s)
#     print(s_labels)
#     print(s_nbr)#计算各连通域的质心m = measurements.center_of_mass(s, s_labels, range(1, s_nbr+1))
#     print(m)#对质心取整,质心即为粗线条所在位置x = [int(x[0]) for x in m]
#     print(x)# if only the strong lines are detected add lines in between# 如果检测到了粗线条,便在粗线条间添加直线if 4 == len(x):dx = diff(x)x = [x[0], x[0]+dx[0]/3, x[0]+2*dx[0]/3, x[1], x[1]+dx[1]/3, x[1]+2*dx[1]/3, x[2], x[2]+dx[2]/3, x[2]+2*dx[2]/3, x[3]]if 10 == len(x):return xelse:raise RuntimeError('Edges not detected.')

接下来输入原图:

imname = '2.png'
im = array(Image.open(imname).convert('L'))
print(im.shape)
figure()
gray()
imshow(im)
axis('off')

得到单元边界线,并进行绘制输出

# find the cell edges
# 寻找x方向的单元边线
x = find_sudoku_edges(im, axis=0)
#寻找y方向的单元边线
y = find_sudoku_edges(im, axis=1)figure()
gray()y1=[y[0],y[3],y[6],y[-1]]
y2=[y[1],y[2],y[4],y[5],y[7],y[8]]#画直线
for i, ch in enumerate(y1):x1 = range(x[0], x[-1]+1, 1)y1 = ch*ones(len(x1))#画散点图plot(x1, y1, 'r', linewidth=2)for i, ch in enumerate(y2):x1 = range(x[0], x[-1]+1, 1)y1 = ch*ones(len(x1))#画散点图plot(x1, y1, 'b', linewidth=2)'''for i, ch in enumerate(x):y1 = range(x[0], x[-1]+1, 1)x1 = ch*ones(len(x1))#画散点图plot(x1, y1, 'r', linewidth=2)plot(x, y, 'or', linewidth=2)'''imshow(im)
axis('off')
show()

得到的结果为:

Python计算机视觉——图像内容分类相关推荐

  1. python计算机视觉学习第8章——图像内容分类

    目录 引言 一. K邻近分类算法(KNN) 1.1 简单二维示例 1.2 用稠密SIFT作为图像特征 1.3 图像分类:手势识别 二 .贝叶斯分类器 三.支持向量机 3.1 使用LibSVM 四. 光 ...

  2. 计算机视觉编程——图像内容分类

    文章目录 图像内容分类 1 K近邻分类法(KNN) 1.1 一个简单的二维示例 1.2 用稠密SIFT作为图像特征 1.3 图像分类:手势识别 2 贝叶斯分类器 3 支持向量机 图像内容分类 1 K近 ...

  3. Python计算机视觉——图像到图像的映射

    Python计算机视觉--图像到图像的映射 文章目录 Python计算机视觉--图像到图像的映射 写在前面 1 单应性变换 1.1 直接线性变换算法 1.2 仿射变换 2 图像扭曲 2.1 图像中的图 ...

  4. Python计算机视觉——图像搜索

    文章目录 第七章--图像搜索 一.前期准备知识 1.基于内容的图像检索 2.视觉单词 二.图像搜索 流程1 流程2 流程3 三.使用几何特性对结果排序 第七章--图像搜索 主要内容:利用文本挖掘技术对 ...

  5. Python计算机视觉中译本实例代码/数据集

    shu j 向AI转型的程序员都关注了这个号???????????? 机器学习AI算法工程   公众号:datayx 本书介绍Python的计算机视觉编程,用清晰的Python示例,细致讲解对象识别. ...

  6. python计算机视觉pdf百度云下载_Python计算机视觉编程pdf

    Python计算机视觉编程 内容简介 <Python计算机视觉编程>是计算机视觉编程的实践指南,依赖Python语言讲解了基础理论与算法,并通过大量示例细致分析了对象识别.基于内容的图像搜 ...

  7. 计算机视觉要学哪些编程语言,Python计算机视觉编程

    Python计算机视觉编程 语音 编辑 锁定 讨论 上传视频 <Python计算机视觉编程>是由2014年6月1日人民邮电出版社出版的图书,作者是[瑞典] Jan Erik Solem [ ...

  8. 《Python计算机视觉编程》

    <Python计算机视觉编程> 基本信息 作者: (美)Jan Erik Solem 译者: 朱文涛 袁勇 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:978711535 ...

  9. 大数据、人工智能学习书籍推荐——Python计算机视觉编程

    [前言] 本文首发于:泰泰博客--Python计算机视觉编程,大数据.人工智能学习书籍. 今天给大家推荐一本好书--Python计算机视觉编程.如果你在寻找关于大数据相关的学习书籍或准备"进 ...

最新文章

  1. linux系统下nginx安装目录和nginx.conf配置文件目录
  2. 【原】android获取设备基本信息
  3. MySQL-->索引-->如何创建索引,创建原则
  4. JAVA基础之关键字、保留字和标识符
  5. visio流程图总是自动变小_Visio 2010 中新增功能详细介绍
  6. c#如何实现叫号操作_C#银行排队叫号系统
  7. PDF加页码怎么设置?这里有你想知道的答案
  8. TS文件合并,这里提供了一点小思路。
  9. Xilinx FPGA平台DDR3设计保姆式教程(2)DDR3各时钟频率及带宽分析
  10. 人月神教beta阶段冲刺报告集合
  11. 华为鸿蒙wifi认证,鸿蒙 WiFi操作,热点连接
  12. 电脑怎么改默认浏览器为谷歌
  13. 64位ubuntu使用gcc -m32报错
  14. 还在纠结程序员能不能干一辈子吗?有答案了!!
  15. 三十岁开始学Java
  16. 2022-07-06 Unity核心9——3D动画
  17. zephir-基本语法
  18. 解决找不到pandas问题
  19. 计算机开机卡在进入桌面的时候,电脑开机进不了系统 系统开机后停留在》》》》=======的界面...
  20. 勒索病毒的介绍及防范

热门文章

  1. 苹果5s现在还能用吗_现在还适合买苹果吗?iPhone 11上手体验
  2. chatgpt赋能python:Python长度转换-从毫米到厘米、米和英寸
  3. manjaro下安装QQ、TIM、微信(可输入中文)
  4. 10个Python简单技巧,让数据分析速度加快不止一倍(附零基础学习资料)
  5. python sql语句特殊符号转义。
  6. COO白眉:区块链的运营不是用户关系,而是同盟者!
  7. 打算怎么学计算机作文,学习计划作文(精选10篇)
  8. UPX初步使用(1)
  9. 3GPP 5G Security
  10. Android MINI-YY进度