图像分类,根据各自在图像信息中所反映的不同特征,把不同类别的目标区分开来的图像处理方法。它利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,以代替人的视觉判读。
分类意味着事先准备好若干个类别,然后将一个目标对象根据某种特征划到某个类别中去。以下几种情况可以考虑使用分类:
(1)图像分割
(2)目标识别
(3)良品检测
(4)缺陷检测
(5)光学字符识别(OCR)
MLP是一种基于神经网络的、动态的分类器。MLP分类器可用于通用特征的分类、图像分割、OCR等。
多层感知机(MLP,Multilayer Perceptron)也叫人工神经网络(ANN,Artificial Neural Network),除了输入输出层,它中间可以有多个隐层,最简单的MLP只含一个隐层,即三层的结构,如下图:
SVM即支持向量机,用于实现数据的二分类。SVM用于二分类,即只有两种类别的分类。
SVM,英文全称为 Support Vector Machine,中文名为支持向量机,由数学家Vapnik等人早在1963年提出。在深度学习兴起之前,SVM一度风光无限,是机器学习近几十年来最为经典的,也是最受欢迎的分类方法之一。
如下图所示,有两类样本数据(橙色和蓝色的小圆点),中间的红线是分类超平面,两条虚线上的点(橙色圆点3个和蓝色圆点2个)是距离超平面最近的点,这些点即为支持向量。简单地说,作为支持向量的样本点非常非常重要,以至于其他的样本点可以视而不见。而这个分类超平面正是SVM分类器,通过这个分类超平面实现对样本数据一分为二。
GMM分类器,即高斯混合模型分类器。高斯模型就是用高斯概率分布曲线,即正态分布曲线来量化概率的一种表达方式。其可以使用不止一条概率分布曲线。
GMM(Gaussian Mixture Model, 高斯混合模型)是指该算法油多个高斯模型线 性叠加混合而成。每个高斯模型称之为component。GMM算法描述的是数据的 本身存在的一种分布。
GMM算法常用于聚类应用中,component的个数就可以认为是类别的数量。
假定GMM由k个Gaussian分布线性叠加而成,那么概率密度函数如下图所示:
k-NN分类器是一个简单但是功能非常强大的分类器,能够储存所有训练集中的数据和分类,并且对新的样品也能基于其邻近的训练数据进行分类。
K-近邻( k-nearest neighbors / knn )是一类基于实例 ( instance-based ) 的非参数学习算法。在这里,输入是由数据集里的 k 个最近的训练实例组成,输出是一个类成员。一个新对象的分类原则是,它被分到离它最近的 k 个邻居中的多数所在的那个类中。特别地,k = 1 时,该对象被分到离它最近的邻居所在的类中。通常,可以赋邻居权值表示邻居对分类的贡献。例如,可以取对象到每个邻居的距离的倒数作为它的权值。knn 算法的缺点是,它对数据的局部结构敏感,容易过度拟合数据。
多数情况下都可以考虑以上4中分类器。它们足够灵活和高效。实际工作中,可以根据项目的需要或者硬件条件的限制选择合适的分类器。
(1)MLP分类器:分类速度快,但训练速度慢,对内存的要求低,支持多维特征空间,特别适合需要快速分类并且支持离线训练的场景,但不支持缺陷检测。
(2)SVM分类器:分类检测的速度快,当向量维度低时速度最快,但比MLP分类器慢,尽管其训练速度比MLP分类器快得多。其对内存的占用取决于样本的数量,如果有大量的样本,如字符库这样的样本需要训练,分类器会变得十分庞大。
(3)GMM分类器:训练速度和检测速度都很快,特别是类别较少时速度非常快,支持异常检测,但不适用于高维度特征检测。
(4)kNN分类器:训练速度非常快,分类速度比MLP分类器慢,适合缺陷检测和多维度特征分类,但对内存的需求较高。
除了分类器外,特征和训练样本的选择也会影响到分类结果,当分类结果不理想时,可以考虑调整这两个因素。如果训练样本中已经包含了目标对象的全部相关特征,但分类结果仍然不理想,那么可以考虑换一个分类器。
选择什么样的特征完全取决于检测的对象是什么,以及分类的要求是什么。
~
分类的步骤,首先是创建一个合适的分类器;然后考察对象的特征,将合适的特征向量添加到纹理分类器中;最后使用样本数据进行训练,使分类器学会某种分类的规则。在检测时,提取检测目标对应于分类器中的特征值,使用训练过的分类器进行分类。使用完分类器后,从内存中清除它。
(1)明确有哪些类别,并根据类别收集合适的图像作为样本数据集。
(2)创建分类器
(3)获取明确了类别的样本的特征向量
(4)将这些样本按分类序号添加到分类器中
(5)训练分类器
(6)保存分类器(供后续调用)
(7)获取未知分类的被测对象的特征向量,这些特征向量应当是之前训练分类器时使用过的特征向量
(8)对被测对象的特征向量进行分类
(9)从内存中清除分类器
*关闭当前窗口
dev_close_window ()
*创建新窗口
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
*设置绘制形状的方式
dev_set_draw ('margin')
dev_set_line_width (3)
*创建mlp分类器,特征数为1,输出类为2个,输出方法选择‘softmax’用于分类
create_class_mlp (1, 1, 2, 'softmax', 'normalization', 3, 42, MLPHandle)
*创建训练样本图像与其分类的对应关系
*图像和分类名称一一对应
FileNames := ['m1','m2','m3','m4']
Classes := [0,0,1,1]
for J := 0 to |FileNames| - 1 by 1
*读取训练图像
read_image (Image, 'data/' + FileNames[J])
dev_display (Image)
*对图像进行分割
rgb1_to_gray (Image, GrayImage)
threshold (GrayImage, darkRegion, 0, 105)
connection (darkRegion, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 2000, 99999)
fill_up (SelectedRegions, Objects)
dev_display (Objects)
disp_message (WindowHandle, 'Add Sample ' + J + ', Class Index ' + Classes[J], 'window', 10, 10, 'black', 'true')
*将分割后的对象objects添加进分类器对应的分类Classes[J]中
count_obj (Objects, Number)
*提取特征(圆度)
for N := 1 to Number by 1
select_obj (Objects, Region, N)
circularity (Region, Circularity)
add_sample_class_mlp (MLPHandle, Circularity,Classes[J])
endfor
stop()
disp_continue_message (WindowHandle, 'black', 'true')
endfor
dev_clear_window ()
disp_message (WindowHandle, 'Training...', 'window', 10, 10, 'black', 'true')
*训练mlp分类器
train_class_mlp (MLPHandle, 200, 1, 0.01, Error, ErrorLog)
clear_samples_class_mlp (MLPHandle)
*读取输入的待检测图像
read_image (testImage, 'data/m5')
rgb1_to_gray (testImage, GrayTestImage)
*将图像进行分割
threshold (GrayTestImage, darkTestRegion, 0, 105)
connection (darkTestRegion, ConnectedTestRegions)
select_shape (ConnectedTestRegions, SelectedTestRegions, 'area', 'and', 1500, 99999)
fill_up (SelectedTestRegions, testObjects)
*将分割后的对象objects进行分类
count_obj (testObjects, Number)
Classes := []
Colors := ['yellow','magenta']
dev_set_colored (6)
dev_display (testImage)
*提取特征(圆度)
for J := 1 to Number by 1
select_obj (testObjects, singleRegion, J)
circularity (singleRegion, Circularity)
classify_class_mlp (MLPHandle, Circularity, 1, Class, Confidence)
Classes := [Classes,Class]
dev_set_color (Colors[Classes[J-1]])
dev_display (singleRegion)
endfor
*清除MLP分类器,释放内存
clear_class_mlp (MLPHandle)
应注意调整相应的参数
应注意调整相应的参数
应注意调整相应的参数
OCR(光学字符识别)是一种更进一步的分类方法,用于识别字符。识别的第一步,是将独立的字符区域从图像中提取出来,然后将其指定给某个字符的种类。MLP、SVM和k-NN分类器都可以用于OCR。
OCR的检测分为离线训练和在线检测两部分。
dev_close_window()
read_image (Image, 'data/modelWords')
get_image_size(Image,width,height)
dev_open_window (0, 0, width, height, 'black', WindowHandle)
rgb1_to_gray (Image, GrayImage)
gen_empty_obj (EmptyObject)
for Index := 1 to 4 by 1
disp_message (WindowHandle, '请框选单个汉字区域,右键确认:','window', 12, 12, 'yellow', 'false')
draw_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
**根据画的矩形生成对应的矩形
gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)
reduce_domain (GrayImage, Rectangle, ImageReduced1)
*阈值处理
threshold (ImageReduced1, Region1, 128, 255)
*准备接收所有提取的字符区域
concat_obj (EmptyObject, Region1, EmptyObject)
endfor
words:=['艺','术','中','心']
*排序
sort_region (EmptyObject, SortedRegions1, 'character', 'true', 'row')
for Index1:=1 to 4 by 1
select_obj (SortedRegions1, ObjectSelected1, Index1)
append_ocr_trainf (ObjectSelected1, Image, words[Index1-1], 'data/yszx.trf')
endfor
read_ocr_trainf_names ('data/yszx.trf', CharacterNames, CharacterCount)
create_ocr_class_mlp (50, 60, 'constant', 'default', CharacterNames, 80, 'none', 10, 42, OCRHandle)
trainf_ocr_class_mlp (OCRHandle, 'data/yszx.trf', 200, 1, 0.01, Error, ErrorLog)
write_ocr_class_mlp (OCRHandle, 'data/yszx.omc')
*导入另一张做测试的图
read_image (ImageTest, 'data/testWords.jpg')
rgb1_to_gray (ImageTest, Image1)
threshold (Image1, testwordregion, 125, 255)
*对符合条件的字符区域进行分割
connection (testwordregion, ConnectedwordRegions)
*筛选符合条件的字符形状区域
select_shape (ConnectedwordRegions, SelectedwordRegions, 'area', 'and', 700, 2500)
*从左到右,排序
sort_region (SelectedwordRegions, SortedRegions2, 'upper_left', 'true', 'column')
count_obj(SortedRegions2, Number)
*开始字符识别
read_ocr_class_mlp ('data/yszx.omc', OCRHandle1)
do_ocr_multi_class_mlp (SortedRegions2, Image1, OCRHandle1, Class, Confidence)
*显示结果
disp_message(WindowHandle, '识别结果:', 'image', 10, 10, 'white', 'false')
for i:=1 to 4 by 1
disp_message(WindowHandle, Class[i-1], 'image', 90, 60*i, 'yellow', 'false')
endfor