如何在OpenCV Python中进行性能测试以检查:
- 获取识别结果所需的时间
- 数据库测试用例中的错误接受/错误拒绝率。
我正在使用OpenCV中的示例特征脸方法(来自Phillip-https://github.com/bytefish/facerecognition_guide),只对结果感兴趣。如果有人能指点我正确的方向/展示示例,我将不胜感激。也许有一些函数可以使用?
如何在OpenCV Python中进行性能测试以检查:
我正在使用OpenCV中的示例特征脸方法(来自Phillip-https://github.com/bytefish/facerecognition_guide),只对结果感兴趣。如果有人能指点我正确的方向/展示示例,我将不胜感激。也许有一些函数可以使用?
首先很抱歉回复晚了,但是实在没有多余的时间。实际上验证算法是一个非常有趣的话题,而且并不难。在本文中,我将展示如何验证你的算法(我将以人脸识别器为例,因为你提出了这个问题)。像往常一样,在我的文章中,我会通过完整的源代码示例来展示,因为我认为通过代码更容易解释事情。
所以每当有人告诉我“我的算法表现不佳”时,我会问他们:
我希望本文能够澄清一些困惑,并展示验证算法有多容易。因为我从尝试计算机视觉和机器学习算法中学到的是:
本文中的所有代码都采用BSD许可证,所以请随意在你的项目中使用。
任何计算机视觉项目中最重要的任务之一是获取图像数据。你需要获得与实际生产中预期相同的图像数据,这样当你上线时就不会遇到任何问题了。一个非常实际的例子:如果你想在野外识别人脸,那么在受控场景下拍摄的图像验证你的算法是没有用的。尽可能多地获取数据,因为数据就是王道。至于数据方面就讲到这里。
一旦你有了一些数据并编写了你的算法,就需要对其进行评估。有几种验证策略,但我认为你应该从简单的交叉验证开始,并从那里继续进行,有关交叉验证的信息,请参见:
我们将使用一个很棒的开源项目scikit-learn,而不是自己实现所有内容:
它有非常好的文档和验证算法的教程:
所以计划如下:
cv2.FaceRecognizer
封装成scikit-learn估计器。cv2.FaceRecognizer
的性能。首先,我想简单介绍一下要读取的图像数据,因为这方面的问题几乎总是会出现。为了简单起见,在示例中,假设图像(即要识别的人脸)以文件夹的形式给出。每个人一个文件夹。所以,想象一下我有一个名为images
的文件夹(一个数据集),其中包含子文件夹person1
,person2
等:
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人脸数据库,可以在以下网址获取:
解压后的文件夹应该长成这个样子(在我的文件系统上解压到/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))
BaseEstimator
派生而来的,它应该有一个fit
和predict
方法。 fit
方法会得到一组样本X
和相应的标签y
,所以将其映射到cv2.FaceRecognizer
的训练方法是微不足道的。 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中,可以找到可用的交叉验证算法,包括:
cv2.FaceRecognizer
的识别率,建议使用分层交叉验证。你可能会问为什么需要其他交叉验证方法。想象一下,如果您要使用算法进行情感识别,训练集中包含测试算法的人的图片会发生什么?您可能会找到与该人最接近的匹配,但不是情感。在这种情况下,你应该进行主题独立的交叉验证。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
现在我们只需要创建我们的估计器并将estimator
、X
、y
、precision_score
和cv
传递给sklearn.cross_validation.cross_val_score
,它会为我们计算交叉验证分数:
# 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)
有大量可用的指标,随意选择另一个:
那么我们把所有这些放在脚本中!
# 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进行实验,因为您可以看到,这两个伟大的项目之间的接口非常容易。
如果要分析时间性能,可以使用Time模块。
import time
time_1 = time.time()
result = <execute your code>
time_2 = time.time()
duration = time_2 - time_1
这篇博客对opencv2中的各种特征检测算法进行了比较。它是用泰语写的,所以如果您不会泰语,可以使用谷歌浏览器的翻译功能来阅读。
作者没有分享他的代码,但也许您正在寻找类似的东西。