前段时间做了一个车型识别的小项目,思路是利用k-means算法以及词袋模型来做的。

  近年来图像识别的方法非常非常多,这边只记录一下我那个项目的思路,核心思想是k-means算法和词汇树。

  很遗憾没有做详尽的开发前的思路文档,只能按照记忆进行大致总结。

  项目分为三大模块:特征点抽取、训练词汇树、识别(利用训练好的词汇树)。

  

  首先是特征点的抽取。我是用的OpenCV的框架来做的特征点抽取。这里提到两种特征点:SURF和SIFT。

  关于这两种特征点提取算法,这里做简要介绍(其实我真的不太care,主要是看哪个的特性适合我的项目。单纯为了实现这个东西的话我觉得没必要太深究这个,当然如果你要把这个东西做透了,那肯定得好好研究,毕竟源码来看还是有很多可以优化的东西)。

  SIFT特征是图像的局部特征,对平移、旋转、尺度缩放、亮度变化、遮挡和噪声等具有良好的不变性,对视觉变化、仿射变换也保持一定程度的稳定性。SIFT算法时间复杂度的瓶颈在于描述子的建立和匹配 ,如何优化对特征点的描述方法是提升SIFT效率的关键。

  SURF算法的优点是速度远快于SIFT且稳定性好;在时间上,SURF运行速度大约为SIFT的3倍;在质量上,SURF的鲁棒性很好,特征点识别率较SIFT高,在视角、光照、尺度变化等情形下,大体上都优于SIFT。

  这里要提到的一点就是SURF是64维的特征描述子,而SIFT是128维的特征描述子,简单点数说就是SIFT是X=(x1,x2,x3,...,x128)。而SURF是Y=(y1,y2,y3,...,y64)。从做k-means聚类的角度上来说我果断选择了SURF算法来提取(不过因为用的是OpenCV框架,所以几句代码的事。再提一句,OpenCV框架不止C有,Java也有,喜欢Java不喜欢C/C++的朋友可以尝试,我就是用的java代码)。

  简单点说一幅图就是由N多个SURF特征点构成的,有点像像素点。每一个SURF特征点是一个64维的向量Y=(y1,y2,y3,...,y64),就像像素一样,一张图不也是由很多很多个像素点组成的吗,每一个像素点是一个三维向量(x,y,z),其中x,y,z都在0到255之间。

  首先是SURF特征点的抽取,我们采用OpenCV框架来抽取每一张图的SURF特征点(当时大约10000张图),将所有图中抽出的SURF特征点都放在一起,形成一个特征点“池塘”,有大概几十亿个特征点。

  第二步是词汇树的训练。我们把这个词汇树定义为一个深层次的二叉树,那么这个二叉树如何生成呢,这里首先要提到k-means聚类算法:

  k-means聚类算法是一类无监督机器学习的算法。至于什么是机器学习,什么是有监督学习和无监督学习,这里简单介绍,具体可以查百度。

  机器学习是一类算法的总称,通俗点来讲就是想让机器通过学习来拥有智慧(拥有决策能力),这和大多数的基本算法其实没啥区别,这里还要提到一点就是基于时代的背景,当下机器学习大势是在统计学习上的,至于什么是统计学习,什么是符号学习,这个是机器学习的一个发展史相关的东西,可以百度。也就是说我们根据现有的一些数据,通过一些手段来分析,能够得到一个决策的方法,来了一个新的数据我就知道该干什么(这跟我们人类的思维过程是一样的,我们也是小的时候学到了很多东西,后来遇到一件新的事情之后呢我们就能根据以往的经验来做出决策)。

  有监督学习和无监督学习是机器学习中的两个大类,有监督学习是说我给定的一大堆数据,是人为标注好哪些数据属于哪一类的。而无监督学习是指我事先不加以人工干预,单纯凭借这一大批数据来进行一个分类或者说预测。

  k-means算法的大致步骤,这里我用二维坐标系中的点的聚类来形象地表示:

  1)从N个点随机选取K个K作为质心。对于我们的二维坐标系来说,就是随便找K个点(实际上还有一些初始的找质心的算法,比如说你如果三个点紧挨在一起,最终收敛的可能很慢,可能效果不好,这也是机器学习算法的一个普遍特征,他每次运行出来的结果是不一样的,你的初始状态的设定等等会很大程度上影响算法的运行时长、结果等等)
  2)对剩余的每个点测量其到每个质心的距离,并把它归到最近的质心的类。对于我们二维坐标系来说,就是计算欧氏距离即

  (不好意思自己弄得公示有点丑),(x0,y0)即质心。

  3)重新计算已经得到的各个类的质心,即当前已形成了几类,但是我最开始的质心是瞎找的,所以要再次迭代,重新找质心就是计算这个类当中的所有的点的x的平均值,y的平均值,最终得到的新的(x1,y1)就是一个新的质心。
  4)迭代2~3步直至新的质心与原质心相等或小于指定阈值,算法结束。

  从网上贴张图来表示k-means聚类的过程:

  

  这是一种比较形象的聚类。可以看到图中三类点被聚到了3类中。

  那么对于我们项目中的SURF特征点的聚类,实际上和上面提到的二维点聚类是一样的,只不过我们现在是一个64维的坐标系,每一个点是一个64维向量X=(x1,x2,x3,...,x64)

  而计算距离就是变成了。而质心的坐标就是(x10,x20,x30,...,x640)。

  接下来就是建立二叉树的过程了,首先我们有一个根结点。我们对于那么多的特征点利用k-means算法分成两类。那么根结点的左右子树分别是我们分好类的A类和B类。紧接着,对于左右子树,我们分别对A类再分成A1,A2两类作为左子树的左右子树;对B类在分成B1,B2两类作为右子树的左右子树,一直迭代,直到迭代到我们需要的层数。我当时定了32层,于是在叶子节点处就有2^31个叶子节点,即有2^31类。然后对每一个叶子节点给一个符号。现在词汇树就建立完成了。

  接下来就是图像识别。

  现在我的词汇树已经训练完成,那么我要对我数据库里面的10000张图片做一个调整,毕竟图片是没啥东西可以抽取的,我们要转换成别的形式。于是我们数据库里的每一张图,现在我们来走一遍这个二叉树,就能将一张图片转化为一段文本。具体过程:遍历每一个SURF特征点,然后比较和A1,A2类哪个接近(用欧氏距离),假设离A1近,然后再到A1子树里,比较和A1的左子树,A1的右子树哪个近……就这样一直比较到最终的叶子节点,然后就把这个SURF特征点转化为一个符号(也就是一个文字)。接着我么把所有的数据库中的图片全部转化为文字。

  然后我们再进一步转化,可以把一张图转化成一个多维向量!这个利用到文本挖掘里面的一点知识,大家可以自行百度,简单说就是由好多好多文本(每一段文本由不同的符号组成,相当于普通文本,每一段文本由不同的词组成嘛),然后选出一系列具有代表性的词(我们不需要选,因为我们只有2^31个词!那么就能转化成2^31维的向量)。

  紧接着我们拍到了一张新的汽车的图片,我们利用相似的过程将一个新的汽车的图片转化成一个2^31维向量,然后根据已有的数据来匹配,最接近哪些车型?这个过程其实有很多办法,这里不详细展开了,最简单的一种办法就是像刚刚一样计算欧氏距离。

  那么整个识别过程到这里就介绍完了,当中其实还有很多坑,比如说拍的汽车图片,周围是有很多背景的,在提取SURF特征点过程中,如何防止这些无用的背景的干扰,还有可否拍摄视频来识别?等等有很多问题需要解决,也有很多方法,就不在本文中描述了。

初窥图像识别与k-means算法的更多相关文章

  1. KNN 与 K - Means 算法比较

    KNN K-Means 1.分类算法 聚类算法 2.监督学习 非监督学习 3.数据类型:喂给它的数据集是带label的数据,已经是完全正确的数据 喂给它的数据集是无label的数据,是杂乱无章的,经过 ...

  2. js算法初窥05(算法模式02-动态规划与贪心算法)

    在前面的文章中(js算法初窥02(排序算法02-归并.快速以及堆排)我们学习了如何用分治法来实现归并排序,那么动态规划跟分治法有点类似,但是分治法是把问题分解成互相独立的子问题,最后组合它们的结果,而 ...

  3. K-means算法

    K-means算法很简单,它属于无监督学习算法中的聚类算法中的一种方法吧,利用欧式距离进行聚合啦. 解决的问题如图所示哈:有一堆没有标签的训练样本,并且它们可以潜在地分为K类,我们怎么把它们划分呢?  ...

  4. 初窥Kaggle竞赛

    初窥Kaggle竞赛 原文地址: https://www.dataquest.io/mission/74/getting-started-with-kaggle 1: Kaggle竞赛 我们接下来将要 ...

  5. iOS视频直播初窥:高仿<喵播APP>

    视频直播初窥 视频直播,可以分为 采集,前处理,编码,传输, 服务器处理,解码,渲染 采集: iOS系统因为软硬件种类不多, 硬件适配性比较好, 所以比较简单. 而Android端市面上机型众多, 要 ...

  6. 初窥Flask

    初窥Flask Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求 ...

  7. 初窥css---包含一些概念和一些文字样式

    初窥css CSS相关概念 全称是层叠式样式表.规定了html在网页上的显示样式.我们都知道css主要是负责装饰页面的,但是其实在HTML4之前,网页的样式与架构全部都是写在一起的,也是在HTML4之 ...

  8. 机器学习——KNN算法(k近邻算法)

    一 KNN算法 1. KNN算法简介 KNN(K-Nearest Neighbor)工作原理:存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分 ...

  9. 初窥ElasticSearch

    初窥ElasticSearch 官网上面的,不知道讲的是什么.. youtube上面有一个start with,内容是在windows以下跑这个elastic search,然后用一个fidler工具 ...

随机推荐

  1. TCP/IP(七)之玩转HTTP协议

    前言 前面一篇的博文简单的介绍了一下属于应用层的HTTP协议,这一篇我将详细的学习HTTP协议,这也是做Web开发中一定要用到的协议.虽然我是做大数据的,但是多学习一点肯定是 没有坏处的.国庆放假7天 ...

  2. Manacher’s Algorithm (神啊)

    (转载自)http://blog.csdn.net/hopeztm/article/details/7932245 这里描述了一个叫Manacher’s Algorithm的算法. 算法首先将输入字符 ...

  3. HAProxy安装文档

    HAProxy安装文档 [toc][TOC] 一.环境说明 系统环境:CentOS Linux release 7.2.1511 (Core) 系统内核:3.10.0-327.el7.x86_64 软 ...

  4. JavaScript 版数据结构与算法(二)队列

    今天,我们要讲的是数据结构与算法中的队列. 队列简介 队列是什么?队列是一种先进先出(FIFO)的数据结构.队列有什么用呢?队列通常用来描述算法或生活中的一些先进先出的场景,比如: 在图的广度优先遍历 ...

  5. 深入理解C# 静态类与非静态类、静态成员的区别 [转载]

    静态类 静态类与非静态类的重要区别在于静态类不能实例化,也就是说,不能使用 new 关键字创建静态类类型的变量.在声明一个类时使用static关键字,具有两个方面的意义:首先,它防止程序员写代码来实例 ...

  6. 使用Dapper操作Mysql数据库

    首先我想说明一下:相比最原始的ADO.NET,一般都认为封装过一层的ORM性能上会有损耗,但其实在使用中你会发现,当你需要把数据库对象转化为实体模型时,很多所谓的DbHelper其实封装的很低效,反而 ...

  7. (原)怎样解决python dataframe loc,iloc循环处理速度很慢的问题

    怎样解决python dataframe loc,iloc循环处理速度很慢的问题 1.问题说明 最近用DataFrame做大数据 处理,发现处理速度特别慢,追究原因,发现是循环处理时,loc,iloc ...

  8. iOS开发注意事项(一)

    1.OC的消息机制与C++等的函数(方法)有很大的不同,OC在运行时所执行的代码由运行环境来决定,而C++等则由编译器决定.如果调用的函数是多态的,C++在运行时要按照虚方法表来查出到底执行哪个函数, ...

  9. 博客发在win10.me

    看到了http://www.win10.me/?page_id=58 说可以把自己的文章投给win10.me 我试试 抱着没有的心态 居然可以 我联系九幽,和他们说我写了很多博客,质量不好,他们说好 ...

  10. 搭建阿里云 centos mysql tomcat jdk

    [toc] 阿里云使用centos 登录 http://www.aliyun.com/ 点击登录 进入控制 https://home.console.aliyun.com/ 云服务器 运行中 把ip输 ...