快捷搜索:  汽车  科技

opencv提取图像特征(Opencv从零开始-)

opencv提取图像特征(Opencv从零开始-)import cv2 as cv src = cv.imread("people.png") cv.imshow("input" src) # hog特征描述 hog = cv.HOGDescriptor() # 创建SVM检测器 hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector()) # 检测行人 (rects weights) = hog.detectMultiScale(src winStride=(4 4) padding=(8 8)


✒️ HOG特征是对象识别与模式匹配中是一种常见的特征提取算法, 本文主要介绍了HOG特征以及利用其描述子加SVM方法实现检测功能,具体的内容可以参考下文~


目录
  • 概述
  • HOG特征描述子提取
  • HOG SVM 检测示例
  • 小结
概述

✔️ HOG(Histogram of Oriented Gradient)特征在对象识别与模式匹配中是一种常见的特征提取算法,是基于本地像素块进行特征直方图提取的一种算法,对象局部的变形与光照影响有很好的稳定性。

HOG应用-行人检测

✔️ 用HOG特征来来识别人像,通过HOG特征提取 SVM训练,可以得到很好的效果,Opencv也集成了HOG进行的行人检测算法。

OpenCV函数

  1. hog = cv2.HOGDescriptor() :创建HOG特征描述;
  2. hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector()) :创建HOG SVM行人检测器;
  3. 多尺度检测API:

rects weights = hog.detectMultiScale(img foundLocations hitThreshold = 0 winStride padding scale = 1.05 finalThreshold = 2.0 useMeanshiftGrouping = false)

输入

  • Img --> 表示输入图像;
  • foundLocations --> 表示发现对象矩形框;
  • hitThreshold --> 表示SVM距离度量(特征与SVM分类超平面之间距离),默认0表示;
  • winStride --> 表示窗口步长;
  • padding --> 表示填充;
  • scale --> 表示尺度空间;
  • finalThreshold --> 最终阈值,默认为2.0;
  • useMeanshiftGrouping --> 不建议使用,速度太慢;

PS:其中窗口步长与Scale对结果影响最大,特别是Scale,小的尺度变化有利于检出低分辨率对象,同时也会导致FP发生,高的可以避免FP但是会产生FN(对象漏检)。

行人检测代码示例

import cv2 as cv src = cv.imread("people.png") cv.imshow("input" src) # hog特征描述 hog = cv.HOGDescriptor() # 创建SVM检测器 hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector()) # 检测行人 (rects weights) = hog.detectMultiScale(src winStride=(4 4) padding=(8 8) scale=1.25 useMeanshiftGrouping=False) for (x y w h) in rects: cv.rectangle(src (x y) (x w y h) (0 255 0) 2) cv.imshow("hog-people" src) cv.waitKey(0) cv.destroyAllWindows()

opencv提取图像特征(Opencv从零开始-)(1)

src

opencv提取图像特征(Opencv从零开始-)(2)

result

HOG特征描述子提取

提取过程

1. Gamma矫正

✔️ 为了提高检测器对关照等干扰因素的鲁棒性,需要对图像进行Gamma矫正,完成对整个图像的归一化,调整对比度,降低噪声影响;

opencv提取图像特征(Opencv从零开始-)(3)

一般 r=1/2

2. 灰度化

3. 计算图像XY梯度和方向

使用sobel可以出水平和垂直方向的梯度:

gx = cv2.Sobel(img cv2.CV_32F 1 0 ksize=1) gy = cv2.Sobel(img cv2.CV_32F 0 1 ksize=1)

利用公式求取梯度幅值和方向:

opencv提取图像特征(Opencv从零开始-)(4)

Opencv中使用:

mag angle = cv2.cartToPolar(gx gy angleInDegrees=True)

4. 8x8网格方向梯度权重直方图统计

✔️ 流程:首先将图像划分成若干个块(Block),每个块又由若干个细胞单元(cell)组成,细胞单元由更小的单位像素(Pixel)组成,然后在每个细胞单元中对内部的所有像素的梯度方向进行统计。

  • 默认HOG的描述子窗口为64x128, 窗口移动步长为 8x8
  • 每个窗口的cell为8x8 每个block由4个cell组成,block移动步长为一个cell,因此可以得到7x15个block

opencv提取图像特征(Opencv从零开始-)(5)

  • 直方图把180度分为9个bin,每个区间为20度,如果像素落在某个区间,就把该像素的直方图累计到对应区间的直方图上

opencv提取图像特征(Opencv从零开始-)(6)

  • 每个block有4个cell 每个cell有9个向量值,即每个block有36个向量,所以整个窗口有7x15x36=3780个特征描述子。

5. 块描述子和特征向量归一化

✔️ 每个block可以得到4个9维的向量,需要再次进行一次归一化,这样可以进一步提高泛化能力,同传使用L2-nrom进行归一化(还有L1-norm L1-sqrt etc.)

opencv提取图像特征(Opencv从零开始-)(7)

整体流程图

opencv提取图像特征(Opencv从零开始-)(8)

HOG SVM 检测示例

✔️ 这里,我们使用前面所了解到HOG知识,结合SVM,进行一个简单的水表检测案例。

  1. 使用描述子特征生成样本数据
  2. 通过SVM进行分类学习与训练
  3. load模型,进行预测结果
  • 数据生成

# 把目标图放在64x128的灰色图片中间,方便计算描述子 def get_hog_descriptor(image): hog = cv.HOGDescriptor() h w = image.shape[:2] rate = 64 / w image = cv.resize(image (64 np.int(rate*h))) gray = cv.cvtColor(image cv.COLOR_BGR2GRAY) bg = np.zeros((128 64) dtype=np.uint8) bg[: :] = 127 h w = gray.shape dy = (128 - h) // 2 bg[dy:h dy :] = gray descriptors = hog.compute(bg winStride=(8 8) padding=(0 0)) return descriptors def get_data(train_data labels path lableType): for file_name in os.listdir(path): img_dir = os.path.join(path file_name) img = cv.imread(img_dir) hog_desc = get_hog_descriptor(img) one_fv = np.zeros([len(hog_desc)] dtype=np.float32) for i in range(len(hog_desc)): one_fv[i] = hog_desc[i][0] train_data.append(one_fv) labels.append(lableType) return train_data labels def get_dataset(pdir ndir): train_data = [] labels = [] # 获取正样本 train_data labels = get_data(train_data labels pdir lableType=1) # 获取负样本 train_data labels = get_data(train_data labels ndir lableType=-1) return np.array(train_data dtype=np.float32) np.array(labels dtype=np.int32) if __name__ == '__main__': # train_data的shape为(n 3780) labels(n ) # n为样本数 train_data labels = get_dataset("pdir/" "ndir/")

  • 构建SVM训练器

✔️ Opencv中SVM有线性分类器和非线性的径向分类器。

这里使用线性分类器:

svm.train(trainData cv.ml.ROW_SAMPLE responses)

  • Sample --> 表示训练样本数据/HOG特征数据
  • Layout --> 有两种组织方式ROW_SAMPLE与COL_SAMPLE
  • Responses --> 每个输入样本的标签

训练代码

def svm_train(pdir ndir): # 创建SVM svm = cv.ml.SVM_create() # 设置相应的SVM参数 svm.setKernel(cv.ml.SVM_LINEAR) svm.setType(cv.ml.SVM_C_SVC) svm.setC(2.67) svm.setGamma(5.383) # 获取正负样本和labels trainData responses = get_dataset(pdir ndir) # reshape (n )-->(n 1) responses = np.reshape(responses [-1 1]) # 训练 svm.train(trainData cv.ml.ROW_SAMPLE responses) svm.save('svm_data.dat')

  • 预测目标

import cv2 as cv import numpy as np image = cv.imread("test_01.jpg") # 原图太大,降低原图分辨率 test_img = cv.resize(image (0 0) fx=0.2 fy=0.2) # 灰度 gray = cv.cvtColor(test_img cv.COLOR_BGR2GRAY) # 获取大小 h w = test_img.shape[:2] # 加载训练好的模型 svm = cv.ml.SVM_load('../code_104/svm_data.dat') # 为了筛选框,记录框坐标总和以及框的个数,为了最后求出所有候选框的均值框 sum_x = 0 sum_y = 0 count = 0 # 创建hog特征描述子函数 hog = cv.HOGDescriptor() # 为了加快计算,窗口滑动的步长为4,一个cell是8个像素 for row in range(64 h-64 4): for col in range(32 w-32 4): win_roi = gray[row-64:row 64 col-32:col 32] hog_desc = hog.compute(win_roi winStride=(8 8) padding=(0 0)) one_fv = np.zeros([len(hog_desc)] dtype=np.float32) for i in range(len(hog_desc)): one_fv[i] = hog_desc[i][0] one_fv = one_fv.reshape(-1 len(hog_desc)) # 预测 result = svm.predict(one_fv)[1] # 统计正样本 if result[0][0] > 0: sum_x = (col-32) sum_y = (row-64) count = 1 # 画出所有框 cv.rectangle(test_img (col-32 row-64) (col 32 row 64) (0 233 255) 1 8 0) # 求取均值框 x = sum_x // count y = sum_y // count # 画出均值框 cv.rectangle(test_img (x y) (x 64 y 128) (0 0 255) 2 8 0)

opencv提取图像特征(Opencv从零开始-)(9)

src

opencv提取图像特征(Opencv从零开始-)(10)

result

如上图,类似于目标检测中NMS的作用,这里使用均值的方法获得最终的框。

小结

✔️ 对于简单的识别,HOG和SVM的识别效果还是很不错的,为了提高效果,可以增加正负样本进行,再次进行训练。

✔️ SVM不需要GPU,所以在针对一些简单的识别任务,可以采用这个方法,但是复杂问题,还是建议使用神经网络,效果会更好!

未完待续~

更多Opencv教程将持续发布!

欢迎关注哟~❤️❤️❤️

猜您喜欢: