【问题标题】:Face recognition in OpenCV Python FAR/FRROpenCV Python FAR/FRR 中的人脸识别
【发布时间】:2012-08-25 05:04:21
【问题描述】:

如何在 OpenCV Python 中进行性能测试来检查;

  1. 获得识别结果所需的时间
  2. 数据库测试用例的错误接受/错误拒绝率。

我正在使用 OpenCV 中的示例特征脸方法(来自 Phillip - https://github.com/bytefish/facerecognition_guide),我只是对结果感兴趣。如果有人能指出我正确的方向/显示示例,那就太好了。也许有一些我可以使用的功能?

【问题讨论】:

    标签: python opencv computer-vision face-recognition


    【解决方案1】:

    This blog对opencv2中的各种特征检测算法做了比较。它是泰语的,所以你可能想使用谷歌浏览器的翻译功能来阅读它,以防你不使用泰语。

    作者没有分享他的代码,但也许您正在寻找类似的东西。

    【讨论】:

      【解决方案2】:

      验证 OpenCV 算法

      简介

      首先很抱歉花了这么长时间才回复,但是根本没有空闲时间。实际上验证算法是一个非常有趣的话题,而且真的没有那么难。在这篇文章中,我将展示如何验证你的算法(我将使用 FaceRecognizer,因为你已经要求它了)。在我的帖子中,我将一如既往地用一个完整的源代码示例来展示它,因为我认为用代码来解释东西要容易得多。

      所以每当人们告诉我“我的算法表现不佳”时,我都会问他们:

      • 究竟什么是
      • 您是通过查看一个样本来评价这个的吗?
      • 您的图像数据是什么?
      • 如何划分训练数据和测试数据?
      • 您的指标是什么?
      • [...]

      我希望这篇文章能消除一些困惑,并展示验证算法是多么容易。因为我从尝试计算机视觉和机器学习算法中学到的是:

      • 如果没有适当的验证,一切都是为了追逐鬼魂。你真的,真的需要数字来谈论。

      本文中的所有代码均采用 BSD 许可证,因此请随时将其用于您的项目。

      验证算法

      任何计算机视觉项目最重要的任务之一就是获取图像数据。您需要在生产中获得与您期望的相同的图像数据,因此您在上线时不会有任何不良体验。一个非常实际的例子:如果你想在野外识别人脸,那么在非常受控的场景中拍摄的图像上验证你的算法是没有用的。获取尽可能多的数据,因为数据为王。那是为了数据。

      一旦您获得了一些数据并编写了算法,就需要对其进行评估。有几种验证策略,但我认为您应该从简单的交叉验证开始,然后从那里继续,有关交叉验证的信息请参阅:

      我们将利用 scikit-learn 一个很棒的开源项目,而不是自己实现这一切:

      它有很好的算法验证文档和教程:

      所以计划如下:

      • 编写一个函数来读取一些图像数据。
      • cv2.FaceRecognizer 包装到 scikit-learn 估计器中。
      • 使用给定的验证和指标估计 cv2.FaceRecognizer 的性能。
      • 利润!

      正确获取图像数据

      首先我想在要读取的图像数据上写一些文字,因为这方面的问题几乎总是会弹出。为简单起见,我在示例中假设图像(面孔您要识别的人)在文件夹中给出。每人一个文件夹。所以假设我有一个文件夹(一个数据集)调用images,子文件夹person1person2 等等:

      philipp@mango:~/facerec/data/images$ tree -L 2 | head -n 20
      .
      |-- person1
      |   |-- 1.jpg
      |   |-- 2.jpg
      |   |-- 3.jpg
      |   |-- 4.jpg
      |-- person2
      |   |-- 1.jpg
      |   |-- 2.jpg
      |   |-- 3.jpg
      |   |-- 4.jpg
      
      [...]
      

      AT&T Facedatabase 是已经采用这种文件夹结构的公共可用数据集之一,可在以下网址获得:

      解压后它看起来像这样(在我的文件系统上它被解压到/home/philipp/facerec/data/at/,你的路径不同!):

      philipp@mango:~/facerec/data/at$ tree .
      .
      |-- README
      |-- s1
      |   |-- 1.pgm
      |   |-- 2.pgm
      [...]
      |   `-- 10.pgm
      |-- s2
      |   |-- 1.pgm
      |   |-- 2.pgm
      [...]
      |   `-- 10.pgm
      |-- s3
      |   |-- 1.pgm
      |   |-- 2.pgm
      [...]
      |   `-- 10.pgm
      
      ...
      
      40 directories, 401 files
      

      把它放在一起

      所以首先我们要定义一个方法read_images 用于读取图像数据和标签:

      import os
      import sys
      import cv2
      import numpy as np
      
      def read_images(path, sz=None):
          """Reads the images in a given folder, resizes images on the fly if size is given.
      
          Args:
              path: Path to a folder with subfolders representing the subjects (persons).
              sz: A tuple with the size Resizes 
      
          Returns:
              A list [X,y]
      
                  X: The images, which is a Python list of numpy arrays.
                  y: The corresponding labels (the unique number of the subject, person) in a Python list.
          """
          c = 0
          X,y = [], []
          for dirname, dirnames, filenames in os.walk(path):
              for subdirname in dirnames:
                  subject_path = os.path.join(dirname, subdirname)
                  for filename in os.listdir(subject_path):
                      try:
                          im = cv2.imread(os.path.join(subject_path, filename), cv2.IMREAD_GRAYSCALE)
                          # resize to given size (if given)
                          if (sz is not None):
                              im = cv2.resize(im, sz)
                          X.append(np.asarray(im, dtype=np.uint8))
                          y.append(c)
                      except IOError, (errno, strerror):
                          print "I/O error({0}): {1}".format(errno, strerror)
                      except:
                          print "Unexpected error:", sys.exc_info()[0]
                          raise
                  c = c+1
          return [X,y]
      

      然后读取图像数据变得像调用一样简单:

      [X,y] = read_images("/path/to/some/folder")
      

      因为某些算法(例如 Eigenfaces、Fisherfaces)要求您的图像大小相同,所以我添加了第二个参数 sz。通过传递元组sz,所有图像都被调整大小。所以下面的调用会将/path/to/some/folder中的所有图像调整为100x100像素。:

      [X,y] = read_images("/path/to/some/folder", (100,100))
      

      scikit-learn 中的所有分类器都派生自 BaseEstimator,它应该有 fitpredict 方法。 fit 方法获取样本列表X 和对应的标签y,因此映射到cv2.FaceRecognizer 的train 方法很简单。 predict 方法还获取样本列表和相应标签,但这次我们需要返回每个样本的预测:

      from sklearn.base import BaseEstimator
      
      class FaceRecognizerModel(BaseEstimator):
      
          def __init__(self):
              self.model = cv2.createEigenFaceRecognizer()
      
          def fit(self, X, y):
              self.model.train(X,y)
      
          def predict(self, T):
              return [self.model.predict(T[i]) for i in range(0, T.shape[0])]
      

      然后,您可以在大量验证方法和指标之间进行选择,以测试 cv2.FaceRecognizer。你可以在sklearn.cross_validation找到可用的交叉验证算法:

      • 留一法交叉验证
      • K 折交叉验证
      • 分层 K 折交叉验证
      • Leave-One-Label-Out 交叉验证
      • 带有替换交叉验证的随机抽样
      • [...]

      为了估计cv2.FaceRecognizer 的识别率,我建议使用分层交叉验证。您可能会问为什么有人需要其他交叉验证方法。想象一下,你想用你的算法进行情绪识别。如果您的训练集包含与您一起测试算法的人的图像,会发生什么?您可能会找到与此人最接近的匹配项,但不会找到与情感最匹配的匹配项。在这些情况下,您应该执行与主题无关的交叉验证。

      使用 scikit-learn 创建分层 k 折交叉验证迭代器非常简单:

      from sklearn import cross_validation as cval
      # Then we create a 10-fold cross validation iterator:
      cv = cval.StratifiedKFold(y, 10)
      

      我们可以选择多种指标。目前我只想知道模型的精度,所以我们导入可调用函数sklearn.metrics.precision_score

      from sklearn.metrics import precision_score
      

      现在我们只需要创建我们的估算器并将estimatorXyprecision_scorecv 传递给cv,它会为我们计算交叉验证分数:

      # Now we'll create a classifier, note we wrap it up in the 
      # FaceRecognizerModel we have defined in this file. This is 
      # done, so we can use it in the awesome scikit-learn library:
      estimator = FaceRecognizerModel()
      # And getting the precision_scores is then as easy as writing:
      precision_scores = cval.cross_val_score(estimator, X, y, score_func=precision_score, cv=cv)
      

      有大量可用的指标,请随意选择另一个:

      所以让我们把所有这些都放在一个脚本中吧!

      验证.py

      ​​>
      # Author: Philipp Wagner <bytefish@gmx.de>
      # Released to public domain under terms of the BSD Simplified license.
      #
      # Redistribution and use in source and binary forms, with or without
      # modification, are permitted provided that the following conditions are met:
      #   * Redistributions of source code must retain the above copyright
      #     notice, this list of conditions and the following disclaimer.
      #   * Redistributions in binary form must reproduce the above copyright
      #     notice, this list of conditions and the following disclaimer in the
      #     documentation and/or other materials provided with the distribution.
      #   * Neither the name of the organization nor the names of its contributors
      #     may be used to endorse or promote products derived from this software
      #     without specific prior written permission.
      #
      #   See <http://www.opensource.org/licenses/bsd-license>
      
      import os
      import sys
      import cv2
      import numpy as np
      
      from sklearn import cross_validation as cval
      from sklearn.base import BaseEstimator
      from sklearn.metrics import precision_score
      
      def read_images(path, sz=None):
          """Reads the images in a given folder, resizes images on the fly if size is given.
      
          Args:
              path: Path to a folder with subfolders representing the subjects (persons).
              sz: A tuple with the size Resizes 
      
          Returns:
              A list [X,y]
      
                  X: The images, which is a Python list of numpy arrays.
                  y: The corresponding labels (the unique number of the subject, person) in a Python list.
          """
          c = 0
          X,y = [], []
          for dirname, dirnames, filenames in os.walk(path):
              for subdirname in dirnames:
                  subject_path = os.path.join(dirname, subdirname)
                  for filename in os.listdir(subject_path):
                      try:
                          im = cv2.imread(os.path.join(subject_path, filename), cv2.IMREAD_GRAYSCALE)
                          # resize to given size (if given)
                          if (sz is not None):
                              im = cv2.resize(im, sz)
                          X.append(np.asarray(im, dtype=np.uint8))
                          y.append(c)
                      except IOError, (errno, strerror):
                          print "I/O error({0}): {1}".format(errno, strerror)
                      except:
                          print "Unexpected error:", sys.exc_info()[0]
                          raise
                  c = c+1
          return [X,y]
      
      class FaceRecognizerModel(BaseEstimator):
      
          def __init__(self):
              self.model = cv2.createFisherFaceRecognizer()
      
          def fit(self, X, y):
              self.model.train(X,y)
      
          def predict(self, T):
              return [self.model.predict(T[i]) for i in range(0, T.shape[0])]
      
      if __name__ == "__main__":
          # You'll need at least some images to perform the validation on:
          if len(sys.argv) < 2:
              print "USAGE: facerec_demo.py </path/to/images> [</path/to/store/images/at>]"
              sys.exit()
          # Read the images and corresponding labels into X and y.
          [X,y] = read_images(sys.argv[1])
          # Convert labels to 32bit integers. This is a workaround for 64bit machines,
          # because the labels will truncated else. This is fixed in recent OpenCV
          # revisions already, I just leave it here for people on older revisions.
          #
          # Thanks to Leo Dirac for reporting:
          y = np.asarray(y, dtype=np.int32)
          # Then we create a 10-fold cross validation iterator:
          cv = cval.StratifiedKFold(y, 10)
          # Now we'll create a classifier, note we wrap it up in the 
          # FaceRecognizerModel we have defined in this file. This is 
          # done, so we can use it in the awesome scikit-learn library:
          estimator = FaceRecognizerModel()
          # And getting the precision_scores is then as easy as writing:
          precision_scores = cval.cross_val_score(estimator, X, y, score_func=precision_score, cv=cv)
          # Let's print them:
          print precision_scores
      

      运行脚本

      上面的脚本将打印出 Fisherfaces 方法的精度分数。您只需要使用图像文件夹调用脚本:

      philipp@mango:~/src/python$ python validation.py /home/philipp/facerec/data/at
      
      Precision Scores:
      [ 1.          0.85        0.925       0.9625      1.          0.9625
        0.8875      0.93333333  0.9625      0.925     ]
      

      结论

      结论是,使用开源项目让您的生活变得非常轻松!示例脚本有很多需要改进的地方。您可能想要添加一些日志记录,例如查看您所在的折叠。但这是评估您想要的任何指标的开始,只需通读 scikit-learn 教程以了解如何执行此操作并使其适应上述脚本。

      我鼓励大家玩转 OpenCV Python 和 scikit-learn,因为如您所见,连接这两个伟大的项目真的非常简单。

      【讨论】:

      • LBP和方法Eigenfaces方法如何得到精度分数?
      【解决方案3】:

      要分析时间性能,您可以使用Time 模块。

      import time
      
      time_1 = time.time()
      result = <execute your code>
      time_2 = time.time()
      duration = time_2 - time_1
      

      关于您的错误率,这实际上取决于您的用例。但是,我通常会保留一个我期望的结果列表,然后将其与我的分类算法返回的结果列表进行比较。然后可以使用它来计算错误率。

      我希望这可以帮助您朝着正确的方向前进。

      【讨论】:

        猜你喜欢
        • 2019-08-10
        • 2017-02-26
        • 2017-02-03
        • 2021-08-16
        • 2018-06-14
        • 2019-05-10
        • 2013-12-24
        • 2020-10-07
        • 1970-01-01
        相关资源
        最近更新 更多