added support of gamama_correction parameter into gpu::HOGDescriptor, updated tests

This commit is contained in:
Alexey Spizhevoy 2010-12-03 11:11:44 +00:00
parent 90cce3a2ba
commit df48ad76b0
5 changed files with 84 additions and 46 deletions

View File

@ -1076,6 +1076,7 @@ namespace cv
double win_sigma;
double threshold_L2hys;
int nlevels;
bool gamma_correction;
protected:
void computeBlockHistograms(const GpuMat& img);
@ -1084,8 +1085,6 @@ namespace cv
static int numPartsWithin(int size, int part_size, int stride);
static Size numPartsWithin(Size size, Size part_size, Size stride);
bool gamma_correction;
// Coefficients of the separating plane
float free_coef;
GpuMat detector;

View File

@ -522,7 +522,7 @@ void extract_descrs_by_cols(int win_height, int win_width, int block_stride_y, i
// Gradients computation
template <int nthreads>
template <int nthreads, int correct_gamma>
__global__ void compute_gradients_8UC4_kernel(int height, int width, const PtrElemStep img,
float angle_scale, PtrElemStepf grad, PtrElemStep qangle)
{
@ -533,11 +533,10 @@ __global__ void compute_gradients_8UC4_kernel(int height, int width, const PtrEl
__shared__ float sh_row[(nthreads + 2) * 3];
uchar4 val;
if (x < width)
val = row[x];
else if (x == width)
val = row[x - 2];
// Othrewise we do not read variable 'val' at all
if (x < width)
val = row[x];
else
val = row[width - 2];
sh_row[threadIdx.x + 1] = val.x;
sh_row[threadIdx.x + 1 + (nthreads + 2)] = val.y;
@ -545,7 +544,7 @@ __global__ void compute_gradients_8UC4_kernel(int height, int width, const PtrEl
if (threadIdx.x == 0)
{
val = x > 0 ? row[x - 1] : row[1];
val = row[max(x - 1, 1)];
sh_row[0] = val.x;
sh_row[(nthreads + 2)] = val.y;
sh_row[2 * (nthreads + 2)] = val.z;
@ -553,7 +552,7 @@ __global__ void compute_gradients_8UC4_kernel(int height, int width, const PtrEl
if (threadIdx.x == blockDim.x - 1)
{
val = (x < width - 1) ? row[x + 1] : row[width - 2];
val = row[min(x + 1, width - 2)];
sh_row[blockDim.x + 1] = val.x;
sh_row[blockDim.x + 1 + (nthreads + 2)] = val.y;
sh_row[blockDim.x + 1 + 2 * (nthreads + 2)] = val.z;
@ -571,9 +570,12 @@ __global__ void compute_gradients_8UC4_kernel(int height, int width, const PtrEl
a.y = sh_row[threadIdx.x + (nthreads + 2)];
a.z = sh_row[threadIdx.x + 2 * (nthreads + 2)];
float3 dx = make_float3(sqrtf(b.x) - sqrtf(a.x),
sqrtf(b.y) - sqrtf(a.y),
sqrtf(b.z) - sqrtf(a.z));
float3 dx;
if (correct_gamma)
dx = make_float3(sqrtf(b.x) - sqrtf(a.x), sqrtf(b.y) - sqrtf(a.y), sqrtf(b.z) - sqrtf(a.z));
else
dx = make_float3(b.x - a.x, b.y - a.y, b.z - a.z);
float3 dy = make_float3(0.f, 0.f, 0.f);
if (blockIdx.y > 0 && blockIdx.y < height - 1)
@ -584,9 +586,10 @@ __global__ void compute_gradients_8UC4_kernel(int height, int width, const PtrEl
val = ((const uchar4*)img.ptr(blockIdx.y + 1))[x];
b = make_float3(val.x, val.y, val.z);
dy = make_float3(sqrtf(b.x) - sqrtf(a.x),
sqrtf(b.y) - sqrtf(a.y),
sqrtf(b.z) - sqrtf(a.z));
if (correct_gamma)
dy = make_float3(sqrtf(b.x) - sqrtf(a.x), sqrtf(b.y) - sqrtf(a.y), sqrtf(b.z) - sqrtf(a.z));
else
dy = make_float3(b.x - a.x, b.y - a.y, b.z - a.z);
}
float best_dx = dx.x;
@ -623,20 +626,25 @@ __global__ void compute_gradients_8UC4_kernel(int height, int width, const PtrEl
void compute_gradients_8UC4(int nbins, int height, int width, const DevMem2D& img,
float angle_scale, DevMem2Df grad, DevMem2D qangle)
float angle_scale, DevMem2Df grad, DevMem2D qangle, bool correct_gamma)
{
const int nthreads = 256;
dim3 bdim(nthreads, 1);
dim3 gdim(div_up(width, bdim.x), div_up(height, bdim.y));
compute_gradients_8UC4_kernel<nthreads><<<gdim, bdim>>>(height, width, img, angle_scale,
grad, qangle);
if (correct_gamma)
compute_gradients_8UC4_kernel<nthreads, 1><<<gdim, bdim>>>(
height, width, img, angle_scale, grad, qangle);
else
compute_gradients_8UC4_kernel<nthreads, 0><<<gdim, bdim>>>(
height, width, img, angle_scale, grad, qangle);
cudaSafeCall(cudaThreadSynchronize());
}
template <int nthreads>
template <int nthreads, int correct_gamma>
__global__ void compute_gradients_8UC1_kernel(int height, int width, const PtrElemStep img,
float angle_scale, PtrElemStepf grad, PtrElemStep qangle)
{
@ -647,24 +655,36 @@ __global__ void compute_gradients_8UC1_kernel(int height, int width, const PtrEl
__shared__ float sh_row[nthreads + 2];
if (x < width)
sh_row[threadIdx.x + 1] = row[x];
else if (x == width)
sh_row[threadIdx.x + 1] = row[x - 2];
sh_row[threadIdx.x + 1] = row[x];
else
sh_row[threadIdx.x + 1] = row[width - 2];
if (threadIdx.x == 0)
sh_row[0] = x > 0 ? row[x - 1] : row[1];
sh_row[0] = row[max(x - 1, 1)];
if (threadIdx.x == blockDim.x - 1)
sh_row[blockDim.x + 1] = (x < width - 1) ? row[x + 1] : row[width - 2];
sh_row[blockDim.x + 1] = row[min(x + 1, width - 2)];
__syncthreads();
if (x < width)
{
float dx = sqrtf(sh_row[threadIdx.x + 2]) - sqrtf(sh_row[threadIdx.x]);
float dx;
if (correct_gamma)
dx = sqrtf(sh_row[threadIdx.x + 2]) - sqrtf(sh_row[threadIdx.x]);
else
dx = sh_row[threadIdx.x + 2] - sh_row[threadIdx.x];
float dy = 0.f;
if (blockIdx.y > 0 && blockIdx.y < height - 1)
dy = sqrtf(((const unsigned char*)img.ptr(blockIdx.y + 1))[x]) -
sqrtf(((const unsigned char*)img.ptr(blockIdx.y - 1))[x]);
{
float a = ((const unsigned char*)img.ptr(blockIdx.y + 1))[x];
float b = ((const unsigned char*)img.ptr(blockIdx.y - 1))[x];
if (correct_gamma)
dy = sqrtf(a) - sqrtf(b);
else
dy = a - b;
}
float mag = sqrtf(dx * dx + dy * dy);
float ang = (atan2f(dy, dx) + CV_PI_F) * angle_scale - 0.5f;
@ -679,15 +699,20 @@ __global__ void compute_gradients_8UC1_kernel(int height, int width, const PtrEl
void compute_gradients_8UC1(int nbins, int height, int width, const DevMem2D& img,
float angle_scale, DevMem2Df grad, DevMem2D qangle)
float angle_scale, DevMem2Df grad, DevMem2D qangle, bool correct_gamma)
{
const int nthreads = 256;
dim3 bdim(nthreads, 1);
dim3 gdim(div_up(width, bdim.x), div_up(height, bdim.y));
compute_gradients_8UC1_kernel<nthreads><<<gdim, bdim>>>(height, width, img, angle_scale,
grad, qangle);
if (correct_gamma)
compute_gradients_8UC1_kernel<nthreads, 1><<<gdim, bdim>>>(
height, width, img, angle_scale, grad, qangle);
else
compute_gradients_8UC1_kernel<nthreads, 0><<<gdim, bdim>>>(
height, width, img, angle_scale, grad, qangle);
cudaSafeCall(cudaThreadSynchronize());
}

View File

@ -85,9 +85,9 @@ void extract_descrs_by_cols(int win_height, int win_width, int block_stride_y, i
cv::gpu::DevMem2Df descriptors);
void compute_gradients_8UC1(int nbins, int height, int width, const cv::gpu::DevMem2D& img,
float angle_scale, cv::gpu::DevMem2Df grad, cv::gpu::DevMem2D qangle);
float angle_scale, cv::gpu::DevMem2Df grad, cv::gpu::DevMem2D qangle, bool correct_gamma);
void compute_gradients_8UC4(int nbins, int height, int width, const cv::gpu::DevMem2D& img,
float angle_scale, cv::gpu::DevMem2Df grad, cv::gpu::DevMem2D qangle);
float angle_scale, cv::gpu::DevMem2Df grad, cv::gpu::DevMem2D qangle, bool correct_gamma);
void resize_8UC1(const cv::gpu::DevMem2D& src, cv::gpu::DevMem2D dst);
void resize_8UC4(const cv::gpu::DevMem2D& src, cv::gpu::DevMem2D dst);
@ -118,8 +118,6 @@ cv::gpu::HOGDescriptor::HOGDescriptor(Size win_size, Size block_size, Size block
CV_Assert(cell_size == Size(8, 8));
CV_Assert(gamma_correction == true);
Size cells_per_block = Size(block_size.width / cell_size.width,
block_size.height / cell_size.height);
CV_Assert(cells_per_block == Size(2, 2));
@ -194,10 +192,10 @@ void cv::gpu::HOGDescriptor::computeGradient(const GpuMat& img, GpuMat& grad, Gp
float angleScale = (float)(nbins / CV_PI);
switch (img.type()) {
case CV_8UC1:
hog::compute_gradients_8UC1(nbins, img.rows, img.cols, img, angleScale, grad, qangle);
hog::compute_gradients_8UC1(nbins, img.rows, img.cols, img, angleScale, grad, qangle, gamma_correction);
break;
case CV_8UC4:
hog::compute_gradients_8UC4(nbins, img.rows, img.cols, img, angleScale, grad, qangle);
hog::compute_gradients_8UC4(nbins, img.rows, img.cols, img, angleScale, grad, qangle, gamma_correction);
break;
}
}

View File

@ -34,6 +34,7 @@ public:
int win_width;
int win_stride_width;
int win_stride_height;
bool gamma_corr;
};
@ -72,6 +73,7 @@ private:
int gr_threshold;
int nlevels;
double hit_threshold;
bool gamma_corr;
int64 hog_work_begin;
double hog_work_fps;
@ -99,7 +101,8 @@ int main(int argc, char** argv)
<< " [-win_width <int>] # width of the window (48 or 64)\n"
<< " [-win_stride_width <int>] # distance by OX axis between neighbour wins\n"
<< " [-win_stride_height <int>] # distance by OY axis between neighbour wins\n"
<< " [-gr_threshold <int>] # merging similar rects constant\n";
<< " [-gr_threshold <int>] # merging similar rects constant\n"
<< " [-gamma_corr <int>] # do gamma correction or not\n";
return 1;
}
App app(Settings::Read(argc, argv));
@ -125,6 +128,7 @@ Settings::Settings()
win_width = 48;
win_stride_width = 8;
win_stride_height = 8;
gamma_corr = true;
}
@ -149,6 +153,7 @@ Settings Settings::Read(int argc, char** argv)
else if (key == "-win_stride_width") settings.win_stride_width = atoi(val.c_str());
else if (key == "-win_stride_height") settings.win_stride_height = atoi(val.c_str());
else if (key == "-gr_threshold") settings.gr_threshold = atoi(val.c_str());
else if (key == "-gamma_corr") settings.gamma_corr = atoi(val.c_str()) != 0;
else throw runtime_error((string("Unknown key: ") + key));
}
@ -176,6 +181,7 @@ App::App(const Settings &s)
gr_threshold = settings.gr_threshold;
nlevels = settings.nlevels;
hit_threshold = settings.hit_threshold;
gamma_corr = settings.gamma_corr;
if (settings.win_width != 64 && settings.win_width != 48)
settings.win_width = 64;
@ -186,6 +192,7 @@ App::App(const Settings &s)
cout << "Win width: " << settings.win_width << endl;
cout << "Win stride: (" << settings.win_stride_width << ", " << settings.win_stride_height << ")\n";
cout << "Hit threshold: " << hit_threshold << endl;
cout << "Gamma correction: " << gamma_corr << endl;
cout << endl;
}
@ -205,11 +212,14 @@ void App::RunOpencvGui()
detector = cv::gpu::HOGDescriptor::getPeopleDetector_48x96();
// GPU's HOG classifier
cv::gpu::HOGDescriptor gpu_hog(win_size);
cv::gpu::HOGDescriptor gpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9,
cv::gpu::HOGDescriptor::DEFAULT_WIN_SIGMA, 0.2, gamma_corr,
cv::gpu::HOGDescriptor::DEFAULT_NLEVELS);
gpu_hog.setSVMDetector(detector);
// CPU's HOG classifier
cv::HOGDescriptor cpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, 1, -1, HOGDescriptor::L2Hys, 0.2, true, 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);
cpu_hog.setSVMDetector(detector);
// Make endless cycle from video (if src is video)
@ -347,6 +357,11 @@ void App::HandleKey(char key)
hit_threshold = max(0.0, hit_threshold - 0.25);
cout << "Hit threshold: " << hit_threshold << endl;
break;
case 'c':
case 'C':
gamma_corr = !gamma_corr;
cout << "Gamma correction: " << gamma_corr << endl;
break;
}
}

View File

@ -47,7 +47,7 @@ using namespace std;
//#define DUMP
#define CHECK(pred, err) if (!(pred)) { \
ts->printf(CvTS::LOG, "Fail: \"%s\" at line: %d\n", #pred, __LINE__); \
ts->printf(CvTS::CONSOLE, "Fail: \"%s\" at line: %d\n", #pred, __LINE__); \
ts->set_failed_test_info(err); \
return; }
@ -141,6 +141,7 @@ struct CV_GpuHogDetectionTest: public CvTest, public cv::gpu::HOGDescriptor
{
cv::gpu::GpuMat d_img(img);
gamma_correction = false;
setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector());
//cpu detector may be updated soon
//hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());
@ -157,9 +158,9 @@ struct CV_GpuHogDetectionTest: public CvTest, public cv::gpu::HOGDescriptor
#endif
// Test detect on smaller image
cv::gpu::GpuMat d_img2;
cv::gpu::resize(d_img, d_img2, cv::Size(d_img.cols / 2, d_img.rows / 2));
detect(d_img2, locations, 0);
cv::Mat img2;
cv::resize(img, img2, cv::Size(img.cols / 2, img.rows / 2));
detect(cv::gpu::GpuMat(img2), locations, 0);
#ifdef DUMP
dump(block_hists, locations);
@ -168,8 +169,8 @@ struct CV_GpuHogDetectionTest: public CvTest, public cv::gpu::HOGDescriptor
#endif
// Test detect on greater image
cv::gpu::resize(d_img, d_img2, cv::Size(d_img.cols * 2, d_img.rows * 2));
detect(d_img2, locations, 0);
cv::resize(img, img2, cv::Size(img.cols * 2, img.rows * 2));
detect(cv::gpu::GpuMat(img2), locations, 0);
#ifdef DUMP
dump(block_hists, locations);