- Normalize :以避免亮度、对比度或其他照明效果造成的影响。
- Filtering:考虑几个相邻像素,而不是单一像素值作为像素的真实值。高斯滤波对中心像素权重最大,对相邻像素权重按w、r、t递减,即根据窗口大小确定与中心像素的距离。
最后对滤波后的图像进行如下计算:
将整个图像分成若干块(b)。一个典型的块是上面提到的红框。此外,其他块可以看作是黑盒中提到的单元格(c)的集合。上图中,b的尺寸是8x8, c的尺寸是4x4
接下来,对于每个单元格,计算单元格中每个点的梯度大小和方向(为了简单起见,梯度大小可以简单地假设为Sobel导数或任意两个连续的x和y像素值之间的差)。然后形成大小为n的直方图,将梯度量级值从w.r.t梯度方向进行处理。最后根据规则对直方图进行归一化,形成一个n维向量。
对于一个单元格,我们得到一个n维向量。接下来的操作是通过向右移动50%重叠的图像块和向下移50%重叠的图像块来覆盖整个图像。
最后,将所有这些直方图串联起来,形成一个一维向量,称为HOG特征描述符。
HOG可以通过下面的代码段进行实现。
##HOGDescriptor#Returnsa1Dvectorforanimageppcr=8ppcc=8hog_images= [] hog_features= [] forimageintqdm(train_images): blur=cv.GaussianBlur(image,(5,5),0) #GaussianFilteringfd,hog_image=hog(blur, orientations=8, pixels_per_cell=(ppcr,ppcc),cells_per_block=(2,2),block_norm=‘L2’,visualize=True) hog_images.append(hog_image) hog_features.append(fd) hog_features=np.array(hog_features) hog_features.shape
参数
对这个问题:-块大小为16x16
-单元格大小为8x8
这使得pixel_per_cell = (8x8)并且cells_per_block = (2x2)
-orientations(=8)是每个单元格的直方图容器的数量。在这8个容器中将放置16个梯度值,并将它们添加到每个容器中以表示该方向容器的梯度大小。当两个连续箱子之间的梯度分配发生冲突时,通常通过梯度插值来对梯度值进行投票。
-block_norm =“L1”。其他参数有L1归一化或L2-Hys(Hysteresis)。L2-Hys在某些情况下可以减少噪音。它使用l2 -范数来完成,然后将最大值限制为0.2,并使用l2 -范数来重新归一化。
#normalization by 'L2-Hys'
out=block/np.sqrt(np.sum(block**2) +eps**2) out=np.minimum(out, 0.2) out=out/np.sqrt(np.sum(out**2) +eps**2)
当实际图像形状为60x80,块大小为16x16时,总共将创建6x9 = 54个块(考虑到x,y中任意一步50%的重叠),而在每个块中我们将有4个单元格,每个单元格有8个直方图。因此,特征向量的长度为54x4x8 = 1728
下面是一些HOG图像的可视化表示:
在建模中使用梯度方向的想法是因为这种方法人类神经系统的工作方式相似。当人类看到某一物体时,大脑皮层会引起人们的注意,或者人类为了看得更清楚而改变观察的角度
由于是多分类问题,而且类内分布也不均匀,建议采用分层抽样。
X_train, X_test, y_train, y_test=train_test_split(hog_features,df_labels['class'],test_size=0.2,stratify=df_labels['class'])print('Training data and target sizes: \n{}, {}'.format(X_train.shape,y_train.shape))print('Test data and target sizes: \n{}, {}'.format(X_test.shape,y_test.shape)) =============================================Trainingdataandtargetsizes: (15998, 1728), (15998,) Testdataandtargetsizes: (4000, 1728), (4000,)
最后,将数据使用分类器处理。针对该问题,分别采用了支持向量机、随机森林和KNN算法。在所有最近邻查找算法(ball_tree、kd_tree和brute force)中,KNN的表现都优于其他分类器。最后,使用“贪婪”搜索,因为它的计算速度比ball_tree和kd_tree快得多。
KNN分类器的代码片段
test_accuracy= [] scaler=StandardScaler() X_scaled=scaler.fit_transform(X_train)classifier=KNeighborsClassifier(n_neighbors=3,algorithm='brute') classifier.fit(X_scaled, y_train) test_accuracy=classifier.score(scaler.transform(X_test), y_test) print(test_accuracy)
在masterCategory中,主要包括以下五个类别:[“服饰”、“配饰”、“鞋履”、“个人护理”、“免费物品”]。所有属于其他类别的记录被命名为“其他”。
通过更改Jupyter笔记本中的列名,可以对任何列类型进行分类。
下面是一些有助于评估模型性能的数字。
list_of_categories=categories+['Others']print("Classification Report: \n Target: %s \n Labels: %s \n Classifier: %s:\n%s\n"% (target,list_of_categories,classifier, metrics.classification_report(y_test, y_pred)))df_report=pd.DataFrame(metrics.confusion_matrix(y_test, y_pred),columns=list_of_categories ) df_report.index= [list_of_categories] df_report
最后,让我们对测试图像进行推断
#testimagewithidtest_data_location=root+'/test/'img=cv.imread(test_data_location+'1570.jpg',cv.IMREAD_GRAYSCALE) #loadatgrayscaleimage=cv.resize(img, (60, 80),interpolation=cv.INTER_LINEAR)ppcr=8ppcc=8hog_images_test= [] hog_features_test= []blur=cv.GaussianBlur(image,(5,5),0) fd_test,hog_img=hog(blur, orientations=8, pixels_per_cell=(ppcr,ppcc),cells_per_block=(2,2),block_norm='L2',visualize=True) hog_images_test.append(hog_img) hog_features_test.append(fd)hog_features_test=np.array(hog_features_test) y_pred_user=classifier.predict(scaler.transform(hog_features_test)) #print(plt.imshow(hog_images_test)) print(y_pred_user) print("Predicted MaterCategory: ", mapper[mapper['class']==int(y_pred_user)]['masterCategory'])
一些建议!
scaler_global=MinMaxScaler() final_features_scaled=scaler_global.fit_transform(hog_features) neighbors=NearestNeighbors(n_neighbors=20, algorithm='brute') neighbors.fit(final_features_scaled)distance,potential=neighbors.kneighbors(scaler_global.transform(hog_features_test)) print("Potential Neighbors Found!") neighbors= [] foriinpotential[0]: neighbors.append(i)recommendation_list=list(df_labels.iloc[neighbors]['id']) recommendation_list
使用Flask分类值和推荐图像构建了一个简单的webservice (UI的开发不在本文讨论范围之内)。webservice看起来如下所示:
结论
本文首先说明了HOG背后的原理是什么,以及我们如何使用它来描述图像的特征。接下来,计算HOG特征并将其用于KNN分类器中,然后寻找K个最近邻点。这两个案例都在不使用任何深度学习方法的情况下达到了较高的准确率。在一些情况下,图像被错误地标记,或者图像有多个对象但被标记在一个类中,这会影响我们的模型。下一步是确定错误分类的根本原因,并制作一个更好的分类和推荐引擎。