knn计算机视觉 - CSDN
  • 1、图像分类与KNN 1.1 图像分类 1.1.2 图像识别的难点:类内形变+类间相似** 1.1.3 图像识别的途径 1.1.4 机器学习解决图像分类的流程 1.2 最近邻分类器(Nearest Neighbor Classifier) 1.2.1 CIFAR-10 1.2.2 基于...

    1、图像分类与KNN

    1.1 图像分类

    对于一张输入的图像,判定其属于哪个类别,图像分类是计算机视觉的核心问题之一,且是很多高层视觉任务的基础。

    1.1.2 图像识别的难点:类内形变+类间相似**

    • 视角不同,每个事物旋转或者侧视最后的构图都完全不同
    • 尺寸大小不统一,相同内容的图片也可大可小
    • 变形,很多东西处于特殊的情形下,会有特殊的摆放和形状
    • 光影等干扰/幻象
    • 背景干扰
    • 同类内的差异(比如椅子有靠椅/吧椅/餐椅/躺椅…)

    这里写图片描述

    1.1.3 图像识别的途径

    就是对于每个类别,我们都找一定量的图片数据,『喂』给计算机,让它自己去『学习和总结』每一类的图片的特点。

    这里写图片描述

    1.1.4 机器学习解决图像分类的流程

    简单来说,分为三步:

    • 输入:我们的给定K个类别的N张图片,作为计算机学习的训练集
    • 学习:让计算机逐张图片地『观察』和『学习』
    • 评估:就像我们上学学了东西要考试检测一样,我们也得考考计算机学得如何,于是我们给定一些计算机不知道类别的图片让它判别,然后再比对我们已知的正确答案。

    1.2 最近邻分类器(Nearest Neighbor Classifier)

    只是为了从基础推进而已,和卷积网络无关。

    1.2.1 CIFAR-10

    CIFAR-10是一个非常常用的图像分类数据集。数据集包含60000张32*32像素的小图片,每张图片都有一个类别标注(总共有10类),分成了50000张的训练集和10000张的测试集。如下是一些图片示例:
    这里写图片描述

    左图是是个类别和对应的图像示例,右图是给定一张图像之后,根据像素距离计算出来的最近的10张图像。

    1.2.2 基于最近邻的简单图像类别判定

    最近邻的思想:

    根据输入图像的像素值,计算其和训练集中的图像的距离,找到最近的图像的类别作为预测的类别即可。

    最近邻的缺点:

    用于图像分类时效果很差。

    距离度量方式:

    L1距离,L2距离,余弦距离等等(scipy

    1.3 k近邻分类器

    将最近邻扩展为最近的N个临近点,然后统计出现类别最多的那一类作为预测的类别。

    1.3.1 交叉验证与参数选择

    哪些因素会影响KNN最后的识别结果:

    • 距离度量方式
    • k值的选取

    当数据总量不大的时候,可以选择k折交叉验证,也就是将原始数据分为k份,轮流使用其中k-1份作为训练数据,剩下的1份作为交叉验证数据,我们可以得到k个准确率,取均值作为预测准确率。

    1.3.2 kNN算法的优缺点

    优点:

    思路简单,不需训练

    缺点:

    • 计算准确率过程很耗时,因为要和全部训练集中的图像都对比一遍;
    • 分类器必须记住全部的训练数据,因为要遍历找近邻,而任何实际的图像训练集上,数据量很可能非常大,那么一次性载入内存,不管是对速度还是对硬件的要求,都是一个极大的挑战。

    重要的是:我们不是很在乎训练时间,训练时间长的话,只有后续识别的时候速度快,效果好即可,但是kNN测试过程很漫长,后续的深度神经网络就是为了解决该问题,其训练时间长,但是识别过程很快。

    这里写链接内容

    展开全文
  • OCR应用非常广泛,而且有许多方法,今天用KNN算法实现简单的0-9手写数字识别。 KNN算法是K近邻分类算法,属于机器学习中的监督学习,需要一定量的带标签的输入样本数据进行“训练”,然后就可以识别。我给“训练”...

    OCR应用非常广泛,而且有许多方法,今天用KNN算法实现简单的0-9手写数字识别。本程序使用OpenCV 3.0和Python 3。


    KNN算法是K近邻分类算法,属于机器学习中的监督学习,需要一定量的带标签的输入样本数据进行“训练”,然后就可以识别。我给“训练”打引号是因为其实KNN没有明显的前期训练过程,它是要给一个样本x分类,就从数据集中在x附近找离它最近的k各数据点,这k个数据点中包含的y类别最多,那么就把x的标签标记为y,这就完成了分类识别的过程。


    首先,利用OpenCV自带的手写数字样本集digits.png来进行初始训练:



    def initKnn():
        knn = cv2.ml.KNearest_create()
        img = cv2.imread('digits.png')
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]
        train = np.array(cells).reshape(-1,400).astype(np.float32)
        trainLabel = np.repeat(np.arange(10),500)
        return knn, train, trainLabel
    
    这是总共5000个数据,0-9各500个,我们读入图片后整理数据,这样得到的train和trainLabel依次对应,图像数据和标签。


    def updateKnn(knn, train, trainLabel, newData=None, newDataLabel=None):
        if newData != None and newDataLabel != None:
            print(train.shape, newData.shape)
            newData = newData.reshape(-1,400).astype(np.float32)
            train = np.vstack((train,newData))
            trainLabel = np.hstack((trainLabel,newDataLabel))
        knn.train(train,cv2.ml.ROW_SAMPLE,trainLabel)
        return knn, train, trainLabel
    
    updateKnn是增加自己的训练数据后更新Knn的操作。


    def findRoi(frame, thresValue):
        rois = []
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        gray2 = cv2.dilate(gray,None,iterations=2)
        gray2 = cv2.erode(gray2,None,iterations=2)
        edges = cv2.absdiff(gray,gray2)
        x = cv2.Sobel(edges,cv2.CV_16S,1,0)
        y = cv2.Sobel(edges,cv2.CV_16S,0,1)
        absX = cv2.convertScaleAbs(x)
        absY = cv2.convertScaleAbs(y)
        dst = cv2.addWeighted(absX,0.5,absY,0.5,0)
        ret, ddst = cv2.threshold(dst,thresValue,255,cv2.THRESH_BINARY)
        im, contours, hierarchy = cv2.findContours(ddst,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        for c in contours:
            x, y, w, h = cv2.boundingRect(c)
            if w > 10 and h > 20:
                rois.append((x,y,w,h))
        return rois, edges
    
    findRoi函数是找到每个数字的位置,用包裹其最小矩形的左上顶点的坐标和该矩形长宽表示(x, y, w, h)。这里还用到了Sobel算子。edges是原始图像形态变换之后的灰度图,可以排除一些背景的影响,比如本子边缘、纸面的格子、手、笔以及影子等等,用edges来获取数字图像效果比Sobel获取的边界效果要好。

    def findDigit(knn, roi, thresValue):
        ret, th = cv2.threshold(roi, thresValue, 255, cv2.THRESH_BINARY)
        th = cv2.resize(th,(20,20))
        out = th.reshape(-1,400).astype(np.float32)
        ret, result, neighbours, dist = knn.findNearest(out, k=5)
        return int(result[0][0]), th
    
    findDigit函数是用KNN来分类,并将结果返回。th是用来手动输入训练数据时显示的图片。20x20pixel的尺寸是OpenCV自带digits.png中图像尺寸,因为我是在其基础上更新数据,所以沿用这个尺寸。


    def concatenate(images):
        n = len(images)
        output = np.zeros(20*20*n).reshape(-1,20)
        for i in range(n):
            output[20*i:20*(i+1),:] = images[i]
        return output
    
    concatenate函数是拼接数字图像并显示的,用来输入训练数据。


    while True:
        ret, frame = cap.read()
        frame = frame[:,:426]
        rois, edges = findRoi(frame, 50)
        digits = []
        for r in rois:
            x, y, w, h = r
            digit, th = findDigit(knn, edges[y:y+h,x:x+w], 50)
            digits.append(cv2.resize(th,(20,20)))
            cv2.rectangle(frame, (x,y), (x+w,y+h), (153,153,0), 2)
            cv2.putText(frame, str(digit), (x,y), cv2.FONT_HERSHEY_SIMPLEX, 1, (127,0,255), 2)
        newEdges = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
        newFrame = np.hstack((frame,newEdges))
        cv2.imshow('frame', newFrame)
        videoFrame.write(newFrame)
        key = cv2.waitKey(1) & 0xff
        if key == ord(' '):
            break
        elif key == ord('x'):
            Nd = len(digits)
            output = concatenate(digits)
            showDigits = cv2.resize(output,(60,60*Nd))
            cv2.imshow('digits', showDigits)
            cv2.imwrite(str(count)+'.png', showDigits)
            count += 1
            if cv2.waitKey(0) & 0xff == ord('e'):
                pass
            print('input the digits(separate by space):')
            numbers = input().split(' ')
            Nn = len(numbers)
            if Nd != Nn:
                print('update KNN fail!')
                continue
            try:
                for i in range(Nn):
                    numbers[i] = int(numbers[i])
            except:
                continue
            knn, train, trainLabel = updateKnn(knn, train, trainLabel, output, numbers)
            print('update KNN, Done!')
    
    这是主函数循环部分,按“x”键会暂停屏幕并显示获取的数字图像,按“e”键会提示输入看到的数字,在终端输入数字用空格隔开,按回车如果显示“update KNN, Done!”则完成一次更新。下面是我用20多组0-9数字更新训练后得到的结果:




    height="540" width="960" src="http://static.hdslb.com/miniloader.swf?aid=4904541&page=1" frameborder="0" allowfullscreen="">

    演示视频:http://www.bilibili.com/video/av4904541/

    完整代码:https://github.com/littlethunder/digitsOCR


    转载请注明:转自http://blog.csdn.net/littlethunder/article/details/51615237


    展开全文
  • 很有用 可运行 KNN学习算法实现,演示回归算法算法在计算机视觉中的应用 ,实现如何利用偏最小二乘回归模型实现数据拟合
  • 应用场景也非常之多,它的重要性还体现在,其实其他的一些计算机视觉的问题(比如说物体识别、图像内容分割等)都可以基于它去完成。举个例子说说这个问题哈。 计算机拿到如下的一张图片,然后需要给出它对应{猫,狗...

    作者: 寒小阳
    时间:2015年11月。
    出处:http://blog.csdn.net/han_xiaoyang/article/details/49949535
    声明:版权所有,转载请注明出处,谢谢

    1. 图像分类问题

    这是人每天自然而然会做的事情,普通到大部分时候,我们都感知不到我们在完成一个个这样的任务。早晨起床洗漱,你要看看洗漱台一堆东西中哪个是杯子,哪个是你的牙刷;吃早餐的时候你要分辨食物和碗碟…
    抽象一下,对于一张输入的图片,要判定它属于给定的一些标签/类别中的哪一个。看似很简单的一个问题,这么多年却一直是计算机视觉的一个核心问题,应用场景也很多。它的重要性还体现在,其实其他的一些计算机视觉的问题(比如说物体定位和识别、图像内容分割等)都可以基于它去完成。

    咱们举个例子从机器学习的角度描述一下这个问题^_^

    计算机拿到一张图片(如下图所示),然后需要给出它对应{猫,狗,帽子,杯子}4类的概率。人类是灰常牛逼的生物,我们一瞥就知道这货是猫。然而对计算机而言,他们是没办法像人一样『看』到整张图片的。对它而言,这是一个3维的大矩阵,包含248*400个像素点,每个像素点又有红绿蓝(RGB)3个颜色通道的值,每个值在0(黑)-255(白)之间,计算机就需要根据这248*400*3=297600个数值去判定这货是『猫』

    猫图像=>矩阵

    1.1 图像识别的难点

    图像识别看似很直接。但实际上包含很多挑战,人类可是经过数亿年的进化才获得如此强大的大脑,对于各种物体有着精准的视觉理解力。总体而言,我们想『教』会计算机去认识一类图,会有下面这样一些困难:

    • 视角不同,每个事物旋转或者侧视最后的构图都完全不同
    • 尺寸大小不统一,相同内容的图片也可大可小
    • 变形,很多东西处于特殊的情形下,会有特殊的摆放和形状
    • 光影等干扰/幻象
    • 背景干扰
    • 同类内的差异(比如椅子有靠椅/吧椅/餐椅/躺椅…)

    图像面临的挑战

    1.2 识别的途径

    首先,大家想想就知道,这个算法并不像『对一个数组排序』或者『求有向图的最短路径』,我们没办法提前制定一个流程和规则去解决。定义『猫』这种动物本身就是一件很难的事情了,更不要说去定义一只猫在图像上的固定表现形式。所以我们寄希望于机器学习,使用『Data-driven approach/数据驱动法』来做做尝试。简单说来,就是对于每个类别,我们都找一定量的图片数据,『喂』给计算机,让它自己去『学习和总结』每一类的图片的特点。对了,这个过程和小盆友学习新鲜事物是一样一样的。『喂』给计算机学习的图片数据就和下图的猫/狗/杯子/帽子一样:

    Data-driven approach

    1.3 机器学习解决图像分类的流程/Pipeline

    整体的流程和普通机器学习完全一致,简单说来,也就下面三步:

    • 输入:我们的给定K个类别的N张图片,作为计算机学习的训练集
    • 学习:让计算机逐张图片地『观察』和『学习』
    • 评估:就像我们上学学了东西要考试检测一样,我们也得考考计算机学得如何,于是我们给定一些计算机不知道类别的图片让它判别,然后再比对我们已知的正确答案。

    2. 最近邻分类器(Nearest Neighbor Classifier)

    先从简单的方法开始说,先提一提最近邻分类器/Nearest Neighbor Classifier,不过事先申明,它和深度学习中的卷积神经网/Convolutional Neural Networks其实一点关系都没有,我们只是从基础到前沿一点一点推进,最近邻是图像识别一个相对简单和基础的实现方式。

    2.1 CIFAR-10

    CIFAR-10是一个非常常用的图像分类数据集。数据集包含60000张32*32像素的小图片,每张图片都有一个类别标注(总共有10类),分成了50000张的训练集和10000张的测试集。如下是一些图片示例:

    CIFAR-10例子

    上图中左边是十个类别和对应的一些示例图片,右边是给定一张图片后,根据像素距离计算出来的,最近的10张图片。

    2.2 基于最近邻的简单图像类别判定

    假如现在用CIFAR-10数据集做训练集,判断一张未知的图片属于CIFAR-10中的哪一类,应该怎么做呢。一个很直观的想法就是,既然我们现在有每个像素点的值,那我们就根据输入图片的这些值,计算和训练集中的图片距离,找最近的图片的类别,作为它的类别,不就行了吗。

    恩,想法很直接,这就是『最近邻』的思想。偷偷说一句,这种直接的做法在图像识别中,其实效果并不是特别好。比如上图是按照这个思想找的最近邻,其实只有3个图片的最近邻是正确的类目。

    即使这样,作为最基础的方法,还是得掌握,我们来简单实现一下吧。我们需要一个图像距离评定准则,比如最简单的方式就是,比对两个图像像素向量之间的l1距离(也叫曼哈顿距离/cityblock距离),公式如下:

    d1(I1,I2)=pIp1Ip2

    其实就是计算了所有像素点之间的差值,然后做了加法,直观的理解如下图:

    矩阵的l1距离

    我们先把数据集读进内存:

    #! /usr/bin/env python
    #coding=utf-8
    import os
    import sys
    import numpy as np
    
    def load_CIFAR_batch(filename):
        """
        cifar-10数据集是分batch存储的,这是载入单个batch
    
        @参数 filename: cifar文件名
        @r返回值: X, Y: cifar batch中的 data 和 labels
        """
    
        with open(filename, 'r') as f:
            datadict=pickle.load(f)
    
            X=datadict['data']
            Y=datadict['labels']
    
            X=X.reshape(10000, 3, 32, 32).transpose(0,2,3,1).astype("float")
            Y=np.array(Y)
    
            return X, Y
    
    
    def load_CIFAR10(ROOT):
        """
        读取载入整个 CIFAR-10 数据集
    
        @参数 ROOT: 根目录名
        @return: X_train, Y_train: 训练集 data 和 labels
                 X_test, Y_test: 测试集 data 和 labels
        """
    
        xs=[]
        ys=[]
    
        for b in range(1,6):
            f=os.path.join(ROOT, "data_batch_%d" % (b, ))
            X, Y=load_CIFAR_batch(f)
            xs.append(X)
            ys.append(Y)
    
        X_train=np.concatenate(xs)
        Y_train=np.concatenate(ys)
    
        del X, Y
    
        X_test, Y_test=load_CIFAR_batch(os.path.join(ROOT, "test_batch"))
    
        return X_train, Y_train, X_test, Y_test
    
    # 载入训练和测试数据集
    X_train, Y_train, X_test, Y_test = load_CIFAR10('data/cifar10/') 
    # 把32*32*3的多维数组展平
    Xtr_rows = X_train.reshape(X_train.shape[0], 32 * 32 * 3) # Xtr_rows : 50000 x 3072
    Xte_rows = X_test.reshape(X_test.shape[0], 32 * 32 * 3) # Xte_rows : 10000 x 3072

    下面我们实现最近邻的思路:

    class NearestNeighbor:
      def __init__(self):
        pass
    
      def train(self, X, y):
        """ 
        这个地方的训练其实就是把所有的已有图片读取进来 -_-||
        """
        # the nearest neighbor classifier simply remembers all the training data
        self.Xtr = X
        self.ytr = y
    
      def predict(self, X):
        """ 
        所谓的预测过程其实就是扫描所有训练集中的图片,计算距离,取最小的距离对应图片的类目
        """
        num_test = X.shape[0]
        # 要保证维度一致哦
        Ypred = np.zeros(num_test, dtype = self.ytr.dtype)
    
        # 把训练集扫一遍 -_-||
        for i in xrange(num_test):
          # 计算l1距离,并找到最近的图片
          distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1)
          min_index = np.argmin(distances) # 取最近图片的下标
          Ypred[i] = self.ytr[min_index] # 记录下label
    
        return Ypred
    
    nn = NearestNeighbor() # 初始化一个最近邻对象
    nn.train(Xtr_rows, Y_train) # 训练...其实就是读取训练集
    Yte_predict = nn.predict(Xte_rows) # 预测
    # 比对标准答案,计算准确率
    print 'accuracy: %f' % ( np.mean(Yte_predict == Y_test) )

    最近邻的思想在CIFAR上得到的准确度为38.6%,我们知道10各类别,我们随机猜测的话准确率差不多是1/10=10%,所以说还是有识别效果的,但是显然这距离人的识别准确率(94%)实在是低太多了,不那么实用。

    2.3 关于最近邻的距离准则

    我们这里用的距离准则是l1距离,实际上除掉l1距离,我们还有很多其他的距离准则。

    • 比如说l2距离(也就是大家熟知的欧氏距离)的计算准则如下:

    d2(I1,I2)=p(Ip1Ip2)2
    • 比如余弦距离计算准则如下:

    1I1I2||I1||||I2||

    更多的距离准则可以参见scipy相关计算页面.

    3. K最近邻分类器(K Nearest Neighbor Classifier)

    这是对最近邻的思想的一个调整。其实我们在使用最近邻分类器分类,扫描CIFAR训练集的时候,会发现,有时候不一定距离最近的和当前图片是同类,但是最近的一些里有很多和当前图片是同类。所以我们自然而然想到,把最近邻扩展为最近的N个临近点,然后统计一下这些点的类目分布,取最多的那个类目作为自己的类别。

    恩,这就是KNN的思想。

    KNN其实是一种特别常用的分类算法。但是有个问题,我们的K值应该取多少呢。换句话说,我们找多少邻居来投票,比较靠谱呢?

    3.1 交叉验证与参数选择

    在现在的场景下,假如我们确定使用KNN来完成图片类别识别问题。我们发现有一些参数是肯定会影响最后的识别结果的,比如:

    • 距离的选择(l1,l2,cos等等)
    • 近邻个数K的取值。

    每组参数下其实都能产生一个新的model,所以这可以视为一个模型选择/model selection问题。而对于模型选择问题,最常用的办法就是在交叉验证集上实验。

    数据总量就那么多,如果我们在test data上做模型参数选择,又用它做效果评估,显然不是那么合理(因为我们的模型参数很有可能是在test data上过拟合的,不能很公正地评估结果)。所以我们通常会把训练数据分为两个部分,一大部分作为训练用,另外一部分就是所谓的cross validation数据集,用来进行模型参数选择的。比如说我们有50000训练图片,我们可以把它分为49000的训练集和1000的交叉验证集。

    # 假定已经有Xtr_rows, Ytr, Xte_rows, Yte了,其中Xtr_rows为50000*3072 矩阵
    Xval_rows = Xtr_rows[:1000, :] # 构建1000的交叉验证集
    Yval = Ytr[:1000]
    Xtr_rows = Xtr_rows[1000:, :] # 保留49000的训练集
    Ytr = Ytr[1000:]
    
    # 设置一些k值,用于试验
    validation_accuracies = []
    for k in [1, 3, 5, 7, 10, 20, 50, 100]:
    
      # 初始化对象
      nn = NearestNeighbor()
      nn.train(Xtr_rows, Ytr)
      # 修改一下predict函数,接受 k 作为参数
      Yval_predict = nn.predict(Xval_rows, k = k)
      acc = np.mean(Yval_predict == Yval)
      print 'accuracy: %f' % (acc,)
    
      # 输出结果
      validation_accuracies.append((k, acc))

    这里提一个在很多地方会看到的概念,叫做k-fold cross-validation,意思其实就是把原始数据分成k份,轮流使用其中k-1份作为训练数据,而剩余的1份作为交叉验证数据(因此其实对于k-fold cross-validation我们会得到k个accuracy)。以下是5-fold cross-validation的一个示例:

    k-fold 交叉验证

    以下是我们使用5-fold cross-validation,取不同的k值时,得到的accuracy曲线(补充一下,因为是5-fold cross-validation,所以在每个k值上有5个取值,我们取其均值作为此时的准确度)

    5-fold 交叉验证

    可以看出大概在k=7左右有最佳的准确度。

    3.2 最近邻方法的优缺点

    K最近邻的优点大家都看出来了,思路非常简单清晰,而且完全不需要训练…不过也正因为如此,最后的predict过程非常耗时,因为要和全部训练集中的图片比对一遍。

    实际应用中,我们其实更加关心实施predict所消耗的时间,如果有一个图像识别app返回结果要半小时一小时,你一定第一时间把它卸了。我们反倒不那么在乎训练时长,训练时间稍微长一点没关系,只要最后应用的时候识别速度快效果好,就很赞。后面会提到的深度神经网络就是这样,深度神经网络解决图像问题时训练是一个相对耗时间的过程,但是识别的过程非常快。

    另外,不得不多说一句的是,优化计算K最近邻时间问题,实际上依旧到现在都是一个非常热门的问题。Approximate Nearest Neighbor (ANN)算法是牺牲掉一小部分的准确度,而提高很大程度的速度,能比较快地找到近似的K最近邻,现在已经有很多这样的库,比如说FLANN.

    最后,我们用一张图来说明一下,用图片像素级别的距离来实现图像类别识别,有其不足之处,我们用一个叫做t-SNE的技术把CIFAR-10的所有图片按两个维度平铺出来,靠得越近的图片表示其像素级别的距离越接近。然而我们瞄一眼,发现,其实靠得最近的并不一定是同类别的。

    像素级别图像距离排列

    其实观察一下,你就会发现,像素级别接近的图片,在整张图的颜色分布上,有很大的共性,然而在图像内容上,有时候也只能无奈地呵呵嗒,毕竟颜色分布相同的不同物体也是非常多的。

    参考资料与原文

    cs231n 图像分类与KNN

    展开全文
  • 本导论主要介绍了图像分类问题及数据驱动方法。图像分类问题 image classification图像的分类问题简单来说就是对选择一个给定label的过程。如下图: 此图片为248×400像素的图片,对电脑来说他是一个248 x 400 x ...

    本导论主要介绍了图像分类问题及数据驱动方法。

    图像分类问题 image classification

    图像的分类问题简单来说就是对选择一个给定label的过程。如下图:
    这里写图片描述
    此图片为248×400像素的图片,对电脑来说他是一个248 x 400 x 3的3维数组,其中的3代表红绿蓝三色通道(这里文中默认是使用RGB格式),假设我们设定,这幅图片的label有四种可能,cat、dog、hat、mug,对他的分类就是通过这248 x 400 x 3=297,600个数字得出其中的一个标签比如cat。这与其他分类过程是相似的。

    分类的挑战性

    但是与机器学习中其他的分类问题不同是,图像分类还有许多的挑战,主要表现在以下几部分:
    1. 视角的变化viewpoint variation,同一个物体在不同的视角下会有不同的表现,而视角的变化可以说是无穷多的。
    2. 比例的变化scale variation ,比如同样是一个字,四号字体,和一号字体他们对应的比例是不同的。
    3. 变形deformation,很多物体并非刚性,往往在不同时刻有不一样的展现形式,比如站着的人与坐着的人都是一个人,但是形状已经变了。
    4. 遮挡occulsion,现实中的图片往往不是以此排列展开的,彼此遮挡的时候很多.
    5. 光照变化 illumination condations,光照的角度不同往往会造成图片中物体的数值形式的差异。
    6. 背景的影响 background clutter. 有时候图片的背景与目标物体很接近不易分辨,比如变色龙.
    7. 概念的复杂性 intra-class variation,一个概念下往往会对应不同的物体,比如label为car的图片可能包含各种各样的汽车。
    下图是上面概念的展示:
    这里写图片描述
    显示中这些不定的变化往往会同时出现,造成了识别的困难,一个比较好的分类法方法应该对上面面临的变化有一定的鲁棒性。

    数据驱动方法

    学过机器学习的对于这个概念应该比较容易理解,我们不会直接告诉电脑如何去分类,(其实我们也不知道如何写一段程序直接告诉电脑该如何对图片进行分类)我们要做的就是给电脑一些包含标签与图片的样例,让电脑自己学习如何分类,这里成这种依靠训练数据的方法为data-driven approach,如下图,我们给电脑数以千计的图片,每类图片都包含数以万计张不同的图片,让电脑学习:
    这里写图片描述

    图像分类流程

    完整的图像分类流程如下:
    1. 输入 input :输入n张包含一类标签的图片,这也是训练数据集。
    2. 学习Learning:使用上面的训练数据,进行学习,得到这类标签对应的模型,这也叫训练一个分类器。
    3. 评估 evaluation: 最后我们用其他的新图片和测试评估得到的分类器的效果,当让我们希望它的预测结果中有大多数与与真实结果(ground truth)相同。

    最近邻分类器 nearest neighbor classifier

    我们首先使用的方法是nearest neighbor,他与convolutional neural network没有啥关系,只是用来让我们明白什么叫做图片分类。

    我们使用数据集是CIFAR-10,他是由5w张训练图片和1w张测试图片组成,一共6w张10类玩具图片。
    所谓nearest neighbor就是比较图片之间的差别大小,认为差别小的就是一类,其中一种简单的方法就是计算每个像素之间的差别然后将所有的差别相加,可以用l1距离或者l2距离来衡量像素之间的差别,设输入数据为向量I1,待测试数据为向量I2。L1距离公式为:
    这里写代码片
    它的含义是计算每个像素间的l1范数然后相加,形象化如下:
    这里写图片描述
    上面图片的差别是456,如果该待测试数据与所有的已知数据中的距离最小就是456,那么我们就认为他是与该已知的训练数图片最相似。
    这种分类方法并不理想,文中说其测试结果为38.6%的测试结果正确,这与人类的识别能力(94%左右)相差甚远,而卷积神经网络能达到95%左右的精确度,而如果我们采取l2范数的方法来测试,得到的结果仅仅是35.4%,更低一点点,l2方法的公式是:
    这里写图片描述
    其他步骤与l1相同。
    L2对大差距更为敏感如下例:
    如三个向量分别为【2、3、4、1】【2、3、4、9】 【6、7、4、1】,测试第一个向量与另外两个的差距
    l1结果为9-1=8 和6-2+7-3=8
    l2结果为8=6416+16=32
    说明如果用l1范数来计算两者差距时认为后面的两个向量与第一个差不多,但是l2认为虽然第二个与第一个仅有一个值不同但是其值差距较大,所以认为第三个比第二个更像第一个。

    KNN分类器

    knn叫作k-nearest neighbor,他与nearest neighbor的区别就是不仅仅一看最接近的一个,而是取前k个最接近的,投票,比如与待测试图片想四的前5个图片的label分别是cat cat dog cat dog,那么我们就认为他是cat。
    但是k到底选几好呢?我们可以使用验证(validation)的方法

    Validation sets for Hyperparameter tuning 验证集参数调优

    使用knn时我们需要知道k等于几的时候得到的值最好,或者使用l1还l2的效果比较好,如何得到我们想要的这些参数的值呢?首先要注意的是我们不能使用测试集来比较各个值的好处,因为现实生活中测试集是我们无法得到的,另外如果使用测试集得到的参数在应用的时候并不好,这也许就是造成了过拟合,过度的与测试集的数据拟合了。应该记住,测试集只能够作为最后的测试用,不能用来调整参数。
    我们常使用调整参数的方法之一就是使用验证集validation sets来调优,以CIFAR-10为例:我们可以将50000个训练集人为划分为49000个训练集和1000个验证集,使用49000个训练集来训练模型用这1000个来查看不同参数时模型的表现,选择表现最好的模型。
    如果你认为一个验证集数量太小可能不具有代表性,那么可以使用更科学的交叉验证的方法,交叉验证是将训练集分为n部分,然后每一部分都以此作为验证集来观察结果,例如将50000化为10fold,每次用一部分得到不同k值时的结果,最后对于每一个k值都可以得到10个准确度,可以使用其平均值最为最中的衡量标准,选择最好的k值。下图是将数据分为5部分后得到的不同k值的结果:
    这里写图片描述
    可以看出在k=7左右时精确度最高因此选择k等于7.

    Pros and Cons of nearest neighbor nn方法的优缺点分析

    由上面的介绍可以看到nearest neighbor的优点就是容易理解,容易实施,不用训练,但是在计算测试结果的时候需要将每一个结果与训练数据分别匹配计算,非常耗时但是我们一般在应用时需要较快的对目标图片进行判断分类,而我们后面将学到的深度神经网络虽然训练时间很长但是其应用时可以非常快的进行分类操作。
    As an aside, 顺便说一句,很多人也在对nearest neighbor 的计算复杂度进行研究, 一些 Approximate Nearest Neighbor (ANN) 算法和数据库可以用来加速计算比如 FLANN).这些算法会对计算的精确度和检索的复杂度做一些权衡,通常会用些预处理比如建立 kdtree, 或者先进行聚类等(如 k-means algorithm)。

    Nearest Neighbor Classifier 有时候在低纬度的一些数据集中表现较好,但是一般不适用于与图像的分类 ,他只对图像的颜色或者背景的值比较感兴趣,并不关注图像中的内容,比如下图的人像,在变换之后人还是一样的人可是用nearest neighbor得到的结果却相差很多:
    这里写图片描述
    为了更加突出表现使用像素间的差异不能用于很好的表现图片之间的差异,文中用t-SNE来将不同图片使用像素差异(l2)表现在下图中:
    这里写图片描述
    可见相似的图片主要是主色调和背景的相似,而不是图片中内容的相似。比如红色的车和在红色背景下的马被判断为相似。
    由此看见利用像素间的区别来区分图片的类别的效果并不好。下节中我们会学习到一个准确度为90%左右,分类迅速的分类器。

    Applying kNN in practice

    knn的运用流程:
    1. 预处理: 将特征标准化为均值为0,标准差为1的数据.
    2. 降维,例如使用pca
    3. 随机划分验证集
    4. 保证训练数据在70%-90%左右. 使用交叉验证的时候越多folds 越好, 但是越 expensive.
    5. 使用验证集选择参数和distance types (L1 and L2 are good candidates)
    6. 如果knn花费时间比较长尝试使用FLANN等工具箱加速运算,但是可能会牺牲精确度。
    7. 使用最佳参数在全部的数据集上训练,在test set上测试。

    总结


    这里写图片描述

    展开全文
  • 文章目录概述KNN算法原理KNN二维分类器模型DSIFT手势识别应用手势识别具体流程 概述 本文介绍了KNN算法的基本原理,以及配合dfift(稠密sift)进行一个手势识别方面的应用 KNN算法原理 KNN算法(K-Nearest ...
  • 计算机视觉入门培训

    2020-04-22 13:55:27
    计算机视觉入门培训 引入 计算机视觉的基本概念 计算机视觉五大技术 计算机视觉主要应用领域 计算机视觉落地场景 一、引入 二、计算机视觉的基本概念 What? 计算机视觉的概念 计算机视觉是使用计算机及相关...
  • KNN算法原理: KNN(k-nearest neighbor)是一个简单而经典的机器学习分类算法,通过度量”待分类数据”和”类别已知的样本”的距离(通常是欧氏距离)对样本进行分类。 这话说得有些绕口,且来分解一番: (1)...
  • 之前为了熟悉机器学习的东西去搞kaggle的东西,然后就从Titanic入门咯,结果发现并没有对机器学习的东西有深入的理解,做数据挖掘的时候直接调用sklearn里面的框架,根本不用去想机器学习的公式的运用和基础的实现,...
  • 1. 图像分类问题 这是人每天自然而然会做的事情,普通到大部分时候,我们都感知不到我们在完成一个个这样的任务。早晨起床洗漱,你要看看洗漱台一堆东西中哪个是杯子,哪个是你的牙刷;
  • 计算机视觉 一、原理1.K邻近分类法(KNN)2.稠密SIFT(Dense SIFT) 一、原理 1.K邻近分类法(KNNKNN算法是分类算法中最典型最容易实现的算法 工作原理:存在一个样本数据集合,也称为训练样本集,并且样本...
  • 一、MNIST手写数字介绍 1、获取样本 手写数字的MNIST数据库可从此页面获得,其中包含60,000个示例的训练集以及10,000个示例的测试集。它是NIST提供的更大集合的子集。这些数字已经过尺寸标准化并以固定尺寸的图像为...
  • 课程由哈尔滨工业大学副教授,视觉技术研究室负责人屈教授讲解。由浅入深,图文并茂,在讲述概念的同时注重和实际系统结合,为上手并深入研究无人驾驶,智能机器人,人机交互,医疗等行业应用奠定坚实基础。
  • 一、K邻近分类法(KNN) 1.1 knn算法概述 1.2knn算法基本思想 1.3 knn算法方法 1.4 knn算法步骤 二、实现代码及结果分析 2.1 knn 2.2 二维示例 2.3 图像特征-稠密SIFT 2.4 图像分类:手势识别 一、K邻近...
  • 计算机视觉综述:cs231n_2018_lecture01 观看视频p1和p2热身,了解计算机视觉概述以及历史背景。观看p3了解整门课程的大纲。   学习数据驱动的方法和KNN算法和线性分类器[上]:cs231n_2018_lecture02 观看视频...
  • 计算机视觉(一)

    2018-09-01 20:44:18
    计算机视觉的一个难题:无论是拍照的角度、光线,形态变化、有无遮挡等等的因素,人都能很容易的识别出图片的目标,但对于计算机来说,这是一件很困难的事情。 k近邻法 1、距离度量选择: 前者会被坐标轴的...
  • 经过一系列的计算机视觉的公开课视频的学习,回归到本课的最初应用,就是实现对于十类图像的图像分类。之前的Assignment 已经通过knn和svm做过基础的分析。这里我们通过卷积神经网络来实现。首先我们下载cs231n提供...
  • CS231设计为以计算机视觉解决实现图像分类问题和数据驱动方法的入门课程,课程内容如下: 图像分类,数据驱动方法,流水线介绍 临近分类器/K-NN验证集,交叉验证,超参数调整最近邻居的优点/缺点概要总结:KNN在...
  • 文章目录KNN算法原理Dense-sift(稠密SIFT)贝斯算法代码实现KNN算法实现稠密SIFT可视化图像分类:手势识别 实现问题解决 KNN算法原理 参考博客:https://blog.csdn.net/jmydream/article/details/8644004 kNN...
1 2 3 4 5 ... 20
收藏数 3,542
精华内容 1,416
热门标签
关键字:

knn计算机视觉