Commit 8257dc3c authored by Vladislav Vinogradov's avatar Vladislav Vinogradov

refactor CUDA HOG algorithm:

use abstract interface with hidden implementation
parent 0af7597d
...@@ -71,10 +71,10 @@ PERF_TEST_P(Image, ObjDetect_HOG, ...@@ -71,10 +71,10 @@ PERF_TEST_P(Image, ObjDetect_HOG,
const cv::cuda::GpuMat d_img(img); const cv::cuda::GpuMat d_img(img);
std::vector<cv::Rect> gpu_found_locations; std::vector<cv::Rect> gpu_found_locations;
cv::cuda::HOGDescriptor d_hog; cv::Ptr<cv::cuda::HOG> d_hog = cv::cuda::HOG::create();
d_hog.setSVMDetector(cv::cuda::HOGDescriptor::getDefaultPeopleDetector()); d_hog->setSVMDetector(d_hog->getDefaultPeopleDetector());
TEST_CYCLE() d_hog.detectMultiScale(d_img, gpu_found_locations); TEST_CYCLE() d_hog->detectMultiScale(d_img, gpu_found_locations);
SANITY_CHECK(gpu_found_locations); SANITY_CHECK(gpu_found_locations);
} }
...@@ -82,8 +82,10 @@ PERF_TEST_P(Image, ObjDetect_HOG, ...@@ -82,8 +82,10 @@ PERF_TEST_P(Image, ObjDetect_HOG,
{ {
std::vector<cv::Rect> cpu_found_locations; std::vector<cv::Rect> cpu_found_locations;
cv::Ptr<cv::cuda::HOG> d_hog = cv::cuda::HOG::create();
cv::HOGDescriptor hog; cv::HOGDescriptor hog;
hog.setSVMDetector(cv::cuda::HOGDescriptor::getDefaultPeopleDetector()); hog.setSVMDetector(d_hog->getDefaultPeopleDetector());
TEST_CYCLE() hog.detectMultiScale(img, cpu_found_locations); TEST_CYCLE() hog.detectMultiScale(img, cpu_found_locations);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -48,9 +48,10 @@ using namespace cvtest; ...@@ -48,9 +48,10 @@ using namespace cvtest;
//#define DUMP //#define DUMP
struct HOG : testing::TestWithParam<cv::cuda::DeviceInfo>, cv::cuda::HOGDescriptor struct HOG : testing::TestWithParam<cv::cuda::DeviceInfo>
{ {
cv::cuda::DeviceInfo devInfo; cv::cuda::DeviceInfo devInfo;
cv::Ptr<cv::cuda::HOG> hog;
#ifdef DUMP #ifdef DUMP
std::ofstream f; std::ofstream f;
...@@ -69,23 +70,13 @@ struct HOG : testing::TestWithParam<cv::cuda::DeviceInfo>, cv::cuda::HOGDescript ...@@ -69,23 +70,13 @@ struct HOG : testing::TestWithParam<cv::cuda::DeviceInfo>, cv::cuda::HOGDescript
devInfo = GetParam(); devInfo = GetParam();
cv::cuda::setDevice(devInfo.deviceID()); cv::cuda::setDevice(devInfo.deviceID());
hog = cv::cuda::HOG::create();
} }
#ifdef DUMP #ifdef DUMP
void dump(const cv::Mat& blockHists, const std::vector<cv::Point>& locations) void dump(const std::vector<cv::Point>& locations)
{ {
f.write((char*)&blockHists.rows, sizeof(blockHists.rows));
f.write((char*)&blockHists.cols, sizeof(blockHists.cols));
for (int i = 0; i < blockHists.rows; ++i)
{
for (int j = 0; j < blockHists.cols; ++j)
{
float val = blockHists.at<float>(i, j);
f.write((char*)&val, sizeof(val));
}
}
int nlocations = locations.size(); int nlocations = locations.size();
f.write((char*)&nlocations, sizeof(nlocations)); f.write((char*)&nlocations, sizeof(nlocations));
...@@ -93,21 +84,18 @@ struct HOG : testing::TestWithParam<cv::cuda::DeviceInfo>, cv::cuda::HOGDescript ...@@ -93,21 +84,18 @@ struct HOG : testing::TestWithParam<cv::cuda::DeviceInfo>, cv::cuda::HOGDescript
f.write((char*)&locations[i], sizeof(locations[i])); f.write((char*)&locations[i], sizeof(locations[i]));
} }
#else #else
void compare(const cv::Mat& blockHists, const std::vector<cv::Point>& locations) void compare(const std::vector<cv::Point>& locations)
{ {
// skip block_hists check
int rows, cols; int rows, cols;
f.read((char*)&rows, sizeof(rows)); f.read((char*)&rows, sizeof(rows));
f.read((char*)&cols, sizeof(cols)); f.read((char*)&cols, sizeof(cols));
ASSERT_EQ(rows, blockHists.rows); for (int i = 0; i < rows; ++i)
ASSERT_EQ(cols, blockHists.cols);
for (int i = 0; i < blockHists.rows; ++i)
{ {
for (int j = 0; j < blockHists.cols; ++j) for (int j = 0; j < cols; ++j)
{ {
float val; float val;
f.read((char*)&val, sizeof(val)); f.read((char*)&val, sizeof(val));
ASSERT_NEAR(val, blockHists.at<float>(i, j), 1e-3);
} }
} }
...@@ -126,54 +114,41 @@ struct HOG : testing::TestWithParam<cv::cuda::DeviceInfo>, cv::cuda::HOGDescript ...@@ -126,54 +114,41 @@ struct HOG : testing::TestWithParam<cv::cuda::DeviceInfo>, cv::cuda::HOGDescript
void testDetect(const cv::Mat& img) void testDetect(const cv::Mat& img)
{ {
gamma_correction = false; hog->setGammaCorrection(false);
setSVMDetector(cv::cuda::HOGDescriptor::getDefaultPeopleDetector()); hog->setSVMDetector(hog->getDefaultPeopleDetector());
std::vector<cv::Point> locations; std::vector<cv::Point> locations;
// Test detect // Test detect
detect(loadMat(img), locations, 0); hog->detect(loadMat(img), locations);
#ifdef DUMP #ifdef DUMP
dump(cv::Mat(block_hists), locations); dump(locations);
#else #else
compare(cv::Mat(block_hists), locations); compare(locations);
#endif #endif
// Test detect on smaller image // Test detect on smaller image
cv::Mat img2; cv::Mat img2;
cv::resize(img, img2, cv::Size(img.cols / 2, img.rows / 2)); cv::resize(img, img2, cv::Size(img.cols / 2, img.rows / 2));
detect(loadMat(img2), locations, 0); hog->detect(loadMat(img2), locations);
#ifdef DUMP #ifdef DUMP
dump(cv::Mat(block_hists), locations); dump(locations);
#else #else
compare(cv::Mat(block_hists), locations); compare(locations);
#endif #endif
// Test detect on greater image // Test detect on greater image
cv::resize(img, img2, cv::Size(img.cols * 2, img.rows * 2)); cv::resize(img, img2, cv::Size(img.cols * 2, img.rows * 2));
detect(loadMat(img2), locations, 0); hog->detect(loadMat(img2), locations);
#ifdef DUMP #ifdef DUMP
dump(cv::Mat(block_hists), locations); dump(locations);
#else #else
compare(cv::Mat(block_hists), locations); compare(locations);
#endif #endif
} }
// Does not compare border value, as interpolation leads to delta
void compare_inner_parts(cv::Mat d1, cv::Mat d2)
{
for (int i = 1; i < blocks_per_win_y - 1; ++i)
for (int j = 1; j < blocks_per_win_x - 1; ++j)
for (int k = 0; k < block_hist_size; ++k)
{
float a = d1.at<float>(0, (i * blocks_per_win_x + j) * block_hist_size);
float b = d2.at<float>(0, (i * blocks_per_win_x + j) * block_hist_size);
ASSERT_FLOAT_EQ(a, b);
}
}
}; };
// desabled while resize does not fixed // desabled while resize does not fixed
...@@ -182,13 +157,8 @@ CUDA_TEST_P(HOG, DISABLED_Detect) ...@@ -182,13 +157,8 @@ CUDA_TEST_P(HOG, DISABLED_Detect)
cv::Mat img_rgb = readImage("hog/road.png"); cv::Mat img_rgb = readImage("hog/road.png");
ASSERT_FALSE(img_rgb.empty()); ASSERT_FALSE(img_rgb.empty());
#ifdef DUMP
f.open((std::string(cvtest::TS::ptr()->get_data_path()) + "hog/expected_output.bin").c_str(), std::ios_base::binary); f.open((std::string(cvtest::TS::ptr()->get_data_path()) + "hog/expected_output.bin").c_str(), std::ios_base::binary);
ASSERT_TRUE(f.is_open()); ASSERT_TRUE(f.is_open());
#else
f.open((std::string(cvtest::TS::ptr()->get_data_path()) + "hog/expected_output.bin").c_str(), std::ios_base::binary);
ASSERT_TRUE(f.is_open());
#endif
// Test on color image // Test on color image
cv::Mat img; cv::Mat img;
...@@ -198,8 +168,6 @@ CUDA_TEST_P(HOG, DISABLED_Detect) ...@@ -198,8 +168,6 @@ CUDA_TEST_P(HOG, DISABLED_Detect)
// Test on gray image // Test on gray image
cv::cvtColor(img_rgb, img, cv::COLOR_BGR2GRAY); cv::cvtColor(img_rgb, img, cv::COLOR_BGR2GRAY);
testDetect(img); testDetect(img);
f.close();
} }
CUDA_TEST_P(HOG, GetDescriptors) CUDA_TEST_P(HOG, GetDescriptors)
...@@ -216,8 +184,14 @@ CUDA_TEST_P(HOG, GetDescriptors) ...@@ -216,8 +184,14 @@ CUDA_TEST_P(HOG, GetDescriptors)
// Convert train images into feature vectors (train table) // Convert train images into feature vectors (train table)
cv::cuda::GpuMat descriptors, descriptors_by_cols; cv::cuda::GpuMat descriptors, descriptors_by_cols;
getDescriptors(d_img, win_size, descriptors, DESCR_FORMAT_ROW_BY_ROW);
getDescriptors(d_img, win_size, descriptors_by_cols, DESCR_FORMAT_COL_BY_COL); hog->setWinStride(Size(64, 128));
hog->setDescriptorFormat(cv::cuda::HOG::DESCR_FORMAT_ROW_BY_ROW);
hog->compute(d_img, descriptors);
hog->setDescriptorFormat(cv::cuda::HOG::DESCR_FORMAT_COL_BY_COL);
hog->compute(d_img, descriptors_by_cols);
// Check size of the result train table // Check size of the result train table
wins_per_img_x = 3; wins_per_img_x = 3;
...@@ -242,48 +216,6 @@ CUDA_TEST_P(HOG, GetDescriptors) ...@@ -242,48 +216,6 @@ CUDA_TEST_P(HOG, GetDescriptors)
ASSERT_EQ(l[(y * blocks_per_win_x + x) * block_hist_size + k], ASSERT_EQ(l[(y * blocks_per_win_x + x) * block_hist_size + k],
r[(x * blocks_per_win_y + y) * block_hist_size + k]); r[(x * blocks_per_win_y + y) * block_hist_size + k]);
} }
/* Now we want to extract the same feature vectors, but from single images. NOTE: results will
be defferent, due to border values interpolation. Using of many small images is slower, however we
wont't call getDescriptors and will use computeBlockHistograms instead of. computeBlockHistograms
works good, it can be checked in the gpu_hog sample */
img_rgb = readImage("hog/positive1.png");
ASSERT_TRUE(!img_rgb.empty());
cv::cvtColor(img_rgb, img, cv::COLOR_BGR2BGRA);
computeBlockHistograms(cv::cuda::GpuMat(img));
// Everything is fine with interpolation for left top subimage
ASSERT_EQ(0.0, cv::norm((cv::Mat)block_hists, (cv::Mat)descriptors.rowRange(0, 1)));
img_rgb = readImage("hog/positive2.png");
ASSERT_TRUE(!img_rgb.empty());
cv::cvtColor(img_rgb, img, cv::COLOR_BGR2BGRA);
computeBlockHistograms(cv::cuda::GpuMat(img));
compare_inner_parts(cv::Mat(block_hists), cv::Mat(descriptors.rowRange(1, 2)));
img_rgb = readImage("hog/negative1.png");
ASSERT_TRUE(!img_rgb.empty());
cv::cvtColor(img_rgb, img, cv::COLOR_BGR2BGRA);
computeBlockHistograms(cv::cuda::GpuMat(img));
compare_inner_parts(cv::Mat(block_hists), cv::Mat(descriptors.rowRange(2, 3)));
img_rgb = readImage("hog/negative2.png");
ASSERT_TRUE(!img_rgb.empty());
cv::cvtColor(img_rgb, img, cv::COLOR_BGR2BGRA);
computeBlockHistograms(cv::cuda::GpuMat(img));
compare_inner_parts(cv::Mat(block_hists), cv::Mat(descriptors.rowRange(3, 4)));
img_rgb = readImage("hog/positive3.png");
ASSERT_TRUE(!img_rgb.empty());
cv::cvtColor(img_rgb, img, cv::COLOR_BGR2BGRA);
computeBlockHistograms(cv::cuda::GpuMat(img));
compare_inner_parts(cv::Mat(block_hists), cv::Mat(descriptors.rowRange(4, 5)));
img_rgb = readImage("hog/negative3.png");
ASSERT_TRUE(!img_rgb.empty());
cv::cvtColor(img_rgb, img, cv::COLOR_BGR2BGRA);
computeBlockHistograms(cv::cuda::GpuMat(img));
compare_inner_parts(cv::Mat(block_hists), cv::Mat(descriptors.rowRange(5, 6)));
} }
INSTANTIATE_TEST_CASE_P(CUDA_ObjDetect, HOG, ALL_DEVICES); INSTANTIATE_TEST_CASE_P(CUDA_ObjDetect, HOG, ALL_DEVICES);
...@@ -310,12 +242,12 @@ CUDA_TEST_P(CalTech, HOG) ...@@ -310,12 +242,12 @@ CUDA_TEST_P(CalTech, HOG)
cv::cuda::GpuMat d_img(img); cv::cuda::GpuMat d_img(img);
cv::Mat markedImage(img.clone()); cv::Mat markedImage(img.clone());
cv::cuda::HOGDescriptor d_hog; cv::Ptr<cv::cuda::HOG> d_hog = cv::cuda::HOG::create();
d_hog.setSVMDetector(cv::cuda::HOGDescriptor::getDefaultPeopleDetector()); d_hog->setSVMDetector(d_hog->getDefaultPeopleDetector());
d_hog.nlevels = d_hog.nlevels + 32; d_hog->setNumLevels(d_hog->getNumLevels() + 32);
std::vector<cv::Rect> found_locations; std::vector<cv::Rect> found_locations;
d_hog.detectMultiScale(d_img, found_locations); d_hog->detectMultiScale(d_img, found_locations);
#if defined (LOG_CASCADE_STATISTIC) #if defined (LOG_CASCADE_STATISTIC)
for (int i = 0; i < (int)found_locations.size(); i++) for (int i = 0; i < (int)found_locations.size(); i++)
...@@ -326,7 +258,8 @@ CUDA_TEST_P(CalTech, HOG) ...@@ -326,7 +258,8 @@ CUDA_TEST_P(CalTech, HOG)
cv::rectangle(markedImage, r , CV_RGB(255, 0, 0)); cv::rectangle(markedImage, r , CV_RGB(255, 0, 0));
} }
cv::imshow("Res", markedImage); cv::waitKey(); cv::imshow("Res", markedImage);
cv::waitKey();
#endif #endif
} }
......
...@@ -244,19 +244,13 @@ void App::run() ...@@ -244,19 +244,13 @@ void App::run()
Size win_size(args.win_width, args.win_width * 2); //(64, 128) or (48, 96) Size win_size(args.win_width, args.win_width * 2); //(64, 128) or (48, 96)
Size win_stride(args.win_stride_width, args.win_stride_height); Size win_stride(args.win_stride_width, args.win_stride_height);
cv::Ptr<cv::cuda::HOG> gpu_hog = cv::cuda::HOG::create(win_size);
cv::HOGDescriptor cpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9);
// Create HOG descriptors and detectors here // Create HOG descriptors and detectors here
vector<float> detector; Mat detector = gpu_hog->getDefaultPeopleDetector();
if (win_size == Size(64, 128))
detector = cv::cuda::HOGDescriptor::getPeopleDetector64x128(); gpu_hog->setSVMDetector(detector);
else
detector = cv::cuda::HOGDescriptor::getPeopleDetector48x96();
cv::cuda::HOGDescriptor gpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9,
cv::cuda::HOGDescriptor::DEFAULT_WIN_SIGMA, 0.2, gamma_corr,
cv::cuda::HOGDescriptor::DEFAULT_NLEVELS);
cv::HOGDescriptor cpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, 1, -1,
HOGDescriptor::L2Hys, 0.2, gamma_corr, cv::HOGDescriptor::DEFAULT_NLEVELS);
gpu_hog.setSVMDetector(detector);
cpu_hog.setSVMDetector(detector); cpu_hog.setSVMDetector(detector);
while (running) while (running)
...@@ -307,9 +301,6 @@ void App::run() ...@@ -307,9 +301,6 @@ void App::run()
else img = img_aux; else img = img_aux;
img_to_show = img; img_to_show = img;
gpu_hog.nlevels = nlevels;
cpu_hog.nlevels = nlevels;
vector<Rect> found; vector<Rect> found;
// Perform HOG classification // Perform HOG classification
...@@ -317,11 +308,19 @@ void App::run() ...@@ -317,11 +308,19 @@ void App::run()
if (use_gpu) if (use_gpu)
{ {
gpu_img.upload(img); gpu_img.upload(img);
gpu_hog.detectMultiScale(gpu_img, found, hit_threshold, win_stride, gpu_hog->setNumLevels(nlevels);
Size(0, 0), scale, gr_threshold); gpu_hog->setHitThreshold(hit_threshold);
gpu_hog->setWinStride(win_stride);
gpu_hog->setScaleFactor(scale);
gpu_hog->setGroupThreshold(gr_threshold);
gpu_hog->detectMultiScale(gpu_img, found);
} }
else cpu_hog.detectMultiScale(img, found, hit_threshold, win_stride, else
{
cpu_hog.nlevels = nlevels;
cpu_hog.detectMultiScale(img, found, hit_threshold, win_stride,
Size(0, 0), scale, gr_threshold); Size(0, 0), scale, gr_threshold);
}
hogWorkEnd(); hogWorkEnd();
// Draw positive classified windows // Draw positive classified windows
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment