基于Gist特征+PCA+KNN的场景分类


什么是场景分类

场景分类是语义分类的一种,例如下图中的图片根据场景分为8种,分别是海滨、森林、高速公路、城市、高山、乡村、街道、高楼。


室外场景图

分类的目的是给定一张图片,给出它属于哪个场景。

整体思路

  1. 把一个图片分成4x4个同样大小的块,每个块用4方向8尺度共32个gabor滤波器滤波,然后对每个块里的像素求平均值,那么一张图片最终能得到16x4x8共512维的一个特征向量。PCA算法能够提取到主要特征,在不是特别影响准确度的情况下,降低计算复杂度,这里从512维降到80维。最后使用KNN算法确定分类结果,这里的k取3。


    场景分类流程图
  2. 数据集地址
    我们先从数据集地址下载ACB.tar.gz、AnFpark.tar.gz、FDFpark.tar.gz三个压缩包并解压,它们分别属于教学楼、公园A、公园B三个场景类,里面都是视频,暂时只提取每个视频的第一帧图片作为这次项目的数据集。
  3. 每个场景取80张图片作为训练集,2o张图片作为测试集,实际训练时随机取50张图片,测试时随机取10张。

核心代码

  1. 提取视频里的第一帧
#这里只给出AnFpark里视频获取图片的代码,其它两个类似。
rootdir = '/Users/gcf/Desktop/AnFpark'
list = os.listdir(rootdir)
for i in range(0, len(list)):
    path = os.path.join(rootdir, list[i])
    vc = cv2.VideoCapture(path)
    rval, frame = vc.read()
    res = cv2.resize(frame, (352, 240), interpolation=cv2.INTER_CUBIC)
    cv2.imwrite('/Users/gcf/Desktop/image/' + 'AnFpark_' + str(i) + '.jpeg', res)
  1. gabor滤波器获取gist特征
"""
img:图片数据
blocks:划分成blocks*blocks个patch
direction:garbo滤波器的方向
scale:滤波器的尺度
返回gist特征
"""
def getGist(img,blocks,direction,scale):
    #1.获取滤波器
    filters = buildFilters(direction,scale)
    #2.分割图片
    img_arr = cropImage(img,blocks)
    #3.gist向量
    img_array = process(img_arr,filters)

    return  img_array

#分割图片
def cropImage(img,blocks):
    img_array = []
    w,h=img.size
    patch_with = w / blocks
    patch_height = h / blocks
    for i in range(blocks):
        for j in range(blocks):
            crop_image = img.crop((j*patch_with,i*patch_height,patch_with*(j+1),patch_height*(i+1)))
            img_array.append(crop_image)
            # name = str(i)+'行'+str(j)+'列'+'.jpeg'
            # crop_image.save(name)
    return img_array


#构建Gabor滤波器
def buildFilters(direction,scale):
    filters = []
    lamda = np.pi/2.0

    for theta in np.arange(0,np.pi,np.pi/direction):
        for k in xrange(4):
            kern = cv2.getGaborKernel((scale[k],scale[k]),1.0,theta,lamda,0.5,0,ktype=cv2.CV_32F)
            kern /= 1.5*kern.sum()
            filters.append(kern)
    return filters

#gist向量
def process(img_array,filters):
    res = []
    for img in img_array:
        img_ndarray = np.asarray(img)
        for filter in filters:
            accum = np.zeros_like(img_ndarray)
            for kern in filter:
                fimg = cv2.filter2D(img_ndarray, cv2.CV_8UC3, kern)
                np.maximum(accum, fimg, accum)
            average = np.mean(accum)
            res.append(average)
    round_res = np.round(res, 4)
    return round_res
  1. PCA降纬
"""
data_array:特征向量数组
k:降低到k维
返回k个特征向量
"""
def pca(data_array,k):
    #计算每个纬度的平均值
    mean=np.array([np.mean(data_array[:,i]) for i in range(data_array.shape[1])])
    #数据中心化
    norm_X=data_array-mean
    #散度矩阵
    scatter_matrix=np.dot(np.transpose(norm_X),norm_X)
    #获得数组(特征值,特征向量)
    eig_val, eig_vec = np.linalg.eig(scatter_matrix)
    #降序排列特征值索引
    val_index = np.argsort(-eig_val)
    #选择前k个特征向量
    features=np.array([eig_vec[i] for i in val_index[:k]])
    return features
  1. KNN求分类结果
"""
data:测试数据
dataset:训练数据源
labels:训练数据标签
k:k邻近
返回测试数据标签
"""
def knn(data,dataset,labels,k):
  #计算行数
  dataSetSize = dataset.shape[0]
  #矩阵作差(每行一个样本,行里的每个元素都是属性)
  diffMat = np.tile(data, (dataSetSize, 1)) - dataset
  #差平方
  sqDiffMat = diffMat ** 2
  #差平方和(列元素相加)
  sqDistance = sqDiffMat.sum(axis=1)
  #开根号(欧式距离)
  distance = sqDistance ** 0.5
  #从小到大排序(元素下标)
  sortedDistIndicies = distance.argsort()
  #投票
  classCount = {}
  for i in range(k):
      #获取对应的标签
      voteIlabel = labels[sortedDistIndicies[i]]
      #票数+1
      classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
  #投票从大到小排序
  sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
  return sortedClassCount[0][0]

实验

获取150个样本的Gist特征值

测试30个样本的准确率

10次测试的结果

总结

  • Gist特征没有考虑颜色信息,结合颜色信息效果会更好。
  • 下一篇文章将考虑使用简单的卷积神经网络来代替KNN算法做分类器。
  • 关于项目代码,我将在下一篇文章中给出,它里面包含所有用到的代码。
  • 项目运行环境:mac pro笔记本、python 2.7、PyCharm IDE
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容