基于传统CV实现图片分类(以图搜图)

图片分类在计算机领域并不是一个新鲜的话题了,相对于传统计算机视觉(CV)方法解决这类问题,深度学习的效果反而更好。但是我们依然需要了解传统做法,说不定在未来研究时可以提供不一样的灵感。

图像描述符

要实现图像分类,首先我们需要提取我们图像库里已有图像的特征,这个过程称为描述图像。图像描述符定义了我们如何量化图像,而其输出可以看作图像本身的抽象。图像描述符的选取可以有很多,可以以颜色,形状为基准或者质地为基准。关于图像描述符更多更详细的介绍将在后面的文章中说明。在本文中,我们使用颜色中的颜色直方图作为图像描述符。

相似度指标

如何判断目标图像和图像库里的某一个图像是否是一类?我们可以通过比较二者的图像描述符来判断。而这个比较方法我们称之为相似度指标,即用来判断两者是否相似的标准。关于相似度指标更多更详细的介绍将在后面的文章中说明。

代码及简单解释

导入必要的库,如果导入失败可以pip安装或者自行搜索导入教程。

import imutils
import cv2
from imutils.paths import list_images
import argparse
import numpy as np
import os

这个是颜色直方图的类,在这里简单介绍一下颜色直方图calcHist()。颜色直方图可以将显示图片中各像素数值区间内像素的数量。例如,我们将bin设为2,那么意味着我们将像素范围[0,255]等比例分为2份[0,127];[128,255]。然后计算图片里属于[0,127]的像素的个数和属于[128,255]的像素的个数。像素数值的大小反映了亮暗程度,各个通道RGB的像素又分别代表了颜色的深浅。于是两幅整体颜色相近的图片的颜色直方图是类似的。
在实际应用时我们也应该注意一点,不同图像的像素数量可能不同,于是我们可以使用归一化normalize(),将数量换成比例。例如[100,300],经过归一化后变为[0.25,0.75]。这样就可以比较不同大小的图像的颜色直方图。

class ColorHistogram:
    def __init__(self,bins):
        self.bins=bins

    def describe(self,image):
        hist=cv2.calcHist([image],[0,1,2],None,self.bins,
                [0,256,0,256,0,256])
        hist=cv2.normalize(hist,hist)

        return hist.flatten()

初始化,bin选择32。我们要注意bin的选择会影响数据量的多少,对于小数据集来说,bin选取较大时构建颜色直方图的时间似乎并没有增长太多。但是对于后续比较相似度时,bin的大小将会明显影响计算的时间。而且可以肯定的是,bin选取越大对于分类的准确性是有提升的。但是提升的幅度可能在到达某一点后就大幅减少,此时再通过堆计算量来提升那一两个百分点其实是没有必要的,尤其是对于专注于应用的同学。


ap=argparse.ArgumentParser()
ap.add_argument("-d","--dataset",required=True)
ap.add_argument("-i","--image",required=True)
args=vars(ap.parse_args())

index={}
desc=ColorHistogram([32,32,32])

for imagePath in list_images(args["dataset"]):
    k=imagePath[imagePath.rfind("/")+1:]
    image=cv2.imread(imagePath)
    features=desc.describe(image)
    index[k]=features

读取我们的图像库,我的图像库里有从网上下载的20张图片,分别包括海洋,树林和沙漠。

基于传统CV实现图片分类(以图搜图)
class Classif:
    def __init__(self,index):
        self.index=index

    def classif(self,iFeature):
        results={}
        for (k,features) in self.index.items():
            d=self.chi2_distance(features,iFeature)
            results[k]=d

        results=sorted([(v,k) for (k,v) in results.items()])
        return results

    def chi2_distance(self,histA,histB,eps=1e-10):
        d=0.5*np.sum([((a-b)**2)/(a+b+eps) for (a,b) in zip(histA,histB)])
        return d

读取我们的目标图片,提取图像描述符并进行分类。分类结束后,我们提取图像库中相似度最高的五张图像进行展示。

image=cv2.imread(args["image"])
cv2.imshow("Image",image)

Features=desc.describe(image)

clas=Classif(index)
results=clas.classif(Features)

montage=np.zeros((100*5,200,3),dtype="uint8")

for j in range(0,5):
    (score,imageName)=results[j]
    path=os.path.join(args["dataset"],imageName)
    result=cv2.imread(path)
    result=cv2.resize(result,(200,100))
    if j<5:
        montage[j*100:(j+1)*100,:]=result

cv2.imshow("Result",montage)
cv2.waitKey(0)

结果

基于传统CV实现图片分类(以图搜图)
基于传统CV实现图片分类(以图搜图)
看起来不错,但很明显这个分类器对颜色很敏感,并不完全符合我们对于分类器的需求。我们也可以根据我们想要分类图片的特征来选取图像描述符,例如有些图片里物体的形状特征很明显。当然,后期我们也会介绍神经网络,深度学习的方法,这个是目前的主流。

“本站所有文章均为原创,欢迎转载,请注明文章出处:https://blog.csdn.net/kasami_/article/details/123834951。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。”

Original: https://blog.csdn.net/kasami_/article/details/123834951
Author: mini梁翊洲MAX
Title: 基于传统CV实现图片分类(以图搜图)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/663375/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球