赞
踩
目录
案例训练数据:cifar 10
图像下载地址(后面我们要用这批数据作为训练数据):CIFAR-10 and CIFAR-100 datasetshttp://www.cs.toronto.edu/~kriz/cifar.html本文参考链接:HOG + SVM 进行图片分类(python)_程序员的点滴-CSDN博客_svm图片二分类pythonhttps://blog.csdn.net/q1242027878/article/details/74271694什么是HOG:
一文讲解方向梯度直方图(hog)https://zhuanlan.zhihu.com/p/85829145
特征描述符就是通过提取图像的有用信息,并且丢弃无关信息来简化图像的表示。HOG特征描述符可以将3通道的彩色图像转换成一定长度的特征向量。
在HOG特征描述符中,梯度方向的分布,也就是梯度方向的直方图被视作特征。图像的梯度(x和y导数)非常有用,因为边缘和拐角(强度突变的区域)周围的梯度幅度很大,并且边缘和拐角比平坦区域包含更多关于物体形状的信息。
图像处理——梯度直方图HOG_lanling1996的博客-CSDN博客_梯度直方图 图像处理之特征提取:HOG特征简单梳理 HOG方向梯度直方图,这里分解为方向梯度与直方图。 一、方向梯度 梯度:在向量微积分中,标量...https://blog.csdn.net/lanling1996/article/details/112589519HOG主要应用于行人检测方面,以行人照片为例:
完整代码、数据处理和样例,可去这里下载:基于Hog 的 SVM Pytorch图像分类任务
案例操作中使用的训练数据是cifar10的数据,这里我们需要先把原始数据,转为图像数据,进行本地化保存,下载好数据后,进行转图操作,转图代码如下:
- import cv2
- import numpy as np
- import os
-
-
- def unpickle(file):
- import _pickle as cPickle
- with open(file, 'rb') as f:
- dict = cPickle.load(f, encoding='iso-8859-1')
- return dict
-
-
- def main(cifar10_data_dir):
- train_txt=[]
- test_txt=[]
- for i in range(1, 2):
- train_data_file = os.path.join(cifar10_data_dir, 'data_batch_' + str(i))
- print(train_data_file)
- data = unpickle(train_data_file)
- print('unpickle done', data)
- for j in range(10000):
- img = np.reshape(data['data'][j], (3, 32, 32))
- img = img.transpose(1, 2, 0)
- img_name = 'train/' + str(data['labels'][j]) + '_' + str(j + (i - 1) * 10000) + '.jpg'
- cv2.imwrite(os.path.join(cifar10_data_dir, img_name), img)
- train_txt.append(str(data['labels'][j]) + '_' + str(j + (i - 1) * 10000) + '.jpg' + ' ' + str(data['labels'][j]))
- np.savetxt(r"./train.txt", np.reshape(train_txt, -1), delimiter=',', fmt='%5s')
-
- test_data_file = os.path.join(cifar10_data_dir, 'test_batch')
- data = unpickle(test_data_file)
- for i in range(10000):
- img = np.reshape(data['data'][i], (3, 32, 32))
- img = img.transpose(1, 2, 0)
- img_name = 'test/' + str(data['labels'][i]) + '_' + str(i) + '.jpg'
- cv2.imwrite(os.path.join(cifar10_data_dir, img_name), img)
- test_txt.append(str(data['labels'][i]) + '_' + str(i) + '.jpg' + ' ' + str(data['labels'][i]))
- np.savetxt(r"./test.txt", np.reshape(test_txt, -1), delimiter=',', fmt='%5s')
-
-
- if __name__ == "__main__":
- main('cifar-10-batches-py')
如果遇到这个问题:
python 3以上版本使用pickle.load读取文件报UnicodeDecodeError: 'ascii' codec can't decode byte 0x8b in position 6
直接方代码,边训练边学习这段代码的含义,主要思路就是一下几点:
- # -*- coding=utf-8 -*-
- import glob
- import platform
- import time
- from PIL import Image
- from skimage.feature import hog
- import numpy as np
- import os
- import joblib
- from sklearn.svm import LinearSVC
- import shutil
- import sys
-
- # 第一个是你的类别 第二个是类别对应的名称 输出结果的时候方便查看
- label_map = {0: 'airplane',
- 1: 'automobile',
- 2: 'bird',
- 3: 'cat',
- 4: 'deer',
- 5: 'dog',
- 6: 'frog',
- 7: 'horse',
- 8: 'ship',
- 9: 'truck,'
- }
- # 训练集图片的位置
- train_image_path = './database/train'
- # 测试集图片的位置
- test_image_path = './database/test'
-
- # 训练集标签的位置
- train_label_path = os.path.join('./labels', 'train.txt')
- # 测试集标签的位置
- test_label_path = os.path.join('./labels', 'test.txt')
-
- image_height = 32
- image_width = 32
-
- train_feat_path = './feature/train/'
- test_feat_path = './feature/test/'
- model_path = 'model/'
-
-
- # 获得图片列表
- def get_image_list(filePath, nameList):
- print('read image from ', filePath)
- img_list = []
- for name in nameList:
- temp = Image.open(os.path.join(filePath, name))
- img_list.append(temp.copy())
- temp.close()
- return img_list
-
-
- # 提取特征并保存
- def get_feat(image_list, name_list, label_list, savePath):
- i = 0
- for image in image_list:
- try:
- # 如果是灰度图片 把3改为-1
- image = np.reshape(image, (image_height, image_width, -1))
- except:
- print('发送了异常,图片大小size不满足要求:', name_list[i])
- continue
- #gray = rgb2gray(image) / 255.0
- # 如果直接就是灰度图
- gray = image
- # 这句话根据你的尺寸改改
- fd = hog(gray, orientations=12, block_norm='L1', pixels_per_cell=[8, 8], cells_per_block=[4, 4], visualize=False,
- transform_sqrt=True)
- fd = np.concatenate((fd, [label_list[i]]))
- fd_name = name_list[i] + '.feat'
- fd_path = os.path.join(savePath, fd_name)
- joblib.dump(fd, fd_path)
- i += 1
- print("Test features are extracted and saved.")
-
-
- # 变成灰度图片
- def rgb2gray(im):
- gray = im[:, :, 0] * 0.2989 + im[:, :, 1] * 0.5870 + im[:, :, 2] * 0.1140
- return gray
-
-
- # 获得图片名称与对应的类别
- def get_name_label(file_path):
- print("read label from ", file_path)
- name_list = []
- label_list = []
- with open(file_path) as f:
- for line in f.readlines():
- #一般是name label 三部分,所以至少长度为3 所以可以通过这个忽略空白行
- if len(line) >= 3:
- name_list.append(line.split(' ')[0])
- label_list.append(line.split(' ')[1].replace('\n','').replace('\r',''))
- if not str(label_list[-1]).isdigit():
- print("label必须为数字,得到的是:",label_list[-1], "程序终止,请检查文件")
- exit(1)
- return name_list, label_list
-
-
- # 提取特征
- def extra_feat():
- train_name, train_label = get_name_label(train_label_path)
- test_name, test_label = get_name_label(test_label_path)
-
- train_image = get_image_list(train_image_path, train_name)
- test_image = get_image_list(test_image_path, test_name)
- get_feat(train_image, train_name, train_label, train_feat_path)
- get_feat(test_image, test_name, test_label, test_feat_path)
-
-
- # 创建存放特征的文件夹
- def mkdir():
- if not os.path.exists(train_feat_path):
- os.mkdir(train_feat_path)
- if not os.path.exists(test_feat_path):
- os.mkdir(test_feat_path)
-
-
- # 训练和测试
- def train_and_test():
- t0 = time.time()
- features = []
- labels = []
- correct_number = 0
- total = 0
- for feat_path in glob.glob(os.path.join(train_feat_path, '*.feat')):
- data = joblib.load(feat_path)
- features.append(data[:-1])
- labels.append(data[-1])
-
- ############ 训练部分 ############
- """
- print("Training a Linear LinearSVM Classifier.")
- clf = LinearSVC()
- clf.fit(features, labels)
- # 下面的代码是保存模型的
- if not os.path.exists(model_path):
- os.makedirs(model_path)
- joblib.dump(clf, model_path + 'model')
- """
-
- ############ 训练完验证部分 ############
- # 下面的代码是加载模型 可以注释上面的代码 直接进行加载模型 不进行训练
- clf = joblib.load(model_path+'model')
- print("训练之后的模型存放在model文件夹中")
- # exit()
- result_list = []
- for feat_path in glob.glob(os.path.join(test_feat_path, '*.feat')):
- total += 1
- if platform.system() == 'Windows':
- symbol = '\\'
- else:
- symbol = '/'
- image_name = feat_path.split(symbol)[1].split('.feat')[0]
- data_test = joblib.load(feat_path)
- data_test_feat = data_test[:-1].reshape((1, -1)).astype(np.float64)
- result = clf.predict(data_test_feat)
- print(result)
- result_list.append(image_name + ' ' + str(result[0]) + '\n')
- if int(result[0]) == int(data_test[-1]):
- correct_number += 1
- write_to_txt(result_list)
- rate = float(correct_number) / total
- t1 = time.time()
- print('准确率是: %f' % rate)
- print('耗时是 : %f' % (t1 - t0))
-
-
- def write_to_txt(list):
- with open('result.txt', 'w') as f:
- f.writelines(list)
- print('每张图片的识别结果存放在result.txt里面')
-
-
- if __name__ == '__main__':
-
- mkdir() # 不存在文件夹就创建
- # need_input = input('是否手动输入各个信息?y/n\n')
-
- if sys.version_info < (3,):
- need_extra_feat = input('是否需要重新获取特征?y/n\n')
- else:
- need_extra_feat = input('是否需要重新获取特征?y/n\n')
-
- if need_extra_feat == 'y':
- shutil.rmtree(train_feat_path)
- shutil.rmtree(test_feat_path)
- mkdir()
- extra_feat()
-
- train_and_test()
cifar10的训练和测试结果,如下:
- 是否需要重新获取特征?y/n
- y
- read label from ./labels\train.txt
- read label from ./labels\test.txt
- read image from ./database/train
- read image from ./database/test
- Test features are extracted and saved.
- Test features are extracted and saved.
- Training a Linear LinearSVM Classifier.
- 训练之后的模型存放在model文件夹中
- 每张图片的识别结果存放在result.txt里面
- 准确率是: 0.460400
- 耗时是 : 12.241030
直观的查看下hog梯度方向直方图的样式,以一张其它图像为例进行展示,你也可以替换为你自己的图像,如下:
- from skimage.feature import hog
- from skimage import io
- from PIL import Image
- import cv2
-
- img = cv2.cvtColor(cv2.imread('./database/train_medical/DRCrop_3.png'), cv2.COLOR_BGR2GRAY)
- print(img.shape)
- normalised_blocks, hog_image = hog(img, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(8, 8),
- block_norm='L2-Hys', visualize=True)
- io.imshow(hog_image)
- io.show()
支持向量机(Support Vector Machine, SVM)是一种监督学习算法,常用于分类和回归问题。它的基本思想是在训练数据集中找到一个超平面,使得超平面尽可能地将不同类别的数据分开,同时尽量缩小超平面与数据点之间的间隔。
在分类问题中,支持向量机通常使用线性分类器,即找到一个超平面使得其将数据点分为两个类别。在非线性分类问题中,支持向量机可以通过将数据映射到高维空间,再在高维空间中找到超平面,来解决非线性分类问题。
在回归问题中,支持向量机使用支持向量回归(Support Vector Regression, SVR)来预测连续型输出变量。SVR的基本思想是找到一条拟合数据的直线或曲线,使得直线或曲线与数据点之间的误差尽可能小。
支持向量机具有许多优点,例如:
1. 泛化能力强、
2. 不需要太多的训练数据(因为最终的解仅由少数支持向量决定)
3. 可以解决高维问题等。
但是,支持向量机也有一些缺点,例如:
1. 对缺失数据敏感、
2. 对参数调整敏感等。
问:分类间隔是由所有训练集样本所决定的吗?
答:不是!分类间隔是由距离分类决策边界最近的那些少量样本决定的。而比这些样本距离分类决策边界更远的大量样本,其实都不会影响到最优权向量的求取。这些作用十分特殊的样本,就被称为“支持向量(Support Vector)”,表示是他们支撑起了线性分类器在最大分类间隔意义下的最优解。这也是为什么这种算法被称为“支持向量机(Support Vector Machine,SVM)”的原因。
推荐更详尽的学习链接,强烈推荐:
如果最后测试阶段的准确率不好,可以调整核函数,可以参考这个函数,对核函数进行修改:SVMhttps://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html#sklearn.svm.SVC
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。