Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
1b7ad93d
Commit
1b7ad93d
authored
Jul 24, 2012
by
marina.kolpakova
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
LBP features integrated in CascadeClassifier_GPU
parent
2dc93574
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
504 additions
and
491 deletions
+504
-491
gpu.hpp
modules/gpu/include/opencv2/gpu/gpu.hpp
+20
-34
perf_objdetect.cpp
modules/gpu/perf/perf_objdetect.cpp
+1
-1
cascadeclassifier.cpp
modules/gpu/src/cascadeclassifier.cpp
+473
-447
lbp.cu
modules/gpu/src/cuda/lbp.cu
+1
-0
test_objdetect.cpp
modules/gpu/test/test_objdetect.cpp
+9
-9
No files found.
modules/gpu/include/opencv2/gpu/gpu.hpp
View file @
1b7ad93d
...
@@ -1397,7 +1397,7 @@ public:
...
@@ -1397,7 +1397,7 @@ public:
};
};
////////////////////////////////// CascadeClassifier_GPU //////////////////////////////////////////
////////////////////////////////// CascadeClassifier_GPU //////////////////////////////////////////
// The cascade classifier class for object detection
.
// The cascade classifier class for object detection
: supports old haar and new lbp xlm formats and nvbin for haar cascades olny.
class
CV_EXPORTS
CascadeClassifier_GPU
class
CV_EXPORTS
CascadeClassifier_GPU
{
{
public
:
public
:
...
@@ -1407,42 +1407,28 @@ public:
...
@@ -1407,42 +1407,28 @@ public:
bool
empty
()
const
;
bool
empty
()
const
;
bool
load
(
const
std
::
string
&
filename
);
bool
load
(
const
std
::
string
&
filename
);
void
release
();
void
release
();
/* returns number of detected objects */
int
detectMultiScale
(
const
GpuMat
&
image
,
GpuMat
&
objectsBuf
,
double
scaleFactor
=
1.2
,
int
minNeighbors
=
4
,
Size
minSize
=
Size
());
bool
findLargestObject
;
bool
visualizeInPlace
;
Size
getClassifierSize
()
const
;
private
:
struct
CascadeClassifierImpl
;
CascadeClassifierImpl
*
impl
;
};
// The cascade classifier class for object detection.
class
CV_EXPORTS
CascadeClassifier_GPU_LBP
{
public
:
CascadeClassifier_GPU_LBP
(
cv
::
Size
detectionFrameSize
=
cv
::
Size
());
~
CascadeClassifier_GPU_LBP
();
bool
empty
()
const
;
bool
load
(
const
std
::
string
&
filename
);
void
release
();
int
detectMultiScale
(
const
GpuMat
&
image
,
GpuMat
&
objectsBuf
,
double
scaleFactor
=
1.1
,
int
minNeighbors
=
4
,
cv
::
Size
maxObjectSize
=
cv
::
Size
()
/*, Size minSize = Size()*/
);
Size
getClassifierSize
()
const
;
private
:
/* returns number of detected objects */
int
detectMultiScale
(
const
GpuMat
&
image
,
GpuMat
&
objectsBuf
,
double
scaleFactor
=
1.2
,
int
minNeighbors
=
4
,
Size
minSize
=
Size
());
bool
findLargestObject
;
bool
visualizeInPlace
;
Size
getClassifierSize
()
const
;
private
:
struct
CascadeClassifierImpl
;
struct
CascadeClassifierImpl
;
CascadeClassifierImpl
*
impl
;
CascadeClassifierImpl
*
impl
;
};
struct
HaarCascade
;
struct
LbpCascade
;
////////////////////////////////// SURF //////////////////////////////////////////
friend
class
CascadeClassifier_GPU_LBP
;
public
:
int
detectMultiScale
(
const
GpuMat
&
image
,
GpuMat
&
objectsBuf
,
Size
maxObjectSize
,
Size
minSize
=
Size
(),
double
scaleFactor
=
1.1
,
int
minNeighbors
=
4
);
};
////////////////////////////////// SURF //////////////////////////////////////////
class
CV_EXPORTS
SURF_GPU
class
CV_EXPORTS
SURF_GPU
{
{
...
...
modules/gpu/perf/perf_objdetect.cpp
View file @
1b7ad93d
...
@@ -70,7 +70,7 @@ GPU_PERF_TEST_1(LBPClassifier, cv::gpu::DeviceInfo)
...
@@ -70,7 +70,7 @@ GPU_PERF_TEST_1(LBPClassifier, cv::gpu::DeviceInfo)
cv
::
gpu
::
GpuMat
img
(
img_host
);
cv
::
gpu
::
GpuMat
img
(
img_host
);
cv
::
gpu
::
GpuMat
gpu_rects
;
cv
::
gpu
::
GpuMat
gpu_rects
;
cv
::
gpu
::
CascadeClassifier_GPU
_LBP
cascade
(
img
.
size
());
cv
::
gpu
::
CascadeClassifier_GPU
cascade
;
ASSERT_TRUE
(
cascade
.
load
(
perf
::
TestBase
::
getDataPath
(
"gpu/lbpcascade/lbpcascade_frontalface.xml"
)));
ASSERT_TRUE
(
cascade
.
load
(
perf
::
TestBase
::
getDataPath
(
"gpu/lbpcascade/lbpcascade_frontalface.xml"
)));
cascade
.
detectMultiScale
(
img
,
gpu_rects
);
cascade
.
detectMultiScale
(
img
,
gpu_rects
);
...
...
modules/gpu/src/cascadeclassifier.cpp
View file @
1b7ad93d
...
@@ -46,439 +46,54 @@
...
@@ -46,439 +46,54 @@
using
namespace
cv
;
using
namespace
cv
;
using
namespace
cv
::
gpu
;
using
namespace
cv
::
gpu
;
using
namespace
std
;
using
namespace
std
;
#if !defined (HAVE_CUDA)
// ============ old fashioned haar cascade ==============================================//
cv
::
gpu
::
CascadeClassifier_GPU
::
CascadeClassifier_GPU
()
{
throw_nogpu
();
}
cv
::
gpu
::
CascadeClassifier_GPU
::
CascadeClassifier_GPU
(
const
string
&
)
{
throw_nogpu
();
}
cv
::
gpu
::
CascadeClassifier_GPU
::~
CascadeClassifier_GPU
()
{
throw_nogpu
();
}
bool
cv
::
gpu
::
CascadeClassifier_GPU
::
empty
()
const
{
throw_nogpu
();
return
true
;
}
bool
cv
::
gpu
::
CascadeClassifier_GPU
::
load
(
const
string
&
)
{
throw_nogpu
();
return
true
;
}
Size
cv
::
gpu
::
CascadeClassifier_GPU
::
getClassifierSize
()
const
{
throw_nogpu
();
return
Size
();
}
int
cv
::
gpu
::
CascadeClassifier_GPU
::
detectMultiScale
(
const
GpuMat
&
,
GpuMat
&
,
double
,
int
,
Size
)
{
throw_nogpu
();
return
0
;
}
// ============ LBP cascade ==============================================//
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
CascadeClassifier_GPU_LBP
(
cv
::
Size
/*frameSize*/
){
throw_nogpu
();
}
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::~
CascadeClassifier_GPU_LBP
()
{
throw_nogpu
();
}
bool
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
empty
()
const
{
throw_nogpu
();
return
true
;
}
bool
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
load
(
const
string
&
)
{
throw_nogpu
();
return
true
;
}
Size
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
getClassifierSize
()
const
{
throw_nogpu
();
return
Size
();
}
void
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
allocateBuffers
(
cv
::
Size
/*frame*/
)
{
throw_nogpu
();}
int
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
detectMultiScale
(
const
cv
::
gpu
::
GpuMat
&
/*image*/
,
cv
::
gpu
::
GpuMat
&
/*objectsBuf*/
,
double
/*scaleFactor*/
,
int
/*minNeighbors*/
,
cv
::
Size
/*maxObjectSize*/
){
throw_nogpu
();
return
0
;}
#else
cv
::
Size
operator
-
(
const
cv
::
Size
&
a
,
const
cv
::
Size
&
b
)
{
return
cv
::
Size
(
a
.
width
-
b
.
width
,
a
.
height
-
b
.
height
);
}
cv
::
Size
operator
+
(
const
cv
::
Size
&
a
,
const
int
&
i
)
{
return
cv
::
Size
(
a
.
width
+
i
,
a
.
height
+
i
);
}
cv
::
Size
operator
*
(
const
cv
::
Size
&
a
,
const
float
&
f
)
#if !defined (HAVE_CUDA)
{
return
cv
::
Size
(
cvRound
(
a
.
width
*
f
),
cvRound
(
a
.
height
*
f
));
}
cv
::
Size
operator
/
(
const
cv
::
Size
&
a
,
const
float
&
f
)
cv
::
gpu
::
CascadeClassifier_GPU
::
CascadeClassifier_GPU
()
{
throw_nogpu
();
}
{
cv
::
gpu
::
CascadeClassifier_GPU
::
CascadeClassifier_GPU
(
const
string
&
)
{
throw_nogpu
();
}
return
cv
::
Size
(
cvRound
(
a
.
width
/
f
),
cvRound
(
a
.
height
/
f
));
cv
::
gpu
::
CascadeClassifier_GPU
::~
CascadeClassifier_GPU
()
{
throw_nogpu
();
}
}
bool
cv
::
gpu
::
CascadeClassifier_GPU
::
empty
()
const
{
throw_nogpu
();
return
true
;
}
bool
cv
::
gpu
::
CascadeClassifier_GPU
::
load
(
const
string
&
)
{
throw_nogpu
();
return
true
;
}
Size
cv
::
gpu
::
CascadeClassifier_GPU
::
getClassifierSize
()
const
{
throw_nogpu
();
return
Size
();}
void
cv
::
gpu
::
CascadeClassifier_GPU
::
release
()
{
throw_nogpu
();
}
int
cv
::
gpu
::
CascadeClassifier_GPU
::
detectMultiScale
(
const
GpuMat
&
,
GpuMat
&
,
double
,
int
,
Size
)
{
throw_nogpu
();
return
-
1
;}
int
cv
::
gpu
::
CascadeClassifier_GPU
::
detectMultiScale
(
const
GpuMat
&
,
GpuMat
&
,
Size
,
Size
,
double
,
int
)
{
throw_nogpu
();
return
-
1
;}
bool
operator
<=
(
const
cv
::
Size
&
a
,
const
cv
::
Size
&
b
)
#else
{
return
a
.
width
<=
b
.
width
&&
a
.
height
<=
b
.
width
;
}
struct
PyrLave
l
struct
cv
::
gpu
::
CascadeClassifier_GPU
::
CascadeClassifierImp
l
{
{
PyrLavel
(
int
_order
,
float
_scale
,
cv
::
Size
frame
,
cv
::
Size
window
)
:
order
(
_order
)
public
:
{
CascadeClassifierImpl
(){}
scale
=
pow
(
_scale
,
order
);
virtual
~
CascadeClassifierImpl
(){}
sFrame
=
frame
/
scale
;
workArea
=
sFrame
-
window
+
1
;
sWindow
=
window
*
scale
;
}
bool
isFeasible
(
cv
::
Size
maxObj
)
{
return
workArea
.
width
>
0
&&
workArea
.
height
>
0
&&
sWindow
<=
maxObj
;
}
PyrLavel
next
(
float
factor
,
cv
::
Size
frame
,
cv
::
Size
window
)
virtual
unsigned
int
process
(
const
GpuMat
&
src
,
GpuMat
&
objects
,
float
scaleStep
,
int
minNeighbors
,
{
bool
findLargestObject
,
bool
visualizeInPlace
,
cv
::
Size
ncvMinSize
,
cv
::
Size
maxObjectSize
)
=
0
;
return
PyrLavel
(
order
+
1
,
factor
,
frame
,
window
);
}
int
order
;
virtual
cv
::
Size
getClassifierCvSize
()
const
=
0
;
float
scale
;
virtual
bool
read
(
const
string
&
classifierAsXml
)
=
0
;
cv
::
Size
sFrame
;
cv
::
Size
workArea
;
cv
::
Size
sWindow
;
};
};
namespace
cv
{
namespace
gpu
{
namespace
device
struct
cv
::
gpu
::
CascadeClassifier_GPU
::
HaarCascade
:
cv
::
gpu
::
CascadeClassifier_GPU
::
CascadeClassifierImpl
{
{
namespace
lbp
public
:
HaarCascade
()
:
lastAllocatedFrameSize
(
-
1
,
-
1
)
{
{
void
classifyPyramid
(
int
frameW
,
ncvSetDebugOutputHandler
(
NCVDebugOutputHandler
);
int
frameH
,
int
windowW
,
int
windowH
,
float
initalScale
,
float
factor
,
int
total
,
const
DevMem2Db
&
mstages
,
const
int
nstages
,
const
DevMem2Di
&
mnodes
,
const
DevMem2Df
&
mleaves
,
const
DevMem2Di
&
msubsets
,
const
DevMem2Db
&
mfeatures
,
const
int
subsetSize
,
DevMem2D_
<
int4
>
objects
,
unsigned
int
*
classified
,
DevMem2Di
integral
);
void
connectedConmonents
(
DevMem2D_
<
int4
>
candidates
,
int
ncandidates
,
DevMem2D_
<
int4
>
objects
,
int
groupThreshold
,
float
grouping_eps
,
unsigned
int
*
nclasses
);
}
}
}}}
struct
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
CascadeClassifierImpl
bool
read
(
const
string
&
filename
)
{
public
:
struct
Stage
{
{
int
first
;
ncvSafeCall
(
load
(
filename
)
);
int
ntrees
;
return
true
;
float
threshold
;
}
};
bool
read
(
const
FileNode
&
root
);
void
allocateBuffers
(
cv
::
Size
frame
=
cv
::
Size
());
bool
empty
()
const
{
return
stage_mat
.
empty
();}
int
process
(
const
GpuMat
&
image
,
GpuMat
&
objects
,
double
scaleFactor
,
int
groupThreshold
,
cv
::
Size
maxObjectSize
);
private
:
enum
stage
{
BOOST
=
0
};
enum
feature
{
LBP
=
0
};
static
const
stage
stageType
=
BOOST
;
static
const
feature
featureType
=
LBP
;
cv
::
Size
NxM
;
bool
isStumps
;
int
ncategories
;
int
subsetSize
;
int
nodeStep
;
// gpu representation of classifier
GpuMat
stage_mat
;
GpuMat
trees_mat
;
GpuMat
nodes_mat
;
GpuMat
leaves_mat
;
GpuMat
subsets_mat
;
GpuMat
features_mat
;
GpuMat
integral
;
GpuMat
integralBuffer
;
GpuMat
resuzeBuffer
;
GpuMat
candidates
;
static
const
int
integralFactor
=
4
;
};
void
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
CascadeClassifierImpl
::
allocateBuffers
(
cv
::
Size
frame
)
{
if
(
frame
==
cv
::
Size
())
return
;
if
(
resuzeBuffer
.
empty
()
||
frame
.
width
>
resuzeBuffer
.
cols
||
frame
.
height
>
resuzeBuffer
.
rows
)
{
resuzeBuffer
.
create
(
frame
,
CV_8UC1
);
integral
.
create
(
frame
.
height
+
1
,
integralFactor
*
(
frame
.
width
+
1
),
CV_32SC1
);
NcvSize32u
roiSize
;
roiSize
.
width
=
frame
.
width
;
roiSize
.
height
=
frame
.
height
;
cudaDeviceProp
prop
;
cudaSafeCall
(
cudaGetDeviceProperties
(
&
prop
,
cv
::
gpu
::
getDevice
())
);
Ncv32u
bufSize
;
ncvSafeCall
(
nppiStIntegralGetSize_8u32u
(
roiSize
,
&
bufSize
,
prop
)
);
integralBuffer
.
create
(
1
,
bufSize
,
CV_8UC1
);
candidates
.
create
(
1
,
frame
.
width
>>
1
,
CV_32SC4
);
}
}
// currently only stump based boost classifiers are supported
bool
CascadeClassifier_GPU_LBP
::
CascadeClassifierImpl
::
read
(
const
FileNode
&
root
)
{
const
char
*
GPU_CC_STAGE_TYPE
=
"stageType"
;
const
char
*
GPU_CC_FEATURE_TYPE
=
"featureType"
;
const
char
*
GPU_CC_BOOST
=
"BOOST"
;
const
char
*
GPU_CC_LBP
=
"LBP"
;
const
char
*
GPU_CC_MAX_CAT_COUNT
=
"maxCatCount"
;
const
char
*
GPU_CC_HEIGHT
=
"height"
;
const
char
*
GPU_CC_WIDTH
=
"width"
;
const
char
*
GPU_CC_STAGE_PARAMS
=
"stageParams"
;
const
char
*
GPU_CC_MAX_DEPTH
=
"maxDepth"
;
const
char
*
GPU_CC_FEATURE_PARAMS
=
"featureParams"
;
const
char
*
GPU_CC_STAGES
=
"stages"
;
const
char
*
GPU_CC_STAGE_THRESHOLD
=
"stageThreshold"
;
const
float
GPU_THRESHOLD_EPS
=
1e-5
f
;
const
char
*
GPU_CC_WEAK_CLASSIFIERS
=
"weakClassifiers"
;
const
char
*
GPU_CC_INTERNAL_NODES
=
"internalNodes"
;
const
char
*
GPU_CC_LEAF_VALUES
=
"leafValues"
;
const
char
*
GPU_CC_FEATURES
=
"features"
;
const
char
*
GPU_CC_RECT
=
"rect"
;
std
::
string
stageTypeStr
=
(
string
)
root
[
GPU_CC_STAGE_TYPE
];
CV_Assert
(
stageTypeStr
==
GPU_CC_BOOST
);
string
featureTypeStr
=
(
string
)
root
[
GPU_CC_FEATURE_TYPE
];
CV_Assert
(
featureTypeStr
==
GPU_CC_LBP
);
NxM
.
width
=
(
int
)
root
[
GPU_CC_WIDTH
];
NxM
.
height
=
(
int
)
root
[
GPU_CC_HEIGHT
];
CV_Assert
(
NxM
.
height
>
0
&&
NxM
.
width
>
0
);
isStumps
=
((
int
)(
root
[
GPU_CC_STAGE_PARAMS
][
GPU_CC_MAX_DEPTH
])
==
1
)
?
true
:
false
;
CV_Assert
(
isStumps
);
FileNode
fn
=
root
[
GPU_CC_FEATURE_PARAMS
];
if
(
fn
.
empty
())
return
false
;
ncategories
=
fn
[
GPU_CC_MAX_CAT_COUNT
];
subsetSize
=
(
ncategories
+
31
)
/
32
;
nodeStep
=
3
+
(
ncategories
>
0
?
subsetSize
:
1
);
fn
=
root
[
GPU_CC_STAGES
];
if
(
fn
.
empty
())
return
false
;
std
::
vector
<
Stage
>
stages
;
stages
.
reserve
(
fn
.
size
());
std
::
vector
<
int
>
cl_trees
;
std
::
vector
<
int
>
cl_nodes
;
std
::
vector
<
float
>
cl_leaves
;
std
::
vector
<
int
>
subsets
;
FileNodeIterator
it
=
fn
.
begin
(),
it_end
=
fn
.
end
();
for
(
size_t
si
=
0
;
it
!=
it_end
;
si
++
,
++
it
)
{
FileNode
fns
=
*
it
;
Stage
st
;
st
.
threshold
=
(
float
)
fns
[
GPU_CC_STAGE_THRESHOLD
]
-
GPU_THRESHOLD_EPS
;
fns
=
fns
[
GPU_CC_WEAK_CLASSIFIERS
];
if
(
fns
.
empty
())
return
false
;
st
.
ntrees
=
(
int
)
fns
.
size
();
st
.
first
=
(
int
)
cl_trees
.
size
();
stages
.
push_back
(
st
);
// (int, int, float)
cl_trees
.
reserve
(
stages
[
si
].
first
+
stages
[
si
].
ntrees
);
// weak trees
FileNodeIterator
it1
=
fns
.
begin
(),
it1_end
=
fns
.
end
();
for
(
;
it1
!=
it1_end
;
++
it1
)
{
FileNode
fnw
=
*
it1
;
FileNode
internalNodes
=
fnw
[
GPU_CC_INTERNAL_NODES
];
FileNode
leafValues
=
fnw
[
GPU_CC_LEAF_VALUES
];
if
(
internalNodes
.
empty
()
||
leafValues
.
empty
()
)
return
false
;
int
nodeCount
=
(
int
)
internalNodes
.
size
()
/
nodeStep
;
cl_trees
.
push_back
(
nodeCount
);
cl_nodes
.
reserve
((
cl_nodes
.
size
()
+
nodeCount
)
*
3
);
cl_leaves
.
reserve
(
cl_leaves
.
size
()
+
leafValues
.
size
());
if
(
subsetSize
>
0
)
subsets
.
reserve
(
subsets
.
size
()
+
nodeCount
*
subsetSize
);
// nodes
FileNodeIterator
iIt
=
internalNodes
.
begin
(),
iEnd
=
internalNodes
.
end
();
for
(
;
iIt
!=
iEnd
;
)
{
cl_nodes
.
push_back
((
int
)
*
(
iIt
++
));
cl_nodes
.
push_back
((
int
)
*
(
iIt
++
));
cl_nodes
.
push_back
((
int
)
*
(
iIt
++
));
if
(
subsetSize
>
0
)
for
(
int
j
=
0
;
j
<
subsetSize
;
j
++
,
++
iIt
)
subsets
.
push_back
((
int
)
*
iIt
);
}
// leaves
iIt
=
leafValues
.
begin
(),
iEnd
=
leafValues
.
end
();
for
(
;
iIt
!=
iEnd
;
++
iIt
)
cl_leaves
.
push_back
((
float
)
*
iIt
);
}
}
fn
=
root
[
GPU_CC_FEATURES
];
if
(
fn
.
empty
()
)
return
false
;
std
::
vector
<
uchar
>
features
;
features
.
reserve
(
fn
.
size
()
*
4
);
FileNodeIterator
f_it
=
fn
.
begin
(),
f_end
=
fn
.
end
();
for
(;
f_it
!=
f_end
;
++
f_it
)
{
FileNode
rect
=
(
*
f_it
)[
GPU_CC_RECT
];
FileNodeIterator
r_it
=
rect
.
begin
();
features
.
push_back
(
saturate_cast
<
uchar
>
((
int
)
*
(
r_it
++
)));
features
.
push_back
(
saturate_cast
<
uchar
>
((
int
)
*
(
r_it
++
)));
features
.
push_back
(
saturate_cast
<
uchar
>
((
int
)
*
(
r_it
++
)));
features
.
push_back
(
saturate_cast
<
uchar
>
((
int
)
*
(
r_it
++
)));
}
// copy data structures on gpu
stage_mat
.
upload
(
cv
::
Mat
(
1
,
stages
.
size
()
*
sizeof
(
Stage
),
CV_8UC1
,
(
uchar
*
)
&
(
stages
[
0
])
));
trees_mat
.
upload
(
cv
::
Mat
(
cl_trees
).
reshape
(
1
,
1
));
nodes_mat
.
upload
(
cv
::
Mat
(
cl_nodes
).
reshape
(
1
,
1
));
leaves_mat
.
upload
(
cv
::
Mat
(
cl_leaves
).
reshape
(
1
,
1
));
subsets_mat
.
upload
(
cv
::
Mat
(
subsets
).
reshape
(
1
,
1
));
features_mat
.
upload
(
cv
::
Mat
(
features
).
reshape
(
4
,
1
));
return
true
;
}
int
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
CascadeClassifierImpl
::
process
(
const
GpuMat
&
image
,
GpuMat
&
objects
,
double
scaleFactor
,
int
groupThreshold
,
cv
::
Size
maxObjectSize
)
{
CV_Assert
(
!
empty
()
&&
scaleFactor
>
1
&&
image
.
depth
()
==
CV_8U
);
const
int
defaultObjSearchNum
=
100
;
const
float
grouping_eps
=
0.2
f
;
if
(
!
objects
.
empty
()
&&
objects
.
depth
()
==
CV_32S
)
objects
.
reshape
(
4
,
1
);
else
objects
.
create
(
1
,
image
.
cols
>>
4
,
CV_32SC4
);
// used for debug
// candidates.setTo(cv::Scalar::all(0));
// objects.setTo(cv::Scalar::all(0));
if
(
maxObjectSize
==
cv
::
Size
())
maxObjectSize
=
image
.
size
();
allocateBuffers
(
image
.
size
());
unsigned
int
classified
=
0
;
GpuMat
dclassified
(
1
,
1
,
CV_32S
);
cudaSafeCall
(
cudaMemcpy
(
dclassified
.
ptr
(),
&
classified
,
sizeof
(
int
),
cudaMemcpyHostToDevice
)
);
PyrLavel
level
(
0
,
1.0
f
,
image
.
size
(),
NxM
);
while
(
level
.
isFeasible
(
maxObjectSize
))
{
int
acc
=
level
.
sFrame
.
width
+
1
;
float
iniScale
=
level
.
scale
;
cv
::
Size
area
=
level
.
workArea
;
int
step
=
1
+
(
level
.
scale
<=
2.
f
);
int
total
=
0
,
prev
=
0
;
while
(
acc
<=
integralFactor
*
(
image
.
cols
+
1
)
&&
level
.
isFeasible
(
maxObjectSize
))
{
// create sutable matrix headers
GpuMat
src
=
resuzeBuffer
(
cv
::
Rect
(
0
,
0
,
level
.
sFrame
.
width
,
level
.
sFrame
.
height
));
GpuMat
sint
=
integral
(
cv
::
Rect
(
prev
,
0
,
level
.
sFrame
.
width
+
1
,
level
.
sFrame
.
height
+
1
));
GpuMat
buff
=
integralBuffer
;
// generate integral for scale
gpu
::
resize
(
image
,
src
,
level
.
sFrame
,
0
,
0
,
CV_INTER_LINEAR
);
gpu
::
integralBuffered
(
src
,
sint
,
buff
);
// calculate job
int
totalWidth
=
level
.
workArea
.
width
/
step
;
// totalWidth = ((totalWidth + WARP_MASK) / WARP_SIZE) << WARP_LOG;
total
+=
totalWidth
*
(
level
.
workArea
.
height
/
step
);
// go to next pyramide level
level
=
level
.
next
(
scaleFactor
,
image
.
size
(),
NxM
);
area
=
level
.
workArea
;
step
=
(
1
+
(
level
.
scale
<=
2.
f
));
prev
=
acc
;
acc
+=
level
.
sFrame
.
width
+
1
;
}
device
::
lbp
::
classifyPyramid
(
image
.
cols
,
image
.
rows
,
NxM
.
width
-
1
,
NxM
.
height
-
1
,
iniScale
,
scaleFactor
,
total
,
stage_mat
,
stage_mat
.
cols
/
sizeof
(
Stage
),
nodes_mat
,
leaves_mat
,
subsets_mat
,
features_mat
,
subsetSize
,
candidates
,
dclassified
.
ptr
<
unsigned
int
>
(),
integral
);
}
if
(
groupThreshold
<=
0
||
objects
.
empty
())
return
0
;
cudaSafeCall
(
cudaMemcpy
(
&
classified
,
dclassified
.
ptr
(),
sizeof
(
int
),
cudaMemcpyDeviceToHost
)
);
device
::
lbp
::
connectedConmonents
(
candidates
,
classified
,
objects
,
groupThreshold
,
grouping_eps
,
dclassified
.
ptr
<
unsigned
int
>
());
// candidates.copyTo(objects);
cudaSafeCall
(
cudaMemcpy
(
&
classified
,
dclassified
.
ptr
(),
sizeof
(
int
),
cudaMemcpyDeviceToHost
)
);
cudaSafeCall
(
cudaDeviceSynchronize
()
);
return
classified
;
}
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
CascadeClassifier_GPU_LBP
(
cv
::
Size
detectionFrameSize
)
:
impl
(
new
CascadeClassifierImpl
())
{
(
*
impl
).
allocateBuffers
(
detectionFrameSize
);
}
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::~
CascadeClassifier_GPU_LBP
(){
delete
impl
;
}
bool
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
empty
()
const
{
return
(
*
impl
).
empty
();
}
bool
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
load
(
const
string
&
classifierAsXml
)
{
FileStorage
fs
(
classifierAsXml
,
FileStorage
::
READ
);
return
fs
.
isOpened
()
?
(
*
impl
).
read
(
fs
.
getFirstTopLevelNode
())
:
false
;
}
int
cv
::
gpu
::
CascadeClassifier_GPU_LBP
::
detectMultiScale
(
const
GpuMat
&
image
,
GpuMat
&
objects
,
double
scaleFactor
,
int
groupThreshold
,
cv
::
Size
maxObjectSize
)
{
return
(
*
impl
).
process
(
image
,
objects
,
scaleFactor
,
groupThreshold
,
maxObjectSize
);
}
// ============ old fashioned haar cascade ==============================================//
NCVStatus
process
(
const
GpuMat
&
src
,
GpuMat
&
objects
,
float
scaleStep
,
int
minNeighbors
,
struct
cv
::
gpu
::
CascadeClassifier_GPU
::
CascadeClassifierImpl
bool
findLargestObject
,
bool
visualizeInPlace
,
cv
::
Size
ncvMinSize
,
{
/*out*/
unsigned
int
&
numDetections
)
CascadeClassifierImpl
(
const
string
&
filename
)
:
lastAllocatedFrameSize
(
-
1
,
-
1
)
{
{
calculateMemReqsAndAllocate
(
src
.
size
());
ncvSetDebugOutputHandler
(
NCVDebugOutputHandler
);
ncvSafeCall
(
load
(
filename
)
);
}
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
>
();
...
@@ -507,6 +122,8 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
...
@@ -507,6 +122,8 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
roi
.
width
=
d_src
.
width
();
roi
.
width
=
d_src
.
width
();
roi
.
height
=
d_src
.
height
();
roi
.
height
=
d_src
.
height
();
NcvSize32u
winMinSize
(
ncvMinSize
.
width
,
ncvMinSize
.
height
);
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
;
...
@@ -514,7 +131,7 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
...
@@ -514,7 +131,7 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
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
,
ncvMinSize
,
winMinSize
,
minNeighbors
,
minNeighbors
,
scaleStep
,
1
,
scaleStep
,
1
,
flags
,
flags
,
...
@@ -525,16 +142,35 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
...
@@ -525,16 +142,35 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
return
NCV_SUCCESS
;
return
NCV_SUCCESS
;
}
}
unsigned
int
process
(
const
GpuMat
&
image
,
GpuMat
&
objectsBuf
,
float
scaleFactor
,
int
minNeighbors
,
bool
findLargestObject
,
bool
visualizeInPlace
,
cv
::
Size
minSize
,
cv
::
Size
maxObjectSize
)
{
CV_Assert
(
scaleFactor
>
1
&&
image
.
depth
()
==
CV_8U
);
NcvSize32u
getClassifierSize
()
const
{
return
haar
.
ClassifierSize
;
}
const
int
defaultObjSearchNum
=
100
;
cv
::
Size
getClassifierCvSize
()
const
{
return
cv
::
Size
(
haar
.
ClassifierSize
.
width
,
haar
.
ClassifierSize
.
height
);
}
if
(
objectsBuf
.
empty
())
{
objectsBuf
.
create
(
1
,
defaultObjSearchNum
,
DataType
<
Rect
>::
type
);
}
cv
::
Size
ncvMinSize
=
this
->
getClassifierCvSize
();
private
:
if
(
ncvMinSize
.
width
<
(
unsigned
)
minSize
.
width
&&
ncvMinSize
.
height
<
(
unsigned
)
minSize
.
height
)
{
ncvMinSize
.
width
=
minSize
.
width
;
ncvMinSize
.
height
=
minSize
.
height
;
}
unsigned
int
numDetections
;
ncvSafeCall
(
this
->
process
(
image
,
objectsBuf
,
(
float
)
scaleFactor
,
minNeighbors
,
findLargestObject
,
visualizeInPlace
,
ncvMinSize
,
numDetections
));
static
void
NCVDebugOutputHandler
(
const
std
::
string
&
msg
)
{
CV_Error
(
CV_GpuApiCallError
,
msg
.
c_str
());
}
return
numDetections
;
}
cv
::
Size
getClassifierCvSize
()
const
{
return
cv
::
Size
(
haar
.
ClassifierSize
.
width
,
haar
.
ClassifierSize
.
height
);
}
private
:
static
void
NCVDebugOutputHandler
(
const
std
::
string
&
msg
)
{
CV_Error
(
CV_GpuApiCallError
,
msg
.
c_str
());
}
NCVStatus
load
(
const
string
&
classifierFile
)
NCVStatus
load
(
const
string
&
classifierFile
)
{
{
...
@@ -581,7 +217,6 @@ private:
...
@@ -581,7 +217,6 @@ private:
return
NCV_SUCCESS
;
return
NCV_SUCCESS
;
}
}
NCVStatus
calculateMemReqsAndAllocate
(
const
Size
&
frameSize
)
NCVStatus
calculateMemReqsAndAllocate
(
const
Size
&
frameSize
)
{
{
if
(
lastAllocatedFrameSize
==
frameSize
)
if
(
lastAllocatedFrameSize
==
frameSize
)
...
@@ -623,7 +258,6 @@ private:
...
@@ -623,7 +258,6 @@ private:
return
NCV_SUCCESS
;
return
NCV_SUCCESS
;
}
}
cudaDeviceProp
devProp
;
cudaDeviceProp
devProp
;
NCVStatus
ncvStat
;
NCVStatus
ncvStat
;
...
@@ -644,55 +278,448 @@ private:
...
@@ -644,55 +278,448 @@ private:
Ptr
<
NCVMemStackAllocator
>
gpuAllocator
;
Ptr
<
NCVMemStackAllocator
>
gpuAllocator
;
Ptr
<
NCVMemStackAllocator
>
cpuAllocator
;
Ptr
<
NCVMemStackAllocator
>
cpuAllocator
;
virtual
~
HaarCascade
(){}
};
};
cv
::
Size
operator
-
(
const
cv
::
Size
&
a
,
const
cv
::
Size
&
b
)
{
return
cv
::
Size
(
a
.
width
-
b
.
width
,
a
.
height
-
b
.
height
);
}
cv
::
gpu
::
CascadeClassifier_GPU
::
CascadeClassifier_GPU
()
:
findLargestObject
(
false
),
visualizeInPlace
(
false
),
impl
(
0
)
{}
cv
::
Size
operator
+
(
const
cv
::
Size
&
a
,
const
int
&
i
)
cv
::
gpu
::
CascadeClassifier_GPU
::
CascadeClassifier_GPU
(
const
string
&
filename
)
:
findLargestObject
(
false
),
visualizeInPlace
(
false
),
impl
(
0
)
{
load
(
filename
);
}
{
cv
::
gpu
::
CascadeClassifier_GPU
::~
CascadeClassifier_GPU
()
{
release
();
}
return
cv
::
Size
(
a
.
width
+
i
,
a
.
height
+
i
);
bool
cv
::
gpu
::
CascadeClassifier_GPU
::
empty
()
const
{
return
impl
==
0
;
}
}
void
cv
::
gpu
::
CascadeClassifier_GPU
::
release
()
{
if
(
impl
)
{
delete
impl
;
impl
=
0
;
}
}
cv
::
Size
operator
*
(
const
cv
::
Size
&
a
,
const
float
&
f
)
{
return
cv
::
Size
(
cvRound
(
a
.
width
*
f
),
cvRound
(
a
.
height
*
f
));
}
bool
cv
::
gpu
::
CascadeClassifier_GPU
::
load
(
const
string
&
filename
)
cv
::
Size
operator
/
(
const
cv
::
Size
&
a
,
const
float
&
f
)
{
{
release
();
return
cv
::
Size
(
cvRound
(
a
.
width
/
f
),
cvRound
(
a
.
height
/
f
));
impl
=
new
CascadeClassifierImpl
(
filename
);
}
return
!
this
->
empty
();
bool
operator
<=
(
const
cv
::
Size
&
a
,
const
cv
::
Size
&
b
)
{
return
a
.
width
<=
b
.
width
&&
a
.
height
<=
b
.
width
;
}
}
struct
PyrLavel
{
PyrLavel
(
int
_order
,
float
_scale
,
cv
::
Size
frame
,
cv
::
Size
window
,
cv
::
Size
minObjectSize
)
{
do
{
order
=
_order
;
scale
=
pow
(
_scale
,
order
);
sFrame
=
frame
/
scale
;
workArea
=
sFrame
-
window
+
1
;
sWindow
=
window
*
scale
;
_order
++
;
}
while
(
sWindow
<=
minObjectSize
);
}
bool
isFeasible
(
cv
::
Size
maxObj
)
{
return
workArea
.
width
>
0
&&
workArea
.
height
>
0
&&
sWindow
<=
maxObj
;
}
PyrLavel
next
(
float
factor
,
cv
::
Size
frame
,
cv
::
Size
window
,
cv
::
Size
minObjectSize
)
{
return
PyrLavel
(
order
+
1
,
factor
,
frame
,
window
,
minObjectSize
);
}
int
order
;
float
scale
;
cv
::
Size
sFrame
;
cv
::
Size
workArea
;
cv
::
Size
sWindow
;
};
namespace
cv
{
namespace
gpu
{
namespace
device
{
namespace
lbp
{
void
classifyPyramid
(
int
frameW
,
int
frameH
,
int
windowW
,
int
windowH
,
float
initalScale
,
float
factor
,
int
total
,
const
DevMem2Db
&
mstages
,
const
int
nstages
,
const
DevMem2Di
&
mnodes
,
const
DevMem2Df
&
mleaves
,
const
DevMem2Di
&
msubsets
,
const
DevMem2Db
&
mfeatures
,
const
int
subsetSize
,
DevMem2D_
<
int4
>
objects
,
unsigned
int
*
classified
,
DevMem2Di
integral
);
void
connectedConmonents
(
DevMem2D_
<
int4
>
candidates
,
int
ncandidates
,
DevMem2D_
<
int4
>
objects
,
int
groupThreshold
,
float
grouping_eps
,
unsigned
int
*
nclasses
);
}
}}}
struct
cv
::
gpu
::
CascadeClassifier_GPU
::
LbpCascade
:
cv
::
gpu
::
CascadeClassifier_GPU
::
CascadeClassifierImpl
{
public
:
struct
Stage
{
int
first
;
int
ntrees
;
float
threshold
;
};
LbpCascade
(){}
virtual
~
LbpCascade
(){}
virtual
unsigned
int
process
(
const
GpuMat
&
image
,
GpuMat
&
objects
,
float
scaleFactor
,
int
groupThreshold
,
bool
findLargestObject
,
bool
visualizeInPlace
,
cv
::
Size
minObjectSize
,
cv
::
Size
maxObjectSize
)
{
CV_Assert
(
scaleFactor
>
1
&&
image
.
depth
()
==
CV_8U
);
const
int
defaultObjSearchNum
=
100
;
const
float
grouping_eps
=
0.2
f
;
if
(
!
objects
.
empty
()
&&
objects
.
depth
()
==
CV_32S
)
objects
.
reshape
(
4
,
1
);
else
objects
.
create
(
1
,
image
.
cols
>>
4
,
CV_32SC4
);
// used for debug
// candidates.setTo(cv::Scalar::all(0));
// objects.setTo(cv::Scalar::all(0));
if
(
maxObjectSize
==
cv
::
Size
())
maxObjectSize
=
image
.
size
();
allocateBuffers
(
image
.
size
());
unsigned
int
classified
=
0
;
GpuMat
dclassified
(
1
,
1
,
CV_32S
);
cudaSafeCall
(
cudaMemcpy
(
dclassified
.
ptr
(),
&
classified
,
sizeof
(
int
),
cudaMemcpyHostToDevice
)
);
PyrLavel
level
(
0
,
1.0
f
,
image
.
size
(),
NxM
,
minObjectSize
);
while
(
level
.
isFeasible
(
maxObjectSize
))
{
int
acc
=
level
.
sFrame
.
width
+
1
;
float
iniScale
=
level
.
scale
;
cv
::
Size
area
=
level
.
workArea
;
int
step
=
1
+
(
level
.
scale
<=
2.
f
);
int
total
=
0
,
prev
=
0
;
while
(
acc
<=
integralFactor
*
(
image
.
cols
+
1
)
&&
level
.
isFeasible
(
maxObjectSize
))
{
// create sutable matrix headers
GpuMat
src
=
resuzeBuffer
(
cv
::
Rect
(
0
,
0
,
level
.
sFrame
.
width
,
level
.
sFrame
.
height
));
GpuMat
sint
=
integral
(
cv
::
Rect
(
prev
,
0
,
level
.
sFrame
.
width
+
1
,
level
.
sFrame
.
height
+
1
));
GpuMat
buff
=
integralBuffer
;
// generate integral for scale
gpu
::
resize
(
image
,
src
,
level
.
sFrame
,
0
,
0
,
CV_INTER_LINEAR
);
gpu
::
integralBuffered
(
src
,
sint
,
buff
);
// calculate job
int
totalWidth
=
level
.
workArea
.
width
/
step
;
total
+=
totalWidth
*
(
level
.
workArea
.
height
/
step
);
// go to next pyramide level
level
=
level
.
next
(
scaleFactor
,
image
.
size
(),
NxM
,
minObjectSize
);
area
=
level
.
workArea
;
step
=
(
1
+
(
level
.
scale
<=
2.
f
));
prev
=
acc
;
acc
+=
level
.
sFrame
.
width
+
1
;
}
device
::
lbp
::
classifyPyramid
(
image
.
cols
,
image
.
rows
,
NxM
.
width
-
1
,
NxM
.
height
-
1
,
iniScale
,
scaleFactor
,
total
,
stage_mat
,
stage_mat
.
cols
/
sizeof
(
Stage
),
nodes_mat
,
leaves_mat
,
subsets_mat
,
features_mat
,
subsetSize
,
candidates
,
dclassified
.
ptr
<
unsigned
int
>
(),
integral
);
}
if
(
groupThreshold
<=
0
||
objects
.
empty
())
return
0
;
cudaSafeCall
(
cudaMemcpy
(
&
classified
,
dclassified
.
ptr
(),
sizeof
(
int
),
cudaMemcpyDeviceToHost
)
);
device
::
lbp
::
connectedConmonents
(
candidates
,
classified
,
objects
,
groupThreshold
,
grouping_eps
,
dclassified
.
ptr
<
unsigned
int
>
());
cudaSafeCall
(
cudaMemcpy
(
&
classified
,
dclassified
.
ptr
(),
sizeof
(
int
),
cudaMemcpyDeviceToHost
)
);
cudaSafeCall
(
cudaDeviceSynchronize
()
);
return
classified
;
}
virtual
cv
::
Size
getClassifierCvSize
()
const
{
return
NxM
;
}
bool
read
(
const
string
&
classifierAsXml
)
{
FileStorage
fs
(
classifierAsXml
,
FileStorage
::
READ
);
return
fs
.
isOpened
()
?
read
(
fs
.
getFirstTopLevelNode
())
:
false
;
}
private
:
void
allocateBuffers
(
cv
::
Size
frame
)
{
if
(
frame
==
cv
::
Size
())
return
;
if
(
resuzeBuffer
.
empty
()
||
frame
.
width
>
resuzeBuffer
.
cols
||
frame
.
height
>
resuzeBuffer
.
rows
)
{
resuzeBuffer
.
create
(
frame
,
CV_8UC1
);
integral
.
create
(
frame
.
height
+
1
,
integralFactor
*
(
frame
.
width
+
1
),
CV_32SC1
);
NcvSize32u
roiSize
;
roiSize
.
width
=
frame
.
width
;
roiSize
.
height
=
frame
.
height
;
cudaDeviceProp
prop
;
cudaSafeCall
(
cudaGetDeviceProperties
(
&
prop
,
cv
::
gpu
::
getDevice
())
);
Ncv32u
bufSize
;
ncvSafeCall
(
nppiStIntegralGetSize_8u32u
(
roiSize
,
&
bufSize
,
prop
)
);
integralBuffer
.
create
(
1
,
bufSize
,
CV_8UC1
);
candidates
.
create
(
1
,
frame
.
width
>>
1
,
CV_32SC4
);
}
}
bool
read
(
const
FileNode
&
root
)
{
const
char
*
GPU_CC_STAGE_TYPE
=
"stageType"
;
const
char
*
GPU_CC_FEATURE_TYPE
=
"featureType"
;
const
char
*
GPU_CC_BOOST
=
"BOOST"
;
const
char
*
GPU_CC_LBP
=
"LBP"
;
const
char
*
GPU_CC_MAX_CAT_COUNT
=
"maxCatCount"
;
const
char
*
GPU_CC_HEIGHT
=
"height"
;
const
char
*
GPU_CC_WIDTH
=
"width"
;
const
char
*
GPU_CC_STAGE_PARAMS
=
"stageParams"
;
const
char
*
GPU_CC_MAX_DEPTH
=
"maxDepth"
;
const
char
*
GPU_CC_FEATURE_PARAMS
=
"featureParams"
;
const
char
*
GPU_CC_STAGES
=
"stages"
;
const
char
*
GPU_CC_STAGE_THRESHOLD
=
"stageThreshold"
;
const
float
GPU_THRESHOLD_EPS
=
1e-5
f
;
const
char
*
GPU_CC_WEAK_CLASSIFIERS
=
"weakClassifiers"
;
const
char
*
GPU_CC_INTERNAL_NODES
=
"internalNodes"
;
const
char
*
GPU_CC_LEAF_VALUES
=
"leafValues"
;
const
char
*
GPU_CC_FEATURES
=
"features"
;
const
char
*
GPU_CC_RECT
=
"rect"
;
std
::
string
stageTypeStr
=
(
string
)
root
[
GPU_CC_STAGE_TYPE
];
CV_Assert
(
stageTypeStr
==
GPU_CC_BOOST
);
string
featureTypeStr
=
(
string
)
root
[
GPU_CC_FEATURE_TYPE
];
CV_Assert
(
featureTypeStr
==
GPU_CC_LBP
);
NxM
.
width
=
(
int
)
root
[
GPU_CC_WIDTH
];
NxM
.
height
=
(
int
)
root
[
GPU_CC_HEIGHT
];
CV_Assert
(
NxM
.
height
>
0
&&
NxM
.
width
>
0
);
isStumps
=
((
int
)(
root
[
GPU_CC_STAGE_PARAMS
][
GPU_CC_MAX_DEPTH
])
==
1
)
?
true
:
false
;
CV_Assert
(
isStumps
);
FileNode
fn
=
root
[
GPU_CC_FEATURE_PARAMS
];
if
(
fn
.
empty
())
return
false
;
ncategories
=
fn
[
GPU_CC_MAX_CAT_COUNT
];
subsetSize
=
(
ncategories
+
31
)
/
32
;
nodeStep
=
3
+
(
ncategories
>
0
?
subsetSize
:
1
);
fn
=
root
[
GPU_CC_STAGES
];
if
(
fn
.
empty
())
return
false
;
std
::
vector
<
Stage
>
stages
;
stages
.
reserve
(
fn
.
size
());
std
::
vector
<
int
>
cl_trees
;
std
::
vector
<
int
>
cl_nodes
;
std
::
vector
<
float
>
cl_leaves
;
std
::
vector
<
int
>
subsets
;
FileNodeIterator
it
=
fn
.
begin
(),
it_end
=
fn
.
end
();
for
(
size_t
si
=
0
;
it
!=
it_end
;
si
++
,
++
it
)
{
FileNode
fns
=
*
it
;
Stage
st
;
st
.
threshold
=
(
float
)
fns
[
GPU_CC_STAGE_THRESHOLD
]
-
GPU_THRESHOLD_EPS
;
fns
=
fns
[
GPU_CC_WEAK_CLASSIFIERS
];
if
(
fns
.
empty
())
return
false
;
st
.
ntrees
=
(
int
)
fns
.
size
();
st
.
first
=
(
int
)
cl_trees
.
size
();
stages
.
push_back
(
st
);
// (int, int, float)
cl_trees
.
reserve
(
stages
[
si
].
first
+
stages
[
si
].
ntrees
);
// weak trees
FileNodeIterator
it1
=
fns
.
begin
(),
it1_end
=
fns
.
end
();
for
(
;
it1
!=
it1_end
;
++
it1
)
{
FileNode
fnw
=
*
it1
;
FileNode
internalNodes
=
fnw
[
GPU_CC_INTERNAL_NODES
];
FileNode
leafValues
=
fnw
[
GPU_CC_LEAF_VALUES
];
if
(
internalNodes
.
empty
()
||
leafValues
.
empty
()
)
return
false
;
int
nodeCount
=
(
int
)
internalNodes
.
size
()
/
nodeStep
;
cl_trees
.
push_back
(
nodeCount
);
cl_nodes
.
reserve
((
cl_nodes
.
size
()
+
nodeCount
)
*
3
);
cl_leaves
.
reserve
(
cl_leaves
.
size
()
+
leafValues
.
size
());
if
(
subsetSize
>
0
)
subsets
.
reserve
(
subsets
.
size
()
+
nodeCount
*
subsetSize
);
// nodes
FileNodeIterator
iIt
=
internalNodes
.
begin
(),
iEnd
=
internalNodes
.
end
();
for
(
;
iIt
!=
iEnd
;
)
{
cl_nodes
.
push_back
((
int
)
*
(
iIt
++
));
cl_nodes
.
push_back
((
int
)
*
(
iIt
++
));
cl_nodes
.
push_back
((
int
)
*
(
iIt
++
));
if
(
subsetSize
>
0
)
for
(
int
j
=
0
;
j
<
subsetSize
;
j
++
,
++
iIt
)
subsets
.
push_back
((
int
)
*
iIt
);
}
// leaves
iIt
=
leafValues
.
begin
(),
iEnd
=
leafValues
.
end
();
for
(
;
iIt
!=
iEnd
;
++
iIt
)
cl_leaves
.
push_back
((
float
)
*
iIt
);
}
}
fn
=
root
[
GPU_CC_FEATURES
];
if
(
fn
.
empty
()
)
return
false
;
std
::
vector
<
uchar
>
features
;
features
.
reserve
(
fn
.
size
()
*
4
);
FileNodeIterator
f_it
=
fn
.
begin
(),
f_end
=
fn
.
end
();
for
(;
f_it
!=
f_end
;
++
f_it
)
{
FileNode
rect
=
(
*
f_it
)[
GPU_CC_RECT
];
FileNodeIterator
r_it
=
rect
.
begin
();
features
.
push_back
(
saturate_cast
<
uchar
>
((
int
)
*
(
r_it
++
)));
features
.
push_back
(
saturate_cast
<
uchar
>
((
int
)
*
(
r_it
++
)));
features
.
push_back
(
saturate_cast
<
uchar
>
((
int
)
*
(
r_it
++
)));
features
.
push_back
(
saturate_cast
<
uchar
>
((
int
)
*
(
r_it
++
)));
}
// copy data structures on gpu
stage_mat
.
upload
(
cv
::
Mat
(
1
,
stages
.
size
()
*
sizeof
(
Stage
),
CV_8UC1
,
(
uchar
*
)
&
(
stages
[
0
])
));
trees_mat
.
upload
(
cv
::
Mat
(
cl_trees
).
reshape
(
1
,
1
));
nodes_mat
.
upload
(
cv
::
Mat
(
cl_nodes
).
reshape
(
1
,
1
));
leaves_mat
.
upload
(
cv
::
Mat
(
cl_leaves
).
reshape
(
1
,
1
));
subsets_mat
.
upload
(
cv
::
Mat
(
subsets
).
reshape
(
1
,
1
));
features_mat
.
upload
(
cv
::
Mat
(
features
).
reshape
(
4
,
1
));
return
true
;
}
enum
stage
{
BOOST
=
0
};
enum
feature
{
LBP
=
1
,
HAAR
=
2
};
static
const
stage
stageType
=
BOOST
;
static
const
feature
featureType
=
LBP
;
cv
::
Size
NxM
;
bool
isStumps
;
int
ncategories
;
int
subsetSize
;
int
nodeStep
;
// gpu representation of classifier
GpuMat
stage_mat
;
GpuMat
trees_mat
;
GpuMat
nodes_mat
;
GpuMat
leaves_mat
;
GpuMat
subsets_mat
;
GpuMat
features_mat
;
GpuMat
integral
;
GpuMat
integralBuffer
;
GpuMat
resuzeBuffer
;
GpuMat
candidates
;
static
const
int
integralFactor
=
4
;
};
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
()
{
release
();
}
void
cv
::
gpu
::
CascadeClassifier_GPU
::
release
()
{
if
(
impl
)
{
delete
impl
;
impl
=
0
;
}
}
bool
cv
::
gpu
::
CascadeClassifier_GPU
::
empty
()
const
{
return
impl
==
0
;
}
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
(
!
this
->
empty
());
CV_Assert
(
!
this
->
empty
());
return
impl
->
process
(
image
,
objectsBuf
,
(
float
)
scaleFactor
,
minNeighbors
,
findLargestObject
,
visualizeInPlace
,
minSize
,
cv
::
Size
());
}
const
int
defaultObjSearchNum
=
100
;
int
cv
::
gpu
::
CascadeClassifier_GPU
::
detectMultiScale
(
const
GpuMat
&
image
,
GpuMat
&
objectsBuf
,
Size
maxObjectSize
,
Size
minSize
,
double
scaleFactor
,
int
minNeighbors
)
if
(
objectsBuf
.
empty
())
{
CV_Assert
(
!
this
->
empty
());
return
impl
->
process
(
image
,
objectsBuf
,
(
float
)
scaleFactor
,
minNeighbors
,
findLargestObject
,
visualizeInPlace
,
minSize
,
maxObjectSize
);
}
bool
cv
::
gpu
::
CascadeClassifier_GPU
::
load
(
const
string
&
filename
)
{
release
();
std
::
string
fext
=
filename
.
substr
(
filename
.
find_last_of
(
"."
)
+
1
);
std
::
transform
(
fext
.
begin
(),
fext
.
end
(),
fext
.
begin
(),
::
tolower
);
if
(
fext
==
"nvbin"
)
{
{
objectsBuf
.
create
(
1
,
defaultObjSearchNum
,
DataType
<
Rect
>::
type
);
impl
=
new
HaarCascade
();
return
impl
->
read
(
filename
);
}
}
NcvSize32u
ncvMinSize
=
impl
->
getClassifierSize
();
FileStorage
fs
(
filename
,
FileStorage
::
READ
);
if
(
ncvMinSize
.
width
<
(
unsigned
)
minSize
.
width
&&
ncvMinSize
.
height
<
(
unsigned
)
minSize
.
height
)
if
(
!
fs
.
isOpened
())
{
{
ncvMinSize
.
width
=
minSize
.
width
;
impl
=
new
HaarCascade
();
ncvMinSize
.
height
=
minSize
.
height
;
return
impl
->
read
(
filename
);
}
}
unsigned
int
numDetections
;
const
char
*
GPU_CC_LBP
=
"LBP"
;
ncvSafeCall
(
impl
->
process
(
image
,
objectsBuf
,
(
float
)
scaleFactor
,
minNeighbors
,
findLargestObject
,
visualizeInPlace
,
ncvMinSize
,
numDetections
)
);
string
featureTypeStr
=
(
string
)
fs
.
getFirstTopLevelNode
()[
"featureType"
];
if
(
featureTypeStr
==
GPU_CC_LBP
)
impl
=
new
LbpCascade
();
else
impl
=
new
HaarCascade
();
return
numDetections
;
impl
->
read
(
filename
);
return
!
this
->
empty
();
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
struct
RectConvert
struct
RectConvert
{
{
...
@@ -708,7 +735,6 @@ struct RectConvert
...
@@ -708,7 +735,6 @@ struct RectConvert
}
}
};
};
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
());
...
...
modules/gpu/src/cuda/lbp.cu
View file @
1b7ad93d
...
@@ -290,6 +290,7 @@ namespace cv { namespace gpu { namespace device
...
@@ -290,6 +290,7 @@ namespace cv { namespace gpu { namespace device
{
{
const int block = 128;
const int block = 128;
int grid = divUp(workAmount, block);
int grid = divUp(workAmount, block);
cudaFuncSetCacheConfig(lbp_cascade, cudaFuncCachePreferL1);
Cascade cascade((Stage*)mstages.ptr(), nstages, (ClNode*)mnodes.ptr(), mleaves.ptr(), msubsets.ptr(), (uchar4*)mfeatures.ptr(), subsetSize);
Cascade cascade((Stage*)mstages.ptr(), nstages, (ClNode*)mnodes.ptr(), mleaves.ptr(), msubsets.ptr(), (uchar4*)mfeatures.ptr(), subsetSize);
lbp_cascade<<<grid, block>>>(cascade, frameW, frameH, windowW, windowH, initialScale, factor, workAmount, integral.ptr(), integral.step / sizeof(int), objects, classified);
lbp_cascade<<<grid, block>>>(cascade, frameW, frameH, windowW, windowH, initialScale, factor, workAmount, integral.ptr(), integral.step / sizeof(int), objects, classified);
}
}
...
...
modules/gpu/test/test_objdetect.cpp
View file @
1b7ad93d
...
@@ -302,13 +302,13 @@ PARAM_TEST_CASE(LBP_Read_classifier, cv::gpu::DeviceInfo, int)
...
@@ -302,13 +302,13 @@ PARAM_TEST_CASE(LBP_Read_classifier, cv::gpu::DeviceInfo, int)
TEST_P
(
LBP_Read_classifier
,
Accuracy
)
TEST_P
(
LBP_Read_classifier
,
Accuracy
)
{
{
cv
::
gpu
::
CascadeClassifier_GPU
_LBP
classifier
;
cv
::
gpu
::
CascadeClassifier_GPU
classifier
;
std
::
string
classifierXmlPath
=
std
::
string
(
cvtest
::
TS
::
ptr
()
->
get_data_path
())
+
"lbpcascade/lbpcascade_frontalface.xml"
;
std
::
string
classifierXmlPath
=
std
::
string
(
cvtest
::
TS
::
ptr
()
->
get_data_path
())
+
"lbpcascade/lbpcascade_frontalface.xml"
;
ASSERT_TRUE
(
classifier
.
load
(
classifierXmlPath
));
ASSERT_TRUE
(
classifier
.
load
(
classifierXmlPath
));
}
}
INSTANTIATE_TEST_CASE_P
(
GPU_ObjDetect
,
LBP_Read_classifier
,
INSTANTIATE_TEST_CASE_P
(
GPU_ObjDetect
,
LBP_Read_classifier
,
testing
::
Combine
(
ALL_DEVICES
,
testing
::
Values
<
int
>
(
0
)));
testing
::
Combine
(
ALL_DEVICES
,
testing
::
Values
<
int
>
(
0
)));
PARAM_TEST_CASE
(
LBP_classify
,
cv
::
gpu
::
DeviceInfo
,
int
)
PARAM_TEST_CASE
(
LBP_classify
,
cv
::
gpu
::
DeviceInfo
,
int
)
...
@@ -344,7 +344,7 @@ TEST_P(LBP_classify, Accuracy)
...
@@ -344,7 +344,7 @@ TEST_P(LBP_classify, Accuracy)
for
(;
it
!=
rects
.
end
();
++
it
)
for
(;
it
!=
rects
.
end
();
++
it
)
cv
::
rectangle
(
markedImage
,
*
it
,
CV_RGB
(
0
,
0
,
255
));
cv
::
rectangle
(
markedImage
,
*
it
,
CV_RGB
(
0
,
0
,
255
));
cv
::
gpu
::
CascadeClassifier_GPU
_LBP
gpuClassifier
;
cv
::
gpu
::
CascadeClassifier_GPU
gpuClassifier
;
ASSERT_TRUE
(
gpuClassifier
.
load
(
classifierXmlPath
));
ASSERT_TRUE
(
gpuClassifier
.
load
(
classifierXmlPath
));
cv
::
gpu
::
GpuMat
gpu_rects
;
cv
::
gpu
::
GpuMat
gpu_rects
;
...
@@ -352,23 +352,23 @@ TEST_P(LBP_classify, Accuracy)
...
@@ -352,23 +352,23 @@ TEST_P(LBP_classify, Accuracy)
int
count
=
gpuClassifier
.
detectMultiScale
(
tested
,
gpu_rects
);
int
count
=
gpuClassifier
.
detectMultiScale
(
tested
,
gpu_rects
);
cv
::
Mat
downloaded
(
gpu_rects
);
cv
::
Mat
downloaded
(
gpu_rects
);
const
cv
::
Rect
*
faces
=
downloaded
.
ptr
<
cv
::
Rect
>
();
const
cv
::
Rect
*
faces
=
downloaded
.
ptr
<
cv
::
Rect
>
();
for
(
int
i
=
0
;
i
<
count
;
i
++
)
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
{
cv
::
Rect
r
=
faces
[
i
];
cv
::
Rect
r
=
faces
[
i
];
#if defined (LOG_CASCADE_STATISTIC)
#if defined (LOG_CASCADE_STATISTIC)
std
::
cout
<<
r
.
x
<<
" "
<<
r
.
y
<<
" "
<<
r
.
width
<<
" "
<<
r
.
height
<<
std
::
endl
;
std
::
cout
<<
r
.
x
<<
" "
<<
r
.
y
<<
" "
<<
r
.
width
<<
" "
<<
r
.
height
<<
std
::
endl
;
#endif
cv
::
rectangle
(
markedImage
,
r
,
CV_RGB
(
255
,
0
,
0
));
cv
::
rectangle
(
markedImage
,
r
,
CV_RGB
(
255
,
0
,
0
));
#endif
}
}
#if defined (LOG_CASCADE_STATISTIC)
#if defined (LOG_CASCADE_STATISTIC)
cv
::
imshow
(
"Res"
,
markedImage
);
cv
::
waitKey
();
cv
::
imshow
(
"Res"
,
markedImage
);
cv
::
waitKey
();
#endif
#endif
}
}
INSTANTIATE_TEST_CASE_P
(
GPU_ObjDetect
,
LBP_classify
,
INSTANTIATE_TEST_CASE_P
(
GPU_ObjDetect
,
LBP_classify
,
testing
::
Combine
(
ALL_DEVICES
,
testing
::
Values
<
int
>
(
0
)));
testing
::
Combine
(
ALL_DEVICES
,
testing
::
Values
<
int
>
(
0
)));
}
// namespace
}
// namespace
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment