使用 openCV 改进人员检测
Improving people detection with openCV
我正在尝试在 openCV 上进行人员检测的样本。 运行 它在图像上之后 (original image available here) 这是我的结果:
我正在使用与 openCV 捆绑在一起的人员检测示例(略微修改以避免 Visual Studio 错误)。这是执行的代码:
// opencv-sample.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
using namespace cv;
using namespace std;
// static void help()
// {
// printf(
// "\nDemonstrate the use of the HoG descriptor using\n"
// " HOGDescriptor::hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());\n"
// "Usage:\n"
// "./peopledetect (<image_filename> | <image_list>.txt)\n\n");
// }
int main(int argc, char** argv)
{
Mat img;
FILE* f = 0;
char _filename[1024];
if (argc == 1)
{
printf("Usage: peopledetect (<image_filename> | <image_list>.txt)\n");
return 0;
}
img = imread(argv[1]);
if (img.data)
{
strcpy_s(_filename, argv[1]);
}
else
{
fopen_s(&f, argv[1], "rt");
if (!f)
{
fprintf(stderr, "ERROR: the specified file could not be loaded\n");
return -1;
}
}
HOGDescriptor hog;
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
namedWindow("people detector", 1);
for (;;)
{
char* filename = _filename;
if (f)
{
if (!fgets(filename, (int)sizeof(_filename) - 2, f))
break;
//while(*filename && isspace(*filename))
// ++filename;
if (filename[0] == '#')
continue;
int l = (int)strlen(filename);
while (l > 0 && isspace(filename[l - 1]))
--l;
filename[l] = '[=10=]';
img = imread(filename);
}
printf("%s:\n", filename);
if (!img.data)
continue;
fflush(stdout);
vector<Rect> found, found_filtered;
double t = (double)getTickCount();
// run the detector with default parameters. to get a higher hit-rate
// (and more false alarms, respectively), decrease the hitThreshold and
// groupThreshold (set groupThreshold to 0 to turn off the grouping completely).
hog.detectMultiScale(img, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);
t = (double)getTickCount() - t;
printf("tdetection time = %gms\n", t*1000. / cv::getTickFrequency());
size_t i, j;
for (i = 0; i < found.size(); i++)
{
Rect r = found[i];
for (j = 0; j < found.size(); j++)
if (j != i && (r & found[j]) == r)
break;
if (j == found.size())
found_filtered.push_back(r);
}
for (i = 0; i < found_filtered.size(); i++)
{
Rect r = found_filtered[i];
// the HOG detector returns slightly larger rectangles than the real objects.
// so we slightly shrink the rectangles to get a nicer output.
r.x += cvRound(r.width*0.1);
r.width = cvRound(r.width*0.8);
r.y += cvRound(r.height*0.07);
r.height = cvRound(r.height*0.8);
rectangle(img, r.tl(), r.br(), cv::Scalar(0, 255, 0), 3);
}
imshow("people detector", img);
imwrite("detected_ppl.jpg", img);
int c = waitKey(0) & 255;
if (c == 'q' || c == 'Q' || !f)
break;
}
if (f)
fclose(f);
return 0;
}
我想改进这个结果,让我至少可以检测到这张图片中 11 个人中的 9 个。我怎样才能改善这个结果?我需要训练单独的 SVM 吗?或者我可以使用更好的图书馆吗?还是我需要求助于深度学习?
这是我在花不多时间研究示例代码后实现的改进。
我做了什么
- 调整 detectMultiScale
中的一些参数
- 调整过滤器以消除大量重叠的矩形
我会说我得到了 9/11 命中率,有一个误报和两个漏报。
一切都很好,但这是一张静态图片。调整参数以针对单个样本工作会导致过度拟合:这样你就可以准确地得到你对那个样本的反应,但泛化能力差。
我强烈建议您在放弃使用 'better' 库和 'deep learning' 方法之前彻底了解 openCV 算法。如果您不知道该算法的优点和缺点,您将无法与其他库中的其他方法进行比较。
更新
This is the code 我用过的效果。它与 peopledetect.cpp
openCV 示例密切相关。您将需要进行一些更改,因为我使用的是与您无关的自定义图像读取功能。
我为 'scaleFactor' 参数添加了一个滑块,因此您可以轻松查看更改它的效果。 detectMultiscale
以不同尺寸多次通过图像对图像运行分类器 window。 scaleFactor 参数会影响每次传递的大小调整步骤,对输出产生巨大影响,而设置的变化很小。然而,在单个静止图像上调整这些参数有点毫无意义,您确实需要让它在目标数据中的代表性测试集上松散,以评估此(或任何其他)算法的适用性。
我正在尝试在 openCV 上进行人员检测的样本。 运行 它在图像上之后 (original image available here) 这是我的结果:
我正在使用与 openCV 捆绑在一起的人员检测示例(略微修改以避免 Visual Studio 错误)。这是执行的代码:
// opencv-sample.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
using namespace cv;
using namespace std;
// static void help()
// {
// printf(
// "\nDemonstrate the use of the HoG descriptor using\n"
// " HOGDescriptor::hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());\n"
// "Usage:\n"
// "./peopledetect (<image_filename> | <image_list>.txt)\n\n");
// }
int main(int argc, char** argv)
{
Mat img;
FILE* f = 0;
char _filename[1024];
if (argc == 1)
{
printf("Usage: peopledetect (<image_filename> | <image_list>.txt)\n");
return 0;
}
img = imread(argv[1]);
if (img.data)
{
strcpy_s(_filename, argv[1]);
}
else
{
fopen_s(&f, argv[1], "rt");
if (!f)
{
fprintf(stderr, "ERROR: the specified file could not be loaded\n");
return -1;
}
}
HOGDescriptor hog;
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
namedWindow("people detector", 1);
for (;;)
{
char* filename = _filename;
if (f)
{
if (!fgets(filename, (int)sizeof(_filename) - 2, f))
break;
//while(*filename && isspace(*filename))
// ++filename;
if (filename[0] == '#')
continue;
int l = (int)strlen(filename);
while (l > 0 && isspace(filename[l - 1]))
--l;
filename[l] = '[=10=]';
img = imread(filename);
}
printf("%s:\n", filename);
if (!img.data)
continue;
fflush(stdout);
vector<Rect> found, found_filtered;
double t = (double)getTickCount();
// run the detector with default parameters. to get a higher hit-rate
// (and more false alarms, respectively), decrease the hitThreshold and
// groupThreshold (set groupThreshold to 0 to turn off the grouping completely).
hog.detectMultiScale(img, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);
t = (double)getTickCount() - t;
printf("tdetection time = %gms\n", t*1000. / cv::getTickFrequency());
size_t i, j;
for (i = 0; i < found.size(); i++)
{
Rect r = found[i];
for (j = 0; j < found.size(); j++)
if (j != i && (r & found[j]) == r)
break;
if (j == found.size())
found_filtered.push_back(r);
}
for (i = 0; i < found_filtered.size(); i++)
{
Rect r = found_filtered[i];
// the HOG detector returns slightly larger rectangles than the real objects.
// so we slightly shrink the rectangles to get a nicer output.
r.x += cvRound(r.width*0.1);
r.width = cvRound(r.width*0.8);
r.y += cvRound(r.height*0.07);
r.height = cvRound(r.height*0.8);
rectangle(img, r.tl(), r.br(), cv::Scalar(0, 255, 0), 3);
}
imshow("people detector", img);
imwrite("detected_ppl.jpg", img);
int c = waitKey(0) & 255;
if (c == 'q' || c == 'Q' || !f)
break;
}
if (f)
fclose(f);
return 0;
}
我想改进这个结果,让我至少可以检测到这张图片中 11 个人中的 9 个。我怎样才能改善这个结果?我需要训练单独的 SVM 吗?或者我可以使用更好的图书馆吗?还是我需要求助于深度学习?
这是我在花不多时间研究示例代码后实现的改进。
我做了什么
- 调整 detectMultiScale
中的一些参数
- 调整过滤器以消除大量重叠的矩形
我会说我得到了 9/11 命中率,有一个误报和两个漏报。
一切都很好,但这是一张静态图片。调整参数以针对单个样本工作会导致过度拟合:这样你就可以准确地得到你对那个样本的反应,但泛化能力差。
我强烈建议您在放弃使用 'better' 库和 'deep learning' 方法之前彻底了解 openCV 算法。如果您不知道该算法的优点和缺点,您将无法与其他库中的其他方法进行比较。
更新
This is the code 我用过的效果。它与 peopledetect.cpp
openCV 示例密切相关。您将需要进行一些更改,因为我使用的是与您无关的自定义图像读取功能。
我为 'scaleFactor' 参数添加了一个滑块,因此您可以轻松查看更改它的效果。 detectMultiscale
以不同尺寸多次通过图像对图像运行分类器 window。 scaleFactor 参数会影响每次传递的大小调整步骤,对输出产生巨大影响,而设置的变化很小。然而,在单个静止图像上调整这些参数有点毫无意义,您确实需要让它在目标数据中的代表性测试集上松散,以评估此(或任何其他)算法的适用性。