[~] Refactored, cleaned up, and consolidated the code of GPU examples (cascadeclassifier and cascadeclassifier_nvidia_api)
This commit is contained in:
parent
daac469b83
commit
07d19c2c6f
@ -1520,7 +1520,7 @@ namespace cv
|
|||||||
// The cascade classifier class for object detection.
|
// The cascade classifier class for object detection.
|
||||||
class CV_EXPORTS CascadeClassifier_GPU
|
class CV_EXPORTS CascadeClassifier_GPU
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CascadeClassifier_GPU();
|
CascadeClassifier_GPU();
|
||||||
CascadeClassifier_GPU(const string& filename);
|
CascadeClassifier_GPU(const string& filename);
|
||||||
~CascadeClassifier_GPU();
|
~CascadeClassifier_GPU();
|
||||||
@ -1528,20 +1528,20 @@ namespace cv
|
|||||||
bool empty() const;
|
bool empty() const;
|
||||||
bool load(const string& filename);
|
bool load(const string& filename);
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
/* returns number of detected objects */
|
/* returns number of detected objects */
|
||||||
int detectMultiScale( const GpuMat& image, GpuMat& objectsBuf, double scaleFactor=1.2, int minNeighbors=4, Size minSize=Size());
|
int detectMultiScale( const GpuMat& image, GpuMat& objectsBuf, double scaleFactor=1.2, int minNeighbors=4, Size minSize=Size());
|
||||||
|
|
||||||
bool findLargestObject;
|
bool findLargestObject;
|
||||||
bool visualizeInPlace;
|
bool visualizeInPlace;
|
||||||
|
|
||||||
Size getClassifierSize() const;
|
Size getClassifierSize() const;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct CascadeClassifierImpl;
|
struct CascadeClassifierImpl;
|
||||||
CascadeClassifierImpl* impl;
|
CascadeClassifierImpl* impl;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////// SURF //////////////////////////////////////////
|
////////////////////////////////// SURF //////////////////////////////////////////
|
||||||
|
|
||||||
class CV_EXPORTS SURF_GPU : public CvSURFParams
|
class CV_EXPORTS SURF_GPU : public CvSURFParams
|
||||||
|
@ -62,16 +62,22 @@ int cv::gpu::CascadeClassifier_GPU::detectMultiScale( const GpuMat& , GpuMat& ,
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
|
struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
|
||||||
{
|
{
|
||||||
CascadeClassifierImpl(const string& filename) : lastAllocatedFrameSize(-1, -1)
|
CascadeClassifierImpl(const string& filename) : lastAllocatedFrameSize(-1, -1)
|
||||||
{
|
{
|
||||||
ncvSetDebugOutputHandler(NCVDebugOutputHandler);
|
ncvSetDebugOutputHandler(NCVDebugOutputHandler);
|
||||||
if (ncvStat != load(filename))
|
if (ncvStat != load(filename))
|
||||||
|
{
|
||||||
CV_Error(CV_GpuApiCallError, "Error in GPU cacade load");
|
CV_Error(CV_GpuApiCallError, "Error in GPU cacade load");
|
||||||
}
|
}
|
||||||
NCVStatus process(const GpuMat& src, GpuMat& objects, float scaleStep, int minNeighbors, bool findLargestObject, bool visualizeInPlace, NcvSize32u ncvMinSize, /*out*/unsigned int& numDetections)
|
}
|
||||||
{
|
|
||||||
calculateMemReqsAndAllocate(src.size());
|
|
||||||
|
NCVStatus process(const GpuMat& src, GpuMat& objects, float scaleStep, int minNeighbors,
|
||||||
|
bool findLargestObject, bool visualizeInPlace, NcvSize32u ncvMinSize,
|
||||||
|
/*out*/unsigned int& numDetections)
|
||||||
|
{
|
||||||
|
calculateMemReqsAndAllocate(src.size());
|
||||||
|
|
||||||
NCVMemPtr src_beg;
|
NCVMemPtr src_beg;
|
||||||
src_beg.ptr = (void*)src.ptr<Ncv8u>();
|
src_beg.ptr = (void*)src.ptr<Ncv8u>();
|
||||||
@ -81,14 +87,8 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
|
|||||||
src_seg.begin = src_beg;
|
src_seg.begin = src_beg;
|
||||||
src_seg.size = src.step * src.rows;
|
src_seg.size = src.step * src.rows;
|
||||||
|
|
||||||
NCVMatrixReuse<Ncv8u> d_src(src_seg, devProp.textureAlignment, src.cols, src.rows, src.step, true);
|
NCVMatrixReuse<Ncv8u> d_src(src_seg, devProp.textureAlignment, src.cols, src.rows, src.step, true);
|
||||||
ncvAssertReturn(d_src.isMemReused(), NCV_ALLOCATOR_BAD_REUSE);
|
ncvAssertReturn(d_src.isMemReused(), NCV_ALLOCATOR_BAD_REUSE);
|
||||||
|
|
||||||
//NCVMatrixAlloc<Ncv8u> d_src(*gpuAllocator, src.cols, src.rows);
|
|
||||||
//ncvAssertReturn(d_src.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
|
|
||||||
|
|
||||||
//NCVMatrixAlloc<Ncv8u> h_src(*cpuAllocator, src.cols, src.rows);
|
|
||||||
//ncvAssertReturn(h_src.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
|
|
||||||
|
|
||||||
CV_Assert(objects.rows == 1);
|
CV_Assert(objects.rows == 1);
|
||||||
|
|
||||||
@ -100,10 +100,8 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
|
|||||||
objects_seg.begin = objects_beg;
|
objects_seg.begin = objects_beg;
|
||||||
objects_seg.size = objects.step * objects.rows;
|
objects_seg.size = objects.step * objects.rows;
|
||||||
NCVVectorReuse<NcvRect32u> d_rects(objects_seg, objects.cols);
|
NCVVectorReuse<NcvRect32u> d_rects(objects_seg, objects.cols);
|
||||||
ncvAssertReturn(d_rects.isMemReused(), NCV_ALLOCATOR_BAD_REUSE);
|
ncvAssertReturn(d_rects.isMemReused(), NCV_ALLOCATOR_BAD_REUSE);
|
||||||
//NCVVectorAlloc<NcvRect32u> d_rects(*gpuAllocator, 100);
|
|
||||||
//ncvAssertReturn(d_rects.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
|
|
||||||
|
|
||||||
NcvSize32u roi;
|
NcvSize32u roi;
|
||||||
roi.width = d_src.width();
|
roi.width = d_src.width();
|
||||||
roi.height = d_src.height();
|
roi.height = d_src.height();
|
||||||
@ -111,7 +109,7 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
|
|||||||
Ncv32u flags = 0;
|
Ncv32u flags = 0;
|
||||||
flags |= findLargestObject? NCVPipeObjDet_FindLargestObject : 0;
|
flags |= findLargestObject? NCVPipeObjDet_FindLargestObject : 0;
|
||||||
flags |= visualizeInPlace ? NCVPipeObjDet_VisualizeInPlace : 0;
|
flags |= visualizeInPlace ? NCVPipeObjDet_VisualizeInPlace : 0;
|
||||||
|
|
||||||
ncvStat = ncvDetectObjectsMultiScale_device(
|
ncvStat = ncvDetectObjectsMultiScale_device(
|
||||||
d_src, roi, d_rects, numDetections, haar, *h_haarStages,
|
d_src, roi, d_rects, numDetections, haar, *h_haarStages,
|
||||||
*d_haarStages, *d_haarNodes, *d_haarFeatures,
|
*d_haarStages, *d_haarNodes, *d_haarFeatures,
|
||||||
@ -122,24 +120,28 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
|
|||||||
*gpuAllocator, *cpuAllocator, devProp, 0);
|
*gpuAllocator, *cpuAllocator, devProp, 0);
|
||||||
ncvAssertReturnNcvStat(ncvStat);
|
ncvAssertReturnNcvStat(ncvStat);
|
||||||
ncvAssertCUDAReturn(cudaStreamSynchronize(0), NCV_CUDA_ERROR);
|
ncvAssertCUDAReturn(cudaStreamSynchronize(0), NCV_CUDA_ERROR);
|
||||||
|
|
||||||
return NCV_SUCCESS;
|
return NCV_SUCCESS;
|
||||||
}
|
}
|
||||||
////
|
|
||||||
|
|
||||||
NcvSize32u getClassifierSize() const { return haar.ClassifierSize; }
|
NcvSize32u getClassifierSize() const { return haar.ClassifierSize; }
|
||||||
cv::Size getClassifierCvSize() const { return cv::Size(haar.ClassifierSize.width, haar.ClassifierSize.height); }
|
cv::Size getClassifierCvSize() const { return cv::Size(haar.ClassifierSize.width, haar.ClassifierSize.height); }
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
static void NCVDebugOutputHandler(const char* msg) { CV_Error(CV_GpuApiCallError, msg); }
|
static void NCVDebugOutputHandler(const char* msg) { CV_Error(CV_GpuApiCallError, msg); }
|
||||||
|
|
||||||
|
|
||||||
NCVStatus load(const string& classifierFile)
|
NCVStatus load(const string& classifierFile)
|
||||||
{
|
{
|
||||||
int devId = cv::gpu::getDevice();
|
int devId = cv::gpu::getDevice();
|
||||||
ncvAssertCUDAReturn(cudaGetDeviceProperties(&devProp, devId), NCV_CUDA_ERROR);
|
ncvAssertCUDAReturn(cudaGetDeviceProperties(&devProp, devId), NCV_CUDA_ERROR);
|
||||||
|
|
||||||
// Load the classifier from file (assuming its size is about 1 mb) using a simple allocator
|
// Load the classifier from file (assuming its size is about 1 mb) using a simple allocator
|
||||||
gpuCascadeAllocator = new NCVMemNativeAllocator(NCVMemoryTypeDevice, devProp.textureAlignment);
|
gpuCascadeAllocator = new NCVMemNativeAllocator(NCVMemoryTypeDevice, devProp.textureAlignment);
|
||||||
cpuCascadeAllocator = new NCVMemNativeAllocator(NCVMemoryTypeHostPinned, devProp.textureAlignment);
|
cpuCascadeAllocator = new NCVMemNativeAllocator(NCVMemoryTypeHostPinned, devProp.textureAlignment);
|
||||||
|
|
||||||
ncvAssertPrintReturn(gpuCascadeAllocator->isInitialized(), "Error creating cascade GPU allocator", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(gpuCascadeAllocator->isInitialized(), "Error creating cascade GPU allocator", NCV_CUDA_ERROR);
|
||||||
@ -149,12 +151,12 @@ private:
|
|||||||
ncvStat = ncvHaarGetClassifierSize(classifierFile, haarNumStages, haarNumNodes, haarNumFeatures);
|
ncvStat = ncvHaarGetClassifierSize(classifierFile, haarNumStages, haarNumNodes, haarNumFeatures);
|
||||||
ncvAssertPrintReturn(ncvStat == NCV_SUCCESS, "Error reading classifier size (check the file)", NCV_FILE_ERROR);
|
ncvAssertPrintReturn(ncvStat == NCV_SUCCESS, "Error reading classifier size (check the file)", NCV_FILE_ERROR);
|
||||||
|
|
||||||
h_haarStages = new NCVVectorAlloc<HaarStage64>(*cpuCascadeAllocator, haarNumStages);
|
h_haarStages = new NCVVectorAlloc<HaarStage64>(*cpuCascadeAllocator, haarNumStages);
|
||||||
h_haarNodes = new NCVVectorAlloc<HaarClassifierNode128>(*cpuCascadeAllocator, haarNumNodes);
|
h_haarNodes = new NCVVectorAlloc<HaarClassifierNode128>(*cpuCascadeAllocator, haarNumNodes);
|
||||||
h_haarFeatures = new NCVVectorAlloc<HaarFeature64>(*cpuCascadeAllocator, haarNumFeatures);
|
h_haarFeatures = new NCVVectorAlloc<HaarFeature64>(*cpuCascadeAllocator, haarNumFeatures);
|
||||||
|
|
||||||
ncvAssertPrintReturn(h_haarStages->isMemAllocated(), "Error in cascade CPU allocator", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(h_haarStages->isMemAllocated(), "Error in cascade CPU allocator", NCV_CUDA_ERROR);
|
||||||
ncvAssertPrintReturn(h_haarNodes->isMemAllocated(), "Error in cascade CPU allocator", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(h_haarNodes->isMemAllocated(), "Error in cascade CPU allocator", NCV_CUDA_ERROR);
|
||||||
ncvAssertPrintReturn(h_haarFeatures->isMemAllocated(), "Error in cascade CPU allocator", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(h_haarFeatures->isMemAllocated(), "Error in cascade CPU allocator", NCV_CUDA_ERROR);
|
||||||
|
|
||||||
ncvStat = ncvHaarLoadFromFile_host(classifierFile, haar, *h_haarStages, *h_haarNodes, *h_haarFeatures);
|
ncvStat = ncvHaarLoadFromFile_host(classifierFile, haar, *h_haarStages, *h_haarNodes, *h_haarFeatures);
|
||||||
@ -165,7 +167,7 @@ private:
|
|||||||
d_haarFeatures = new NCVVectorAlloc<HaarFeature64>(*gpuCascadeAllocator, haarNumFeatures);
|
d_haarFeatures = new NCVVectorAlloc<HaarFeature64>(*gpuCascadeAllocator, haarNumFeatures);
|
||||||
|
|
||||||
ncvAssertPrintReturn(d_haarStages->isMemAllocated(), "Error in cascade GPU allocator", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(d_haarStages->isMemAllocated(), "Error in cascade GPU allocator", NCV_CUDA_ERROR);
|
||||||
ncvAssertPrintReturn(d_haarNodes->isMemAllocated(), "Error in cascade GPU allocator", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(d_haarNodes->isMemAllocated(), "Error in cascade GPU allocator", NCV_CUDA_ERROR);
|
||||||
ncvAssertPrintReturn(d_haarFeatures->isMemAllocated(), "Error in cascade GPU allocator", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(d_haarFeatures->isMemAllocated(), "Error in cascade GPU allocator", NCV_CUDA_ERROR);
|
||||||
|
|
||||||
ncvStat = h_haarStages->copySolid(*d_haarStages, 0);
|
ncvStat = h_haarStages->copySolid(*d_haarStages, 0);
|
||||||
@ -173,31 +175,33 @@ private:
|
|||||||
ncvStat = h_haarNodes->copySolid(*d_haarNodes, 0);
|
ncvStat = h_haarNodes->copySolid(*d_haarNodes, 0);
|
||||||
ncvAssertPrintReturn(ncvStat == NCV_SUCCESS, "Error copying cascade to GPU", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(ncvStat == NCV_SUCCESS, "Error copying cascade to GPU", NCV_CUDA_ERROR);
|
||||||
ncvStat = h_haarFeatures->copySolid(*d_haarFeatures, 0);
|
ncvStat = h_haarFeatures->copySolid(*d_haarFeatures, 0);
|
||||||
ncvAssertPrintReturn(ncvStat == NCV_SUCCESS, "Error copying cascade to GPU", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(ncvStat == NCV_SUCCESS, "Error copying cascade to GPU", NCV_CUDA_ERROR);
|
||||||
|
|
||||||
return NCV_SUCCESS;
|
return NCV_SUCCESS;
|
||||||
}
|
}
|
||||||
////
|
|
||||||
|
|
||||||
NCVStatus calculateMemReqsAndAllocate(const Size& frameSize)
|
NCVStatus calculateMemReqsAndAllocate(const Size& frameSize)
|
||||||
{
|
{
|
||||||
if (lastAllocatedFrameSize == frameSize)
|
if (lastAllocatedFrameSize == frameSize)
|
||||||
|
{
|
||||||
return NCV_SUCCESS;
|
return NCV_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate memory requirements and create real allocators
|
// Calculate memory requirements and create real allocators
|
||||||
NCVMemStackAllocator gpuCounter(devProp.textureAlignment);
|
NCVMemStackAllocator gpuCounter(devProp.textureAlignment);
|
||||||
NCVMemStackAllocator cpuCounter(devProp.textureAlignment);
|
NCVMemStackAllocator cpuCounter(devProp.textureAlignment);
|
||||||
|
|
||||||
ncvAssertPrintReturn(gpuCounter.isInitialized(), "Error creating GPU memory counter", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(gpuCounter.isInitialized(), "Error creating GPU memory counter", NCV_CUDA_ERROR);
|
||||||
ncvAssertPrintReturn(cpuCounter.isInitialized(), "Error creating CPU memory counter", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(cpuCounter.isInitialized(), "Error creating CPU memory counter", NCV_CUDA_ERROR);
|
||||||
|
|
||||||
NCVMatrixAlloc<Ncv8u> d_src(gpuCounter, frameSize.width, frameSize.height);
|
NCVMatrixAlloc<Ncv8u> d_src(gpuCounter, frameSize.width, frameSize.height);
|
||||||
NCVMatrixAlloc<Ncv8u> h_src(cpuCounter, frameSize.width, frameSize.height);
|
NCVMatrixAlloc<Ncv8u> h_src(cpuCounter, frameSize.width, frameSize.height);
|
||||||
|
|
||||||
ncvAssertReturn(d_src.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
|
ncvAssertReturn(d_src.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
|
||||||
ncvAssertReturn(h_src.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
|
ncvAssertReturn(h_src.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
|
||||||
|
|
||||||
NCVVectorAlloc<NcvRect32u> d_rects(gpuCounter, 100);
|
NCVVectorAlloc<NcvRect32u> d_rects(gpuCounter, 100);
|
||||||
ncvAssertReturn(d_rects.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
|
ncvAssertReturn(d_rects.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
|
||||||
|
|
||||||
NcvSize32u roi;
|
NcvSize32u roi;
|
||||||
@ -209,23 +213,23 @@ private:
|
|||||||
|
|
||||||
ncvAssertReturnNcvStat(ncvStat);
|
ncvAssertReturnNcvStat(ncvStat);
|
||||||
ncvAssertCUDAReturn(cudaStreamSynchronize(0), NCV_CUDA_ERROR);
|
ncvAssertCUDAReturn(cudaStreamSynchronize(0), NCV_CUDA_ERROR);
|
||||||
|
|
||||||
gpuAllocator = new NCVMemStackAllocator(NCVMemoryTypeDevice, gpuCounter.maxSize(), devProp.textureAlignment);
|
gpuAllocator = new NCVMemStackAllocator(NCVMemoryTypeDevice, gpuCounter.maxSize(), devProp.textureAlignment);
|
||||||
cpuAllocator = new NCVMemStackAllocator(NCVMemoryTypeHostPinned, cpuCounter.maxSize(), devProp.textureAlignment);
|
cpuAllocator = new NCVMemStackAllocator(NCVMemoryTypeHostPinned, cpuCounter.maxSize(), devProp.textureAlignment);
|
||||||
|
|
||||||
ncvAssertPrintReturn(gpuAllocator->isInitialized(), "Error creating GPU memory allocator", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(gpuAllocator->isInitialized(), "Error creating GPU memory allocator", NCV_CUDA_ERROR);
|
||||||
ncvAssertPrintReturn(cpuAllocator->isInitialized(), "Error creating CPU memory allocator", NCV_CUDA_ERROR);
|
ncvAssertPrintReturn(cpuAllocator->isInitialized(), "Error creating CPU memory allocator", NCV_CUDA_ERROR);
|
||||||
return NCV_SUCCESS;
|
return NCV_SUCCESS;
|
||||||
}
|
}
|
||||||
////
|
|
||||||
|
|
||||||
cudaDeviceProp devProp;
|
cudaDeviceProp devProp;
|
||||||
NCVStatus ncvStat;
|
NCVStatus ncvStat;
|
||||||
|
|
||||||
Ptr<NCVMemNativeAllocator> gpuCascadeAllocator;
|
Ptr<NCVMemNativeAllocator> gpuCascadeAllocator;
|
||||||
Ptr<NCVMemNativeAllocator> cpuCascadeAllocator;
|
Ptr<NCVMemNativeAllocator> cpuCascadeAllocator;
|
||||||
|
|
||||||
Ptr<NCVVectorAlloc<HaarStage64> > h_haarStages;
|
Ptr<NCVVectorAlloc<HaarStage64> > h_haarStages;
|
||||||
Ptr<NCVVectorAlloc<HaarClassifierNode128> > h_haarNodes;
|
Ptr<NCVVectorAlloc<HaarClassifierNode128> > h_haarNodes;
|
||||||
Ptr<NCVVectorAlloc<HaarFeature64> > h_haarFeatures;
|
Ptr<NCVVectorAlloc<HaarFeature64> > h_haarFeatures;
|
||||||
|
|
||||||
@ -237,96 +241,103 @@ private:
|
|||||||
|
|
||||||
Size lastAllocatedFrameSize;
|
Size lastAllocatedFrameSize;
|
||||||
|
|
||||||
Ptr<NCVMemStackAllocator> gpuAllocator;
|
Ptr<NCVMemStackAllocator> gpuAllocator;
|
||||||
Ptr<NCVMemStackAllocator> cpuAllocator;
|
Ptr<NCVMemStackAllocator> cpuAllocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cv::gpu::CascadeClassifier_GPU::CascadeClassifier_GPU() : findLargestObject(false), visualizeInPlace(false), impl(0) {}
|
cv::gpu::CascadeClassifier_GPU::CascadeClassifier_GPU() : findLargestObject(false), visualizeInPlace(false), impl(0) {}
|
||||||
cv::gpu::CascadeClassifier_GPU::CascadeClassifier_GPU(const string& filename) : findLargestObject(false), visualizeInPlace(false), impl(0) { load(filename); }
|
cv::gpu::CascadeClassifier_GPU::CascadeClassifier_GPU(const string& filename) : findLargestObject(false), visualizeInPlace(false), impl(0) { load(filename); }
|
||||||
cv::gpu::CascadeClassifier_GPU::~CascadeClassifier_GPU() { release(); }
|
cv::gpu::CascadeClassifier_GPU::~CascadeClassifier_GPU() { release(); }
|
||||||
bool cv::gpu::CascadeClassifier_GPU::empty() const { return impl == 0; }
|
bool cv::gpu::CascadeClassifier_GPU::empty() const { return impl == 0; }
|
||||||
|
|
||||||
void cv::gpu::CascadeClassifier_GPU::release() { if (impl) { delete impl; impl = 0; } }
|
void cv::gpu::CascadeClassifier_GPU::release() { if (impl) { delete impl; impl = 0; } }
|
||||||
|
|
||||||
|
|
||||||
bool cv::gpu::CascadeClassifier_GPU::load(const string& filename)
|
bool cv::gpu::CascadeClassifier_GPU::load(const string& filename)
|
||||||
{
|
{
|
||||||
release();
|
release();
|
||||||
impl = new CascadeClassifierImpl(filename);
|
impl = new CascadeClassifierImpl(filename);
|
||||||
return !this->empty();
|
return !this->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Size cv::gpu::CascadeClassifier_GPU::getClassifierSize() const
|
Size cv::gpu::CascadeClassifier_GPU::getClassifierSize() const
|
||||||
{
|
{
|
||||||
return this->empty() ? Size() : impl->getClassifierCvSize();
|
return this->empty() ? Size() : impl->getClassifierCvSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int cv::gpu::CascadeClassifier_GPU::detectMultiScale( const GpuMat& image, GpuMat& objectsBuf, double scaleFactor, int minNeighbors, Size minSize)
|
int cv::gpu::CascadeClassifier_GPU::detectMultiScale( const GpuMat& image, GpuMat& objectsBuf, double scaleFactor, int minNeighbors, Size minSize)
|
||||||
{
|
{
|
||||||
CV_Assert( scaleFactor > 1 && image.depth() == CV_8U);
|
CV_Assert( scaleFactor > 1 && image.depth() == CV_8U);
|
||||||
CV_Assert( !this->empty());
|
CV_Assert( !this->empty());
|
||||||
|
|
||||||
const int defaultObjSearchNum = 100;
|
const int defaultObjSearchNum = 100;
|
||||||
if (objectsBuf.empty())
|
if (objectsBuf.empty())
|
||||||
|
{
|
||||||
objectsBuf.create(1, defaultObjSearchNum, DataType<Rect>::type);
|
objectsBuf.create(1, defaultObjSearchNum, DataType<Rect>::type);
|
||||||
|
}
|
||||||
|
|
||||||
NcvSize32u ncvMinSize = impl->getClassifierSize();
|
NcvSize32u ncvMinSize = impl->getClassifierSize();
|
||||||
|
|
||||||
if (ncvMinSize.width < (unsigned)minSize.width && ncvMinSize.height < (unsigned)minSize.height)
|
if (ncvMinSize.width < (unsigned)minSize.width && ncvMinSize.height < (unsigned)minSize.height)
|
||||||
{
|
{
|
||||||
ncvMinSize.width = minSize.width;
|
ncvMinSize.width = minSize.width;
|
||||||
ncvMinSize.height = minSize.height;
|
ncvMinSize.height = minSize.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int numDetections;
|
unsigned int numDetections;
|
||||||
NCVStatus ncvStat = impl->process(image, objectsBuf, (float)scaleFactor, minNeighbors, findLargestObject, visualizeInPlace, ncvMinSize, numDetections);
|
NCVStatus ncvStat = impl->process(image, objectsBuf, (float)scaleFactor, minNeighbors, findLargestObject, visualizeInPlace, ncvMinSize, numDetections);
|
||||||
if (ncvStat != NCV_SUCCESS)
|
if (ncvStat != NCV_SUCCESS)
|
||||||
|
{
|
||||||
CV_Error(CV_GpuApiCallError, "Error in face detectioln");
|
CV_Error(CV_GpuApiCallError, "Error in face detectioln");
|
||||||
|
}
|
||||||
|
|
||||||
return numDetections;
|
return numDetections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct RectConvert
|
struct RectConvert
|
||||||
{
|
{
|
||||||
Rect operator()(const NcvRect32u& nr) const { return Rect(nr.x, nr.y, nr.width, nr.height); }
|
Rect operator()(const NcvRect32u& nr) const { return Rect(nr.x, nr.y, nr.width, nr.height); }
|
||||||
NcvRect32u operator()(const Rect& nr) const
|
NcvRect32u operator()(const Rect& nr) const
|
||||||
{
|
{
|
||||||
NcvRect32u rect;
|
NcvRect32u rect;
|
||||||
rect.x = nr.x;
|
rect.x = nr.x;
|
||||||
rect.y = nr.y;
|
rect.y = nr.y;
|
||||||
rect.width = nr.width;
|
rect.width = nr.width;
|
||||||
rect.height = nr.height;
|
rect.height = nr.height;
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void groupRectangles(std::vector<NcvRect32u> &hypotheses, int groupThreshold, double eps, std::vector<Ncv32u> *weights)
|
void groupRectangles(std::vector<NcvRect32u> &hypotheses, int groupThreshold, double eps, std::vector<Ncv32u> *weights)
|
||||||
{
|
{
|
||||||
vector<Rect> rects(hypotheses.size());
|
vector<Rect> rects(hypotheses.size());
|
||||||
std::transform(hypotheses.begin(), hypotheses.end(), rects.begin(), RectConvert());
|
std::transform(hypotheses.begin(), hypotheses.end(), rects.begin(), RectConvert());
|
||||||
|
|
||||||
if (weights)
|
if (weights)
|
||||||
{
|
{
|
||||||
vector<int> weights_int;
|
vector<int> weights_int;
|
||||||
weights_int.assign(weights->begin(), weights->end());
|
weights_int.assign(weights->begin(), weights->end());
|
||||||
cv::groupRectangles(rects, weights_int, groupThreshold, eps);
|
cv::groupRectangles(rects, weights_int, groupThreshold, eps);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cv::groupRectangles(rects, groupThreshold, eps);
|
cv::groupRectangles(rects, groupThreshold, eps);
|
||||||
}
|
}
|
||||||
std::transform(rects.begin(), rects.end(), hypotheses.begin(), RectConvert());
|
std::transform(rects.begin(), rects.end(), hypotheses.begin(), RectConvert());
|
||||||
hypotheses.resize(rects.size());
|
hypotheses.resize(rects.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 1 /* loadFromXML implementation switch */
|
#if 1 /* loadFromXML implementation switch */
|
||||||
|
|
||||||
NCVStatus loadFromXML(const std::string &filename,
|
NCVStatus loadFromXML(const std::string &filename,
|
||||||
HaarClassifierCascadeDescriptor &haar,
|
HaarClassifierCascadeDescriptor &haar,
|
||||||
std::vector<HaarStage64> &haarStages,
|
std::vector<HaarStage64> &haarStages,
|
||||||
std::vector<HaarClassifierNode128> &haarClassifierNodes,
|
std::vector<HaarClassifierNode128> &haarClassifierNodes,
|
||||||
std::vector<HaarFeature64> &haarFeatures)
|
std::vector<HaarFeature64> &haarFeatures)
|
||||||
{
|
{
|
||||||
NCVStatus ncvStat;
|
NCVStatus ncvStat;
|
||||||
@ -347,12 +358,12 @@ NCVStatus loadFromXML(const std::string &filename,
|
|||||||
haarStages.resize(0);
|
haarStages.resize(0);
|
||||||
haarClassifierNodes.resize(0);
|
haarClassifierNodes.resize(0);
|
||||||
haarFeatures.resize(0);
|
haarFeatures.resize(0);
|
||||||
|
|
||||||
Ptr<CvHaarClassifierCascade> oldCascade = (CvHaarClassifierCascade*)cvLoad(filename.c_str(), 0, 0, 0);
|
Ptr<CvHaarClassifierCascade> oldCascade = (CvHaarClassifierCascade*)cvLoad(filename.c_str(), 0, 0, 0);
|
||||||
if (oldCascade.empty())
|
if (oldCascade.empty())
|
||||||
|
{
|
||||||
return NCV_HAAR_XML_LOADING_EXCEPTION;
|
return NCV_HAAR_XML_LOADING_EXCEPTION;
|
||||||
|
}
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
haar.ClassifierSize.width = oldCascade->orig_window_size.width;
|
haar.ClassifierSize.width = oldCascade->orig_window_size.width;
|
||||||
haar.ClassifierSize.height = oldCascade->orig_window_size.height;
|
haar.ClassifierSize.height = oldCascade->orig_window_size.height;
|
||||||
@ -384,14 +395,14 @@ NCVStatus loadFromXML(const std::string &filename,
|
|||||||
|
|
||||||
HaarClassifierNodeDescriptor32 nodeLeft;
|
HaarClassifierNodeDescriptor32 nodeLeft;
|
||||||
if ( tree->left[n] <= 0 )
|
if ( tree->left[n] <= 0 )
|
||||||
{
|
{
|
||||||
Ncv32f leftVal = tree->alpha[-tree->left[n]];
|
Ncv32f leftVal = tree->alpha[-tree->left[n]];
|
||||||
ncvStat = nodeLeft.create(leftVal);
|
ncvStat = nodeLeft.create(leftVal);
|
||||||
ncvAssertReturn(ncvStat == NCV_SUCCESS, ncvStat);
|
ncvAssertReturn(ncvStat == NCV_SUCCESS, ncvStat);
|
||||||
bIsLeftNodeLeaf = true;
|
bIsLeftNodeLeaf = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Ncv32u leftNodeOffset = tree->left[n];
|
Ncv32u leftNodeOffset = tree->left[n];
|
||||||
nodeLeft.create((Ncv32u)(h_TmpClassifierNotRootNodes.size() + leftNodeOffset - 1));
|
nodeLeft.create((Ncv32u)(h_TmpClassifierNotRootNodes.size() + leftNodeOffset - 1));
|
||||||
haar.bHasStumpsOnly = false;
|
haar.bHasStumpsOnly = false;
|
||||||
@ -419,8 +430,8 @@ NCVStatus loadFromXML(const std::string &filename,
|
|||||||
|
|
||||||
Ncv32u featureId = 0;
|
Ncv32u featureId = 0;
|
||||||
for(int l = 0; l < CV_HAAR_FEATURE_MAX; ++l) //by rects
|
for(int l = 0; l < CV_HAAR_FEATURE_MAX; ++l) //by rects
|
||||||
{
|
{
|
||||||
Ncv32u rectX = feature->rect[l].r.x;
|
Ncv32u rectX = feature->rect[l].r.x;
|
||||||
Ncv32u rectY = feature->rect[l].r.y;
|
Ncv32u rectY = feature->rect[l].r.y;
|
||||||
Ncv32u rectWidth = feature->rect[l].r.width;
|
Ncv32u rectWidth = feature->rect[l].r.width;
|
||||||
Ncv32u rectHeight = feature->rect[l].r.height;
|
Ncv32u rectHeight = feature->rect[l].r.height;
|
||||||
@ -441,7 +452,7 @@ NCVStatus loadFromXML(const std::string &filename,
|
|||||||
|
|
||||||
HaarFeatureDescriptor32 tmpFeatureDesc;
|
HaarFeatureDescriptor32 tmpFeatureDesc;
|
||||||
ncvStat = tmpFeatureDesc.create(haar.bNeedsTiltedII, bIsLeftNodeLeaf, bIsRightNodeLeaf,
|
ncvStat = tmpFeatureDesc.create(haar.bNeedsTiltedII, bIsLeftNodeLeaf, bIsRightNodeLeaf,
|
||||||
featureId, haarFeatures.size() - featureId);
|
featureId, haarFeatures.size() - featureId);
|
||||||
ncvAssertReturn(NCV_SUCCESS == ncvStat, ncvStat);
|
ncvAssertReturn(NCV_SUCCESS == ncvStat, ncvStat);
|
||||||
curNode.setFeatureDesc(tmpFeatureDesc);
|
curNode.setFeatureDesc(tmpFeatureDesc);
|
||||||
|
|
||||||
@ -466,8 +477,6 @@ NCVStatus loadFromXML(const std::string &filename,
|
|||||||
haarStages.push_back(curStage);
|
haarStages.push_back(curStage);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//fill in cascade stats
|
//fill in cascade stats
|
||||||
haar.NumStages = haarStages.size();
|
haar.NumStages = haarStages.size();
|
||||||
haar.NumClassifierRootNodes = haarClassifierNodes.size();
|
haar.NumClassifierRootNodes = haarClassifierNodes.size();
|
||||||
@ -496,6 +505,7 @@ NCVStatus loadFromXML(const std::string &filename,
|
|||||||
}
|
}
|
||||||
haarClassifierNodes[i].setRightNodeDesc(nodeRight);
|
haarClassifierNodes[i].setRightNodeDesc(nodeRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Ncv32u i=0; i<h_TmpClassifierNotRootNodes.size(); i++)
|
for (Ncv32u i=0; i<h_TmpClassifierNotRootNodes.size(); i++)
|
||||||
{
|
{
|
||||||
HaarFeatureDescriptor32 featureDesc = h_TmpClassifierNotRootNodes[i].getFeatureDesc();
|
HaarFeatureDescriptor32 featureDesc = h_TmpClassifierNotRootNodes[i].getFeatureDesc();
|
||||||
@ -522,8 +532,6 @@ NCVStatus loadFromXML(const std::string &filename,
|
|||||||
return NCV_SUCCESS;
|
return NCV_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
#else /* loadFromXML implementation switch */
|
#else /* loadFromXML implementation switch */
|
||||||
|
|
||||||
#include "e:/devNPP-OpenCV/src/external/_rapidxml-1.13/rapidxml.hpp"
|
#include "e:/devNPP-OpenCV/src/external/_rapidxml-1.13/rapidxml.hpp"
|
||||||
@ -793,5 +801,3 @@ NCVStatus loadFromXML(const std::string &filename,
|
|||||||
#endif /* loadFromXML implementation switch */
|
#endif /* loadFromXML implementation switch */
|
||||||
|
|
||||||
#endif /* HAVE_CUDA */
|
#endif /* HAVE_CUDA */
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,19 +1,29 @@
|
|||||||
// WARNING: this sample is under construction! Use it on your own risk.
|
// WARNING: this sample is under construction! Use it on your own risk.
|
||||||
|
#pragma warning(disable : 4100)
|
||||||
|
|
||||||
|
#include "cvconfig.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <opencv2/contrib/contrib.hpp>
|
#include <opencv2/contrib/contrib.hpp>
|
||||||
#include <opencv2/objdetect/objdetect.hpp>
|
#include <opencv2/objdetect/objdetect.hpp>
|
||||||
#include <opencv2/highgui/highgui.hpp>
|
#include <opencv2/highgui/highgui.hpp>
|
||||||
#include <opencv2/imgproc/imgproc.hpp>
|
#include <opencv2/imgproc/imgproc.hpp>
|
||||||
#include <opencv2/gpu/gpu.hpp>
|
#include <opencv2/gpu/gpu.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
using namespace cv::gpu;
|
using namespace cv::gpu;
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(HAVE_CUDA)
|
||||||
|
int main(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
cout << "Please compile the library with CUDA support" << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
|
||||||
void help()
|
void help()
|
||||||
{
|
{
|
||||||
cout << "Usage: ./cascadeclassifier <cascade_file> <image_or_video_or_cameraid>\n"
|
cout << "Usage: ./cascadeclassifier <cascade_file> <image_or_video_or_cameraid>\n"
|
||||||
@ -21,14 +31,8 @@ void help()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DetectAndDraw(Mat& img, CascadeClassifier_GPU& cascade);
|
template<class T>
|
||||||
|
void convertAndResize(const T& src, T& gray, T& resized, double scale)
|
||||||
|
|
||||||
String cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml";
|
|
||||||
String nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
|
|
||||||
|
|
||||||
|
|
||||||
template<class T> void convertAndResize(const T& src, T& gray, T& resized, double scale)
|
|
||||||
{
|
{
|
||||||
if (src.channels() == 3)
|
if (src.channels() == 3)
|
||||||
{
|
{
|
||||||
@ -54,15 +58,16 @@ template<class T> void convertAndResize(const T& src, T& gray, T& resized, doubl
|
|||||||
|
|
||||||
void matPrint(Mat &img, int lineOffsY, Scalar fontColor, const ostringstream &ss)
|
void matPrint(Mat &img, int lineOffsY, Scalar fontColor, const ostringstream &ss)
|
||||||
{
|
{
|
||||||
int fontFace = FONT_HERSHEY_PLAIN;
|
int fontFace = FONT_HERSHEY_DUPLEX;
|
||||||
double fontScale = 1.5;
|
double fontScale = 0.8;
|
||||||
int fontThickness = 2;
|
int fontThickness = 2;
|
||||||
Size fontSize = cv::getTextSize("T[]", fontFace, fontScale, fontThickness, 0);
|
Size fontSize = cv::getTextSize("T[]", fontFace, fontScale, fontThickness, 0);
|
||||||
|
|
||||||
Point org;
|
Point org;
|
||||||
org.x = 1;
|
org.x = 1;
|
||||||
org.y = 3 * fontSize.height * (lineOffsY + 1) / 2;
|
org.y = 3 * fontSize.height * (lineOffsY + 1) / 2;
|
||||||
putText(img, ss.str(), org, fontFace, fontScale, fontColor, fontThickness);
|
putText(img, ss.str(), org, fontFace, fontScale, CV_RGB(0,0,0), 5*fontThickness/2, 16);
|
||||||
|
putText(img, ss.str(), org, fontFace, fontScale, fontColor, fontThickness, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -72,25 +77,26 @@ void displayState(Mat &canvas, bool bHelp, bool bGpu, bool bLargestFace, bool bF
|
|||||||
Scalar fontColorNV = CV_RGB(118,185,0);
|
Scalar fontColorNV = CV_RGB(118,185,0);
|
||||||
|
|
||||||
ostringstream ss;
|
ostringstream ss;
|
||||||
|
ss << "FPS = " << setprecision(1) << fixed << fps;
|
||||||
|
matPrint(canvas, 0, fontColorRed, ss);
|
||||||
|
ss.str("");
|
||||||
ss << "[" << canvas.cols << "x" << canvas.rows << "], " <<
|
ss << "[" << canvas.cols << "x" << canvas.rows << "], " <<
|
||||||
(bGpu ? "GPU, " : "CPU, ") <<
|
(bGpu ? "GPU, " : "CPU, ") <<
|
||||||
(bLargestFace ? "OneFace, " : "MultiFace, ") <<
|
(bLargestFace ? "OneFace, " : "MultiFace, ") <<
|
||||||
(bFilter ? "Filter:ON, " : "Filter:OFF, ") <<
|
(bFilter ? "Filter:ON" : "Filter:OFF");
|
||||||
"FPS = " << setprecision(1) << fixed << fps;
|
matPrint(canvas, 1, fontColorRed, ss);
|
||||||
|
|
||||||
matPrint(canvas, 0, fontColorRed, ss);
|
|
||||||
|
|
||||||
if (bHelp)
|
if (bHelp)
|
||||||
{
|
{
|
||||||
matPrint(canvas, 1, fontColorNV, ostringstream("Space - switch GPU / CPU"));
|
matPrint(canvas, 2, fontColorNV, ostringstream("Space - switch GPU / CPU"));
|
||||||
matPrint(canvas, 2, fontColorNV, ostringstream("M - switch OneFace / MultiFace"));
|
matPrint(canvas, 3, fontColorNV, ostringstream("M - switch OneFace / MultiFace"));
|
||||||
matPrint(canvas, 3, fontColorNV, ostringstream("F - toggle rectangles Filter (only in MultiFace)"));
|
matPrint(canvas, 4, fontColorNV, ostringstream("F - toggle rectangles Filter"));
|
||||||
matPrint(canvas, 4, fontColorNV, ostringstream("H - toggle hotkeys help"));
|
matPrint(canvas, 5, fontColorNV, ostringstream("H - toggle hotkeys help"));
|
||||||
matPrint(canvas, 5, fontColorNV, ostringstream("1/Q - increase/decrease scale"));
|
matPrint(canvas, 6, fontColorNV, ostringstream("1/Q - increase/decrease scale"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
matPrint(canvas, 1, fontColorNV, ostringstream("H - toggle hotkeys help"));
|
matPrint(canvas, 2, fontColorNV, ostringstream("H - toggle hotkeys help"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,8 +136,10 @@ int main(int argc, const char *argv[])
|
|||||||
{
|
{
|
||||||
if (!capture.open(inputName))
|
if (!capture.open(inputName))
|
||||||
{
|
{
|
||||||
int camid = 0;
|
int camid = -1;
|
||||||
sscanf(inputName.c_str(), "%d", &camid);
|
istringstream iss(inputName);
|
||||||
|
iss >> camid;
|
||||||
|
|
||||||
if (!capture.open(camid))
|
if (!capture.open(camid))
|
||||||
{
|
{
|
||||||
cout << "Can't open source" << endl;
|
cout << "Can't open source" << endl;
|
||||||
@ -180,24 +188,26 @@ int main(int argc, const char *argv[])
|
|||||||
cascade_gpu.visualizeInPlace = true;
|
cascade_gpu.visualizeInPlace = true;
|
||||||
cascade_gpu.findLargestObject = findLargestObject;
|
cascade_gpu.findLargestObject = findLargestObject;
|
||||||
|
|
||||||
detections_num = cascade_gpu.detectMultiScale(resized_gpu, facesBuf_gpu, 1.2, filterRects ? 4 : 0);
|
detections_num = cascade_gpu.detectMultiScale(resized_gpu, facesBuf_gpu, 1.2,
|
||||||
|
(filterRects || findLargestObject) ? 4 : 0);
|
||||||
facesBuf_gpu.colRange(0, detections_num).download(faces_downloaded);
|
facesBuf_gpu.colRange(0, detections_num).download(faces_downloaded);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Size minSize = cascade_gpu.getClassifierSize();
|
Size minSize = cascade_gpu.getClassifierSize();
|
||||||
cascade_cpu.detectMultiScale(resized_cpu, facesBuf_cpu, 1.2, filterRects ? 4 : 0, (findLargestObject ? CV_HAAR_FIND_BIGGEST_OBJECT : 0) | CV_HAAR_SCALE_IMAGE, minSize);
|
cascade_cpu.detectMultiScale(resized_cpu, facesBuf_cpu, 1.2,
|
||||||
|
(filterRects || findLargestObject) ? 4 : 0,
|
||||||
|
(findLargestObject ? CV_HAAR_FIND_BIGGEST_OBJECT : 0)
|
||||||
|
| CV_HAAR_SCALE_IMAGE,
|
||||||
|
minSize);
|
||||||
detections_num = (int)facesBuf_cpu.size();
|
detections_num = (int)facesBuf_cpu.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!useGPU)
|
if (!useGPU && detections_num)
|
||||||
{
|
{
|
||||||
if (detections_num)
|
for (int i = 0; i < detections_num; ++i)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < detections_num; ++i)
|
rectangle(resized_cpu, facesBuf_cpu[i], Scalar(255));
|
||||||
{
|
|
||||||
rectangle(resized_cpu, facesBuf_cpu[i], Scalar(255));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,3 +275,5 @@ int main(int argc, const char *argv[])
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif //!defined(HAVE_CUDA)
|
||||||
|
@ -1,50 +1,76 @@
|
|||||||
#pragma warning( disable : 4201 4408 4127 4100)
|
#pragma warning( disable : 4201 4408 4127 4100)
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#include "cvconfig.h"
|
#include "cvconfig.h"
|
||||||
#if !defined(HAVE_CUDA)
|
#include <iostream>
|
||||||
int main( int argc, const char** argv ) { return printf("Please compile the library with CUDA support."), -1; }
|
#include <iomanip>
|
||||||
#else
|
#include <opencv2/opencv.hpp>
|
||||||
|
#include <opencv2/gpu/gpu.hpp>
|
||||||
#include <cuda_runtime.h>
|
|
||||||
#include "opencv2/opencv.hpp"
|
|
||||||
#include "NCVHaarObjectDetection.hpp"
|
#include "NCVHaarObjectDetection.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
|
|
||||||
const Size2i preferredVideoFrameSize(640, 480);
|
|
||||||
|
|
||||||
std::string preferredClassifier = "haarcascade_frontalface_alt.xml";
|
#if !defined(HAVE_CUDA)
|
||||||
std::string wndTitle = "NVIDIA Computer Vision SDK :: Face Detection in Video Feed";
|
int main( int argc, const char** argv )
|
||||||
|
|
||||||
|
|
||||||
void printSyntax(void)
|
|
||||||
{
|
{
|
||||||
printf("Syntax: FaceDetectionFeed.exe [-c cameranum | -v filename] classifier.xml\n");
|
cout << "Please compile the library with CUDA support" << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
|
||||||
|
const Size2i preferredVideoFrameSize(640, 480);
|
||||||
|
const string wndTitle = "NVIDIA Computer Vision :: Haar Classifiers Cascade";
|
||||||
|
|
||||||
|
|
||||||
|
void matPrint(Mat &img, int lineOffsY, Scalar fontColor, const ostringstream &ss)
|
||||||
|
{
|
||||||
|
int fontFace = FONT_HERSHEY_DUPLEX;
|
||||||
|
double fontScale = 0.8;
|
||||||
|
int fontThickness = 2;
|
||||||
|
Size fontSize = cv::getTextSize("T[]", fontFace, fontScale, fontThickness, 0);
|
||||||
|
|
||||||
|
Point org;
|
||||||
|
org.x = 1;
|
||||||
|
org.y = 3 * fontSize.height * (lineOffsY + 1) / 2;
|
||||||
|
putText(img, ss.str(), org, fontFace, fontScale, CV_RGB(0,0,0), 5*fontThickness/2, 16);
|
||||||
|
putText(img, ss.str(), org, fontFace, fontScale, fontColor, fontThickness, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void imagePrintf(Mat& img, int lineOffsY, Scalar color, const char *format, ...)
|
|
||||||
{
|
|
||||||
int fontFace = CV_FONT_HERSHEY_PLAIN;
|
|
||||||
double fontScale = 1;
|
|
||||||
|
|
||||||
int baseline;
|
|
||||||
Size textSize = cv::getTextSize("T", fontFace, fontScale, 1, &baseline);
|
|
||||||
|
|
||||||
va_list arg_ptr;
|
void displayState(Mat &canvas, bool bHelp, bool bGpu, bool bLargestFace, bool bFilter, double fps)
|
||||||
va_start(arg_ptr, format);
|
{
|
||||||
|
Scalar fontColorRed = CV_RGB(255,0,0);
|
||||||
|
Scalar fontColorNV = CV_RGB(118,185,0);
|
||||||
|
|
||||||
char strBuf[4096];
|
ostringstream ss;
|
||||||
vsprintf(&strBuf[0], format, arg_ptr);
|
ss << "FPS = " << setprecision(1) << fixed << fps;
|
||||||
|
matPrint(canvas, 0, fontColorRed, ss);
|
||||||
|
ss.str("");
|
||||||
|
ss << "[" << canvas.cols << "x" << canvas.rows << "], " <<
|
||||||
|
(bGpu ? "GPU, " : "CPU, ") <<
|
||||||
|
(bLargestFace ? "OneFace, " : "MultiFace, ") <<
|
||||||
|
(bFilter ? "Filter:ON" : "Filter:OFF");
|
||||||
|
matPrint(canvas, 1, fontColorRed, ss);
|
||||||
|
|
||||||
Point org(1, 3 * textSize.height * (lineOffsY + 1) / 2);
|
if (bHelp)
|
||||||
putText(img, &strBuf[0], org, fontFace, fontScale, color);
|
{
|
||||||
va_end(arg_ptr);
|
matPrint(canvas, 2, fontColorNV, ostringstream("Space - switch GPU / CPU"));
|
||||||
|
matPrint(canvas, 3, fontColorNV, ostringstream("M - switch OneFace / MultiFace"));
|
||||||
|
matPrint(canvas, 4, fontColorNV, ostringstream("F - toggle rectangles Filter"));
|
||||||
|
matPrint(canvas, 5, fontColorNV, ostringstream("H - toggle hotkeys help"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
matPrint(canvas, 2, fontColorNV, ostringstream("H - toggle hotkeys help"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NCVStatus process(Mat *srcdst,
|
NCVStatus process(Mat *srcdst,
|
||||||
Ncv32u width, Ncv32u height,
|
Ncv32u width, Ncv32u height,
|
||||||
NcvBool bShowAllHypotheses, NcvBool bLargestFace,
|
NcvBool bFilterRects, NcvBool bLargestFace,
|
||||||
HaarClassifierCascadeDescriptor &haar,
|
HaarClassifierCascadeDescriptor &haar,
|
||||||
NCVVector<HaarStage64> &d_haarStages, NCVVector<HaarClassifierNode128> &d_haarNodes,
|
NCVVector<HaarStage64> &d_haarStages, NCVVector<HaarClassifierNode128> &d_haarNodes,
|
||||||
NCVVector<HaarFeature64> &d_haarFeatures, NCVVector<HaarStage64> &h_haarStages,
|
NCVVector<HaarFeature64> &d_haarFeatures, NCVVector<HaarStage64> &h_haarStages,
|
||||||
@ -87,7 +113,7 @@ NCVStatus process(Mat *srcdst,
|
|||||||
d_src, roi, d_rects, numDetections, haar, h_haarStages,
|
d_src, roi, d_rects, numDetections, haar, h_haarStages,
|
||||||
d_haarStages, d_haarNodes, d_haarFeatures,
|
d_haarStages, d_haarNodes, d_haarFeatures,
|
||||||
haar.ClassifierSize,
|
haar.ClassifierSize,
|
||||||
bShowAllHypotheses ? 0 : 4,
|
(bFilterRects || bLargestFace) ? 4 : 0,
|
||||||
1.2f, 1,
|
1.2f, 1,
|
||||||
(bLargestFace ? NCVPipeObjDet_FindLargestObject : 0)
|
(bLargestFace ? NCVPipeObjDet_FindLargestObject : 0)
|
||||||
| NCVPipeObjDet_VisualizeInPlace,
|
| NCVPipeObjDet_VisualizeInPlace,
|
||||||
@ -111,80 +137,67 @@ NCVStatus process(Mat *srcdst,
|
|||||||
return NCV_SUCCESS;
|
return NCV_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main( int argc, const char** argv )
|
|
||||||
|
int main(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
|
cout << "OpenCV / NVIDIA Computer Vision" << endl;
|
||||||
|
cout << "Face Detection in video and live feed" << endl;
|
||||||
|
cout << "Syntax: exename <cascade_file> <image_or_video_or_cameraid>" << endl;
|
||||||
|
cout << "=========================================" << endl;
|
||||||
|
|
||||||
|
ncvAssertPrintReturn(cv::gpu::getCudaEnabledDeviceCount() != 0, "No GPU found or the library is compiled without GPU support", -1);
|
||||||
|
ncvAssertPrintReturn(argc == 3, "Invalid number of arguments", -1);
|
||||||
|
|
||||||
|
string cascadeName = argv[1];
|
||||||
|
string inputName = argv[2];
|
||||||
|
|
||||||
NCVStatus ncvStat;
|
NCVStatus ncvStat;
|
||||||
|
NcvBool bQuit = false;
|
||||||
printf("NVIDIA Computer Vision SDK\n");
|
VideoCapture capture;
|
||||||
printf("Face Detection in video and live feed\n");
|
|
||||||
printf("=========================================\n");
|
|
||||||
printf(" Esc - Quit\n");
|
|
||||||
printf(" Space - Switch between NCV and OpenCV\n");
|
|
||||||
printf(" L - Switch between FullSearch and LargestFace modes\n");
|
|
||||||
printf(" U - Toggle unfiltered hypotheses visualization in FullSearch\n");
|
|
||||||
|
|
||||||
VideoCapture capture;
|
|
||||||
bool bQuit = false;
|
|
||||||
|
|
||||||
Size2i frameSize;
|
Size2i frameSize;
|
||||||
|
|
||||||
if (argc != 4 && argc != 1)
|
//open content source
|
||||||
|
Mat image = imread(inputName);
|
||||||
|
Mat frame;
|
||||||
|
if (!image.empty())
|
||||||
{
|
{
|
||||||
printSyntax();
|
frameSize.width = image.cols;
|
||||||
return -1;
|
frameSize.height = image.rows;
|
||||||
}
|
|
||||||
|
|
||||||
if (argc == 1 || strcmp(argv[1], "-c") == 0)
|
|
||||||
{
|
|
||||||
// Camera input is specified
|
|
||||||
int camIdx = (argc == 3) ? atoi(argv[2]) : 0;
|
|
||||||
if(!capture.open(camIdx))
|
|
||||||
return printf("Error opening camera\n"), -1;
|
|
||||||
|
|
||||||
capture.set(CV_CAP_PROP_FRAME_WIDTH, preferredVideoFrameSize.width);
|
|
||||||
capture.set(CV_CAP_PROP_FRAME_HEIGHT, preferredVideoFrameSize.height);
|
|
||||||
capture.set(CV_CAP_PROP_FPS, 25);
|
|
||||||
frameSize = preferredVideoFrameSize;
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[1], "-v") == 0)
|
|
||||||
{
|
|
||||||
// Video file input (avi)
|
|
||||||
if(!capture.open(argv[2]))
|
|
||||||
return printf("Error opening video file\n"), -1;
|
|
||||||
|
|
||||||
frameSize.width = (int)capture.get(CV_CAP_PROP_FRAME_WIDTH);
|
|
||||||
frameSize.height = (int)capture.get(CV_CAP_PROP_FRAME_HEIGHT);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return printSyntax(), -1;
|
{
|
||||||
|
if (!capture.open(inputName))
|
||||||
|
{
|
||||||
|
int camid = -1;
|
||||||
|
|
||||||
NcvBool bUseOpenCV = true;
|
istringstream ss(inputName);
|
||||||
NcvBool bLargestFace = false; //LargestFace=true is used usually during training
|
int x = 0;
|
||||||
NcvBool bShowAllHypotheses = false;
|
ss >> x;
|
||||||
|
|
||||||
|
ncvAssertPrintReturn(capture.open(camid) != 0, "Can't open source", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
capture >> frame;
|
||||||
|
ncvAssertPrintReturn(!frame.empty(), "Empty video source", -1);
|
||||||
|
|
||||||
|
frameSize.width = frame.cols;
|
||||||
|
frameSize.height = frame.rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
NcvBool bUseGPU = true;
|
||||||
|
NcvBool bLargestObject = false;
|
||||||
|
NcvBool bFilterRects = true;
|
||||||
|
NcvBool bHelpScreen = false;
|
||||||
|
|
||||||
CascadeClassifier classifierOpenCV;
|
CascadeClassifier classifierOpenCV;
|
||||||
std::string classifierFile;
|
ncvAssertPrintReturn(classifierOpenCV.load(cascadeName) != 0, "Error (in OpenCV) opening classifier", -1);
|
||||||
if (argc == 1)
|
|
||||||
{
|
|
||||||
classifierFile = preferredClassifier;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
classifierFile.assign(argv[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!classifierOpenCV.load(classifierFile))
|
|
||||||
{
|
|
||||||
printf("Error (in OpenCV) opening classifier\n");
|
|
||||||
printSyntax();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int devId;
|
int devId;
|
||||||
ncvAssertCUDAReturn(cudaGetDevice(&devId), -1);
|
ncvAssertCUDAReturn(cudaGetDevice(&devId), -1);
|
||||||
cudaDeviceProp devProp;
|
cudaDeviceProp devProp;
|
||||||
ncvAssertCUDAReturn(cudaGetDeviceProperties(&devProp, devId), -1);
|
ncvAssertCUDAReturn(cudaGetDeviceProperties(&devProp, devId), -1);
|
||||||
printf("Using GPU %d %s, arch=%d.%d\n", devId, devProp.name, devProp.major, devProp.minor);
|
cout << "Using GPU: " << devId << "(" << devProp.name <<
|
||||||
|
"), arch=" << devProp.major << "." << devProp.minor << endl;
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
//
|
//
|
||||||
@ -199,7 +212,7 @@ int main( int argc, const char** argv )
|
|||||||
ncvAssertPrintReturn(cpuCascadeAllocator.isInitialized(), "Error creating cascade CPU allocator", -1);
|
ncvAssertPrintReturn(cpuCascadeAllocator.isInitialized(), "Error creating cascade CPU allocator", -1);
|
||||||
|
|
||||||
Ncv32u haarNumStages, haarNumNodes, haarNumFeatures;
|
Ncv32u haarNumStages, haarNumNodes, haarNumFeatures;
|
||||||
ncvStat = ncvHaarGetClassifierSize(classifierFile, haarNumStages, haarNumNodes, haarNumFeatures);
|
ncvStat = ncvHaarGetClassifierSize(cascadeName, haarNumStages, haarNumNodes, haarNumFeatures);
|
||||||
ncvAssertPrintReturn(ncvStat == NCV_SUCCESS, "Error reading classifier size (check the file)", -1);
|
ncvAssertPrintReturn(ncvStat == NCV_SUCCESS, "Error reading classifier size (check the file)", -1);
|
||||||
|
|
||||||
NCVVectorAlloc<HaarStage64> h_haarStages(cpuCascadeAllocator, haarNumStages);
|
NCVVectorAlloc<HaarStage64> h_haarStages(cpuCascadeAllocator, haarNumStages);
|
||||||
@ -210,7 +223,7 @@ int main( int argc, const char** argv )
|
|||||||
ncvAssertPrintReturn(h_haarFeatures.isMemAllocated(), "Error in cascade CPU allocator", -1);
|
ncvAssertPrintReturn(h_haarFeatures.isMemAllocated(), "Error in cascade CPU allocator", -1);
|
||||||
|
|
||||||
HaarClassifierCascadeDescriptor haar;
|
HaarClassifierCascadeDescriptor haar;
|
||||||
ncvStat = ncvHaarLoadFromFile_host(classifierFile, haar, h_haarStages, h_haarNodes, h_haarFeatures);
|
ncvStat = ncvHaarLoadFromFile_host(cascadeName, haar, h_haarStages, h_haarNodes, h_haarFeatures);
|
||||||
ncvAssertPrintReturn(ncvStat == NCV_SUCCESS, "Error loading classifier", -1);
|
ncvAssertPrintReturn(ncvStat == NCV_SUCCESS, "Error loading classifier", -1);
|
||||||
|
|
||||||
NCVVectorAlloc<HaarStage64> d_haarStages(gpuCascadeAllocator, haarNumStages);
|
NCVVectorAlloc<HaarStage64> d_haarStages(gpuCascadeAllocator, haarNumStages);
|
||||||
@ -258,30 +271,25 @@ int main( int argc, const char** argv )
|
|||||||
//
|
//
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
namedWindow(wndTitle, 1);
|
namedWindow(wndTitle, 1);
|
||||||
Mat frame, gray, frameDisp;
|
Mat gray, frameDisp;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// For camera and video file, capture the next image
|
|
||||||
capture >> frame;
|
|
||||||
if (frame.empty())
|
|
||||||
break;
|
|
||||||
|
|
||||||
Mat gray;
|
Mat gray;
|
||||||
cvtColor(frame, gray, CV_BGR2GRAY);
|
cvtColor((image.empty() ? frame : image), gray, CV_BGR2GRAY);
|
||||||
|
|
||||||
//
|
//
|
||||||
// process
|
// process
|
||||||
//
|
//
|
||||||
|
|
||||||
NcvSize32u minSize = haar.ClassifierSize;
|
NcvSize32u minSize = haar.ClassifierSize;
|
||||||
if (bLargestFace)
|
if (bLargestObject)
|
||||||
{
|
{
|
||||||
Ncv32u ratioX = preferredVideoFrameSize.width / minSize.width;
|
Ncv32u ratioX = preferredVideoFrameSize.width / minSize.width;
|
||||||
Ncv32u ratioY = preferredVideoFrameSize.height / minSize.height;
|
Ncv32u ratioY = preferredVideoFrameSize.height / minSize.height;
|
||||||
Ncv32u ratioSmallest = std::min(ratioX, ratioY);
|
Ncv32u ratioSmallest = min(ratioX, ratioY);
|
||||||
ratioSmallest = std::max((Ncv32u)(ratioSmallest / 2.5f), (Ncv32u)1);
|
ratioSmallest = max((Ncv32u)(ratioSmallest / 2.5f), (Ncv32u)1);
|
||||||
minSize.width *= ratioSmallest;
|
minSize.width *= ratioSmallest;
|
||||||
minSize.height *= ratioSmallest;
|
minSize.height *= ratioSmallest;
|
||||||
}
|
}
|
||||||
@ -289,10 +297,10 @@ int main( int argc, const char** argv )
|
|||||||
Ncv32f avgTime;
|
Ncv32f avgTime;
|
||||||
NcvTimer timer = ncvStartTimer();
|
NcvTimer timer = ncvStartTimer();
|
||||||
|
|
||||||
if (!bUseOpenCV)
|
if (bUseGPU)
|
||||||
{
|
{
|
||||||
ncvStat = process(&gray, frameSize.width, frameSize.height,
|
ncvStat = process(&gray, frameSize.width, frameSize.height,
|
||||||
bShowAllHypotheses, bLargestFace, haar,
|
bFilterRects, bLargestObject, haar,
|
||||||
d_haarStages, d_haarNodes,
|
d_haarStages, d_haarNodes,
|
||||||
d_haarFeatures, h_haarStages,
|
d_haarFeatures, h_haarStages,
|
||||||
gpuAllocator, cpuAllocator, devProp);
|
gpuAllocator, cpuAllocator, devProp);
|
||||||
@ -306,8 +314,8 @@ int main( int argc, const char** argv )
|
|||||||
gray,
|
gray,
|
||||||
rectsOpenCV,
|
rectsOpenCV,
|
||||||
1.2f,
|
1.2f,
|
||||||
bShowAllHypotheses && !bLargestFace ? 0 : 4,
|
bFilterRects ? 4 : 0,
|
||||||
(bLargestFace ? CV_HAAR_FIND_BIGGEST_OBJECT : 0)
|
(bLargestObject ? CV_HAAR_FIND_BIGGEST_OBJECT : 0)
|
||||||
| CV_HAAR_SCALE_IMAGE,
|
| CV_HAAR_SCALE_IMAGE,
|
||||||
Size(minSize.width, minSize.height));
|
Size(minSize.width, minSize.height));
|
||||||
|
|
||||||
@ -318,32 +326,41 @@ int main( int argc, const char** argv )
|
|||||||
avgTime = (Ncv32f)ncvEndQueryTimerMs(timer);
|
avgTime = (Ncv32f)ncvEndQueryTimerMs(timer);
|
||||||
|
|
||||||
cvtColor(gray, frameDisp, CV_GRAY2BGR);
|
cvtColor(gray, frameDisp, CV_GRAY2BGR);
|
||||||
|
displayState(frameDisp, bHelpScreen, bUseGPU, bLargestObject, bFilterRects, 1000.0f / avgTime);
|
||||||
|
imshow(wndTitle, frameDisp);
|
||||||
|
|
||||||
imagePrintf(frameDisp, 0, CV_RGB(255, 0,0), "Space - Switch NCV%s / OpenCV%s", bUseOpenCV?"":" (ON)", bUseOpenCV?" (ON)":"");
|
//handle input
|
||||||
imagePrintf(frameDisp, 1, CV_RGB(255, 0,0), "L - Switch FullSearch%s / LargestFace%s modes", bLargestFace?"":" (ON)", bLargestFace?" (ON)":"");
|
|
||||||
imagePrintf(frameDisp, 2, CV_RGB(255, 0,0), "U - Toggle unfiltered hypotheses visualization in FullSearch %s", bShowAllHypotheses?"(ON)":"(OFF)");
|
|
||||||
imagePrintf(frameDisp, 3, CV_RGB(118,185,0), " Running at %f FPS on %s", 1000.0f / avgTime, bUseOpenCV?"CPU":"GPU");
|
|
||||||
|
|
||||||
cv::imshow(wndTitle, frameDisp);
|
|
||||||
|
|
||||||
switch (cvWaitKey(3))
|
switch (cvWaitKey(3))
|
||||||
{
|
{
|
||||||
case ' ':
|
case ' ':
|
||||||
bUseOpenCV = !bUseOpenCV;
|
bUseGPU = !bUseGPU;
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'm':
|
||||||
case 'l':
|
case 'M':
|
||||||
bLargestFace = !bLargestFace;
|
bLargestObject = !bLargestObject;
|
||||||
break;
|
break;
|
||||||
case 'U':
|
case 'f':
|
||||||
case 'u':
|
case 'F':
|
||||||
bShowAllHypotheses = !bShowAllHypotheses;
|
bFilterRects = !bFilterRects;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case 'H':
|
||||||
|
bHelpScreen = !bHelpScreen;
|
||||||
break;
|
break;
|
||||||
case 27:
|
case 27:
|
||||||
bQuit = true;
|
bQuit = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For camera and video file, capture the next image
|
||||||
|
if (capture.isOpened())
|
||||||
|
{
|
||||||
|
capture >> frame;
|
||||||
|
if (frame.empty())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} while (!bQuit);
|
} while (!bQuit);
|
||||||
|
|
||||||
cvDestroyWindow(wndTitle.c_str());
|
cvDestroyWindow(wndTitle.c_str());
|
||||||
@ -351,5 +368,4 @@ int main( int argc, const char** argv )
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif //!defined(HAVE_CUDA)
|
||||||
#endif
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user