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
8b510ad8
Commit
8b510ad8
authored
Mar 11, 2013
by
Ilya Lavrenov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sse2 hog
parent
891d7da6
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
812 additions
and
0 deletions
+812
-0
hog.cpp
modules/objdetect/src/hog.cpp
+0
-0
test_cascadeandhog.cpp
modules/objdetect/test/test_cascadeandhog.cpp
+812
-0
No files found.
modules/objdetect/src/hog.cpp
View file @
8b510ad8
This source diff could not be displayed because it is too large. You can
view the blob
instead.
modules/objdetect/test/test_cascadeandhog.cpp
View file @
8b510ad8
...
...
@@ -543,3 +543,815 @@ TEST(Objdetect_HOGDetectorReadWrite, regression)
TEST
(
Objdetect_CascadeDetector
,
regression
)
{
CV_CascadeDetectorTest
test
;
test
.
safe_run
();
}
TEST
(
Objdetect_HOGDetector
,
regression
)
{
CV_HOGDetectorTest
test
;
test
.
safe_run
();
}
//----------------------------------------------- HOG SSE2 compatible test -----------------------------------
class
HOGDescriptorTester
:
public
cv
::
HOGDescriptor
{
HOGDescriptor
*
actual_hog
;
cvtest
::
TS
*
ts
;
mutable
bool
failed
;
public
:
HOGDescriptorTester
(
HOGDescriptor
&
instance
)
:
cv
::
HOGDescriptor
(
instance
),
actual_hog
(
&
instance
),
ts
(
cvtest
::
TS
::
ptr
()),
failed
(
false
)
{
}
virtual
void
computeGradient
(
const
Mat
&
img
,
Mat
&
grad
,
Mat
&
qangle
,
Size
paddingTL
,
Size
paddingBR
)
const
;
virtual
void
detect
(
const
Mat
&
img
,
vector
<
Point
>&
hits
,
vector
<
double
>&
weights
,
double
hitThreshold
=
0.0
,
Size
winStride
=
Size
(),
Size
padding
=
Size
(),
const
vector
<
Point
>&
locations
=
vector
<
Point
>
())
const
;
virtual
void
detect
(
const
Mat
&
img
,
vector
<
Point
>&
hits
,
double
hitThreshold
=
0.0
,
Size
winStride
=
Size
(),
Size
padding
=
Size
(),
const
vector
<
Point
>&
locations
=
vector
<
Point
>
())
const
;
virtual
void
compute
(
const
Mat
&
img
,
vector
<
float
>&
descriptors
,
Size
winStride
=
Size
(),
Size
padding
=
Size
(),
const
vector
<
Point
>&
locations
=
vector
<
Point
>
())
const
;
bool
is_failed
()
const
;
};
struct
HOGCacheTester
{
struct
BlockData
{
BlockData
()
:
histOfs
(
0
),
imgOffset
()
{}
int
histOfs
;
Point
imgOffset
;
};
struct
PixData
{
size_t
gradOfs
,
qangleOfs
;
int
histOfs
[
4
];
float
histWeights
[
4
];
float
gradWeight
;
};
HOGCacheTester
();
HOGCacheTester
(
const
HOGDescriptorTester
*
descriptor
,
const
Mat
&
img
,
Size
paddingTL
,
Size
paddingBR
,
bool
useCache
,
Size
cacheStride
);
virtual
~
HOGCacheTester
()
{
}
virtual
void
init
(
const
HOGDescriptorTester
*
descriptor
,
const
Mat
&
img
,
Size
paddingTL
,
Size
paddingBR
,
bool
useCache
,
Size
cacheStride
);
Size
windowsInImage
(
Size
imageSize
,
Size
winStride
)
const
;
Rect
getWindow
(
Size
imageSize
,
Size
winStride
,
int
idx
)
const
;
const
float
*
getBlock
(
Point
pt
,
float
*
buf
);
virtual
void
normalizeBlockHistogram
(
float
*
histogram
)
const
;
vector
<
PixData
>
pixData
;
vector
<
BlockData
>
blockData
;
bool
useCache
;
vector
<
int
>
ymaxCached
;
Size
winSize
,
cacheStride
;
Size
nblocks
,
ncells
;
int
blockHistogramSize
;
int
count1
,
count2
,
count4
;
Point
imgoffset
;
Mat_
<
float
>
blockCache
;
Mat_
<
uchar
>
blockCacheFlags
;
Mat
grad
,
qangle
;
const
HOGDescriptorTester
*
descriptor
;
};
HOGCacheTester
::
HOGCacheTester
()
{
useCache
=
false
;
blockHistogramSize
=
count1
=
count2
=
count4
=
0
;
descriptor
=
0
;
}
HOGCacheTester
::
HOGCacheTester
(
const
HOGDescriptorTester
*
_descriptor
,
const
Mat
&
_img
,
Size
_paddingTL
,
Size
_paddingBR
,
bool
_useCache
,
Size
_cacheStride
)
{
init
(
_descriptor
,
_img
,
_paddingTL
,
_paddingBR
,
_useCache
,
_cacheStride
);
}
void
HOGCacheTester
::
init
(
const
HOGDescriptorTester
*
_descriptor
,
const
Mat
&
_img
,
Size
_paddingTL
,
Size
_paddingBR
,
bool
_useCache
,
Size
_cacheStride
)
{
descriptor
=
_descriptor
;
cacheStride
=
_cacheStride
;
useCache
=
_useCache
;
descriptor
->
computeGradient
(
_img
,
grad
,
qangle
,
_paddingTL
,
_paddingBR
);
imgoffset
=
_paddingTL
;
winSize
=
descriptor
->
winSize
;
Size
blockSize
=
descriptor
->
blockSize
;
Size
blockStride
=
descriptor
->
blockStride
;
Size
cellSize
=
descriptor
->
cellSize
;
int
i
,
j
,
nbins
=
descriptor
->
nbins
;
int
rawBlockSize
=
blockSize
.
width
*
blockSize
.
height
;
nblocks
=
Size
((
winSize
.
width
-
blockSize
.
width
)
/
blockStride
.
width
+
1
,
(
winSize
.
height
-
blockSize
.
height
)
/
blockStride
.
height
+
1
);
ncells
=
Size
(
blockSize
.
width
/
cellSize
.
width
,
blockSize
.
height
/
cellSize
.
height
);
blockHistogramSize
=
ncells
.
width
*
ncells
.
height
*
nbins
;
if
(
useCache
)
{
Size
cacheSize
((
grad
.
cols
-
blockSize
.
width
)
/
cacheStride
.
width
+
1
,
(
winSize
.
height
/
cacheStride
.
height
)
+
1
);
blockCache
.
create
(
cacheSize
.
height
,
cacheSize
.
width
*
blockHistogramSize
);
blockCacheFlags
.
create
(
cacheSize
);
size_t
cacheRows
=
blockCache
.
rows
;
ymaxCached
.
resize
(
cacheRows
);
for
(
size_t
ii
=
0
;
ii
<
cacheRows
;
ii
++
)
ymaxCached
[
ii
]
=
-
1
;
}
Mat_
<
float
>
weights
(
blockSize
);
float
sigma
=
(
float
)
descriptor
->
getWinSigma
();
float
scale
=
1.
f
/
(
sigma
*
sigma
*
2
);
for
(
i
=
0
;
i
<
blockSize
.
height
;
i
++
)
for
(
j
=
0
;
j
<
blockSize
.
width
;
j
++
)
{
float
di
=
i
-
blockSize
.
height
*
0.5
f
;
float
dj
=
j
-
blockSize
.
width
*
0.5
f
;
weights
(
i
,
j
)
=
std
::
exp
(
-
(
di
*
di
+
dj
*
dj
)
*
scale
);
}
blockData
.
resize
(
nblocks
.
width
*
nblocks
.
height
);
pixData
.
resize
(
rawBlockSize
*
3
);
// Initialize 2 lookup tables, pixData & blockData.
// Here is why:
//
// The detection algorithm runs in 4 nested loops (at each pyramid layer):
// loop over the windows within the input image
// loop over the blocks within each window
// loop over the cells within each block
// loop over the pixels in each cell
//
// As each of the loops runs over a 2-dimensional array,
// we could get 8(!) nested loops in total, which is very-very slow.
//
// To speed the things up, we do the following:
// 1. loop over windows is unrolled in the HOGDescriptor::{compute|detect} methods;
// inside we compute the current search window using getWindow() method.
// Yes, it involves some overhead (function call + couple of divisions),
// but it's tiny in fact.
// 2. loop over the blocks is also unrolled. Inside we use pre-computed blockData[j]
// to set up gradient and histogram pointers.
// 3. loops over cells and pixels in each cell are merged
// (since there is no overlap between cells, each pixel in the block is processed once)
// and also unrolled. Inside we use PixData[k] to access the gradient values and
// update the histogram
//
count1
=
count2
=
count4
=
0
;
for
(
j
=
0
;
j
<
blockSize
.
width
;
j
++
)
for
(
i
=
0
;
i
<
blockSize
.
height
;
i
++
)
{
PixData
*
data
=
0
;
float
cellX
=
(
j
+
0.5
f
)
/
cellSize
.
width
-
0.5
f
;
float
cellY
=
(
i
+
0.5
f
)
/
cellSize
.
height
-
0.5
f
;
int
icellX0
=
cvFloor
(
cellX
);
int
icellY0
=
cvFloor
(
cellY
);
int
icellX1
=
icellX0
+
1
,
icellY1
=
icellY0
+
1
;
cellX
-=
icellX0
;
cellY
-=
icellY0
;
if
(
(
unsigned
)
icellX0
<
(
unsigned
)
ncells
.
width
&&
(
unsigned
)
icellX1
<
(
unsigned
)
ncells
.
width
)
{
if
(
(
unsigned
)
icellY0
<
(
unsigned
)
ncells
.
height
&&
(
unsigned
)
icellY1
<
(
unsigned
)
ncells
.
height
)
{
data
=
&
pixData
[
rawBlockSize
*
2
+
(
count4
++
)];
data
->
histOfs
[
0
]
=
(
icellX0
*
ncells
.
height
+
icellY0
)
*
nbins
;
data
->
histWeights
[
0
]
=
(
1.
f
-
cellX
)
*
(
1.
f
-
cellY
);
data
->
histOfs
[
1
]
=
(
icellX1
*
ncells
.
height
+
icellY0
)
*
nbins
;
data
->
histWeights
[
1
]
=
cellX
*
(
1.
f
-
cellY
);
data
->
histOfs
[
2
]
=
(
icellX0
*
ncells
.
height
+
icellY1
)
*
nbins
;
data
->
histWeights
[
2
]
=
(
1.
f
-
cellX
)
*
cellY
;
data
->
histOfs
[
3
]
=
(
icellX1
*
ncells
.
height
+
icellY1
)
*
nbins
;
data
->
histWeights
[
3
]
=
cellX
*
cellY
;
}
else
{
data
=
&
pixData
[
rawBlockSize
+
(
count2
++
)];
if
(
(
unsigned
)
icellY0
<
(
unsigned
)
ncells
.
height
)
{
icellY1
=
icellY0
;
cellY
=
1.
f
-
cellY
;
}
data
->
histOfs
[
0
]
=
(
icellX0
*
ncells
.
height
+
icellY1
)
*
nbins
;
data
->
histWeights
[
0
]
=
(
1.
f
-
cellX
)
*
cellY
;
data
->
histOfs
[
1
]
=
(
icellX1
*
ncells
.
height
+
icellY1
)
*
nbins
;
data
->
histWeights
[
1
]
=
cellX
*
cellY
;
data
->
histOfs
[
2
]
=
data
->
histOfs
[
3
]
=
0
;
data
->
histWeights
[
2
]
=
data
->
histWeights
[
3
]
=
0
;
}
}
else
{
if
(
(
unsigned
)
icellX0
<
(
unsigned
)
ncells
.
width
)
{
icellX1
=
icellX0
;
cellX
=
1.
f
-
cellX
;
}
if
(
(
unsigned
)
icellY0
<
(
unsigned
)
ncells
.
height
&&
(
unsigned
)
icellY1
<
(
unsigned
)
ncells
.
height
)
{
data
=
&
pixData
[
rawBlockSize
+
(
count2
++
)];
data
->
histOfs
[
0
]
=
(
icellX1
*
ncells
.
height
+
icellY0
)
*
nbins
;
data
->
histWeights
[
0
]
=
cellX
*
(
1.
f
-
cellY
);
data
->
histOfs
[
1
]
=
(
icellX1
*
ncells
.
height
+
icellY1
)
*
nbins
;
data
->
histWeights
[
1
]
=
cellX
*
cellY
;
data
->
histOfs
[
2
]
=
data
->
histOfs
[
3
]
=
0
;
data
->
histWeights
[
2
]
=
data
->
histWeights
[
3
]
=
0
;
}
else
{
data
=
&
pixData
[
count1
++
];
if
(
(
unsigned
)
icellY0
<
(
unsigned
)
ncells
.
height
)
{
icellY1
=
icellY0
;
cellY
=
1.
f
-
cellY
;
}
data
->
histOfs
[
0
]
=
(
icellX1
*
ncells
.
height
+
icellY1
)
*
nbins
;
data
->
histWeights
[
0
]
=
cellX
*
cellY
;
data
->
histOfs
[
1
]
=
data
->
histOfs
[
2
]
=
data
->
histOfs
[
3
]
=
0
;
data
->
histWeights
[
1
]
=
data
->
histWeights
[
2
]
=
data
->
histWeights
[
3
]
=
0
;
}
}
data
->
gradOfs
=
(
grad
.
cols
*
i
+
j
)
*
2
;
data
->
qangleOfs
=
(
qangle
.
cols
*
i
+
j
)
*
2
;
data
->
gradWeight
=
weights
(
i
,
j
);
}
assert
(
count1
+
count2
+
count4
==
rawBlockSize
);
// defragment pixData
for
(
j
=
0
;
j
<
count2
;
j
++
)
pixData
[
j
+
count1
]
=
pixData
[
j
+
rawBlockSize
];
for
(
j
=
0
;
j
<
count4
;
j
++
)
pixData
[
j
+
count1
+
count2
]
=
pixData
[
j
+
rawBlockSize
*
2
];
count2
+=
count1
;
count4
+=
count2
;
// initialize blockData
for
(
j
=
0
;
j
<
nblocks
.
width
;
j
++
)
for
(
i
=
0
;
i
<
nblocks
.
height
;
i
++
)
{
BlockData
&
data
=
blockData
[
j
*
nblocks
.
height
+
i
];
data
.
histOfs
=
(
j
*
nblocks
.
height
+
i
)
*
blockHistogramSize
;
data
.
imgOffset
=
Point
(
j
*
blockStride
.
width
,
i
*
blockStride
.
height
);
}
}
const
float
*
HOGCacheTester
::
getBlock
(
Point
pt
,
float
*
buf
)
{
float
*
blockHist
=
buf
;
assert
(
descriptor
!=
0
);
Size
blockSize
=
descriptor
->
blockSize
;
pt
+=
imgoffset
;
CV_Assert
(
(
unsigned
)
pt
.
x
<=
(
unsigned
)(
grad
.
cols
-
blockSize
.
width
)
&&
(
unsigned
)
pt
.
y
<=
(
unsigned
)(
grad
.
rows
-
blockSize
.
height
)
);
if
(
useCache
)
{
CV_Assert
(
pt
.
x
%
cacheStride
.
width
==
0
&&
pt
.
y
%
cacheStride
.
height
==
0
);
Point
cacheIdx
(
pt
.
x
/
cacheStride
.
width
,
(
pt
.
y
/
cacheStride
.
height
)
%
blockCache
.
rows
);
if
(
pt
.
y
!=
ymaxCached
[
cacheIdx
.
y
]
)
{
Mat_
<
uchar
>
cacheRow
=
blockCacheFlags
.
row
(
cacheIdx
.
y
);
cacheRow
=
(
uchar
)
0
;
ymaxCached
[
cacheIdx
.
y
]
=
pt
.
y
;
}
blockHist
=
&
blockCache
[
cacheIdx
.
y
][
cacheIdx
.
x
*
blockHistogramSize
];
uchar
&
computedFlag
=
blockCacheFlags
(
cacheIdx
.
y
,
cacheIdx
.
x
);
if
(
computedFlag
!=
0
)
return
blockHist
;
computedFlag
=
(
uchar
)
1
;
// set it at once, before actual computing
}
int
k
,
C1
=
count1
,
C2
=
count2
,
C4
=
count4
;
const
float
*
gradPtr
=
(
const
float
*
)(
grad
.
data
+
grad
.
step
*
pt
.
y
)
+
pt
.
x
*
2
;
const
uchar
*
qanglePtr
=
qangle
.
data
+
qangle
.
step
*
pt
.
y
+
pt
.
x
*
2
;
CV_Assert
(
blockHist
!=
0
);
for
(
k
=
0
;
k
<
blockHistogramSize
;
k
++
)
blockHist
[
k
]
=
0.
f
;
const
PixData
*
_pixData
=
&
pixData
[
0
];
for
(
k
=
0
;
k
<
C1
;
k
++
)
{
const
PixData
&
pk
=
_pixData
[
k
];
const
float
*
a
=
gradPtr
+
pk
.
gradOfs
;
float
w
=
pk
.
gradWeight
*
pk
.
histWeights
[
0
];
const
uchar
*
h
=
qanglePtr
+
pk
.
qangleOfs
;
int
h0
=
h
[
0
],
h1
=
h
[
1
];
float
*
hist
=
blockHist
+
pk
.
histOfs
[
0
];
float
t0
=
hist
[
h0
]
+
a
[
0
]
*
w
;
float
t1
=
hist
[
h1
]
+
a
[
1
]
*
w
;
hist
[
h0
]
=
t0
;
hist
[
h1
]
=
t1
;
}
for
(
;
k
<
C2
;
k
++
)
{
const
PixData
&
pk
=
_pixData
[
k
];
const
float
*
a
=
gradPtr
+
pk
.
gradOfs
;
float
w
,
t0
,
t1
,
a0
=
a
[
0
],
a1
=
a
[
1
];
const
uchar
*
h
=
qanglePtr
+
pk
.
qangleOfs
;
int
h0
=
h
[
0
],
h1
=
h
[
1
];
float
*
hist
=
blockHist
+
pk
.
histOfs
[
0
];
w
=
pk
.
gradWeight
*
pk
.
histWeights
[
0
];
t0
=
hist
[
h0
]
+
a0
*
w
;
t1
=
hist
[
h1
]
+
a1
*
w
;
hist
[
h0
]
=
t0
;
hist
[
h1
]
=
t1
;
hist
=
blockHist
+
pk
.
histOfs
[
1
];
w
=
pk
.
gradWeight
*
pk
.
histWeights
[
1
];
t0
=
hist
[
h0
]
+
a0
*
w
;
t1
=
hist
[
h1
]
+
a1
*
w
;
hist
[
h0
]
=
t0
;
hist
[
h1
]
=
t1
;
}
for
(
;
k
<
C4
;
k
++
)
{
const
PixData
&
pk
=
_pixData
[
k
];
const
float
*
a
=
gradPtr
+
pk
.
gradOfs
;
float
w
,
t0
,
t1
,
a0
=
a
[
0
],
a1
=
a
[
1
];
const
uchar
*
h
=
qanglePtr
+
pk
.
qangleOfs
;
int
h0
=
h
[
0
],
h1
=
h
[
1
];
float
*
hist
=
blockHist
+
pk
.
histOfs
[
0
];
w
=
pk
.
gradWeight
*
pk
.
histWeights
[
0
];
t0
=
hist
[
h0
]
+
a0
*
w
;
t1
=
hist
[
h1
]
+
a1
*
w
;
hist
[
h0
]
=
t0
;
hist
[
h1
]
=
t1
;
hist
=
blockHist
+
pk
.
histOfs
[
1
];
w
=
pk
.
gradWeight
*
pk
.
histWeights
[
1
];
t0
=
hist
[
h0
]
+
a0
*
w
;
t1
=
hist
[
h1
]
+
a1
*
w
;
hist
[
h0
]
=
t0
;
hist
[
h1
]
=
t1
;
hist
=
blockHist
+
pk
.
histOfs
[
2
];
w
=
pk
.
gradWeight
*
pk
.
histWeights
[
2
];
t0
=
hist
[
h0
]
+
a0
*
w
;
t1
=
hist
[
h1
]
+
a1
*
w
;
hist
[
h0
]
=
t0
;
hist
[
h1
]
=
t1
;
hist
=
blockHist
+
pk
.
histOfs
[
3
];
w
=
pk
.
gradWeight
*
pk
.
histWeights
[
3
];
t0
=
hist
[
h0
]
+
a0
*
w
;
t1
=
hist
[
h1
]
+
a1
*
w
;
hist
[
h0
]
=
t0
;
hist
[
h1
]
=
t1
;
}
normalizeBlockHistogram
(
blockHist
);
return
blockHist
;
}
void
HOGCacheTester
::
normalizeBlockHistogram
(
float
*
_hist
)
const
{
float
*
hist
=
&
_hist
[
0
],
partSum
[
4
]
=
{
0.0
f
,
0.0
f
,
0.0
f
,
0.0
f
};
size_t
i
,
sz
=
blockHistogramSize
;
for
(
i
=
0
;
i
<=
sz
-
4
;
i
+=
4
)
{
partSum
[
0
]
+=
hist
[
i
]
*
hist
[
i
];
partSum
[
1
]
+=
hist
[
i
+
1
]
*
hist
[
i
+
1
];
partSum
[
2
]
+=
hist
[
i
+
2
]
*
hist
[
i
+
2
];
partSum
[
3
]
+=
hist
[
i
+
3
]
*
hist
[
i
+
3
];
}
float
t0
=
partSum
[
0
]
+
partSum
[
1
];
float
t1
=
partSum
[
2
]
+
partSum
[
3
];
float
sum
=
t0
+
t1
;
for
(
;
i
<
sz
;
i
++
)
sum
+=
hist
[
i
]
*
hist
[
i
];
float
scale
=
1.
f
/
(
std
::
sqrt
(
sum
)
+
sz
*
0.1
f
),
thresh
=
(
float
)
descriptor
->
L2HysThreshold
;
partSum
[
0
]
=
partSum
[
1
]
=
partSum
[
2
]
=
partSum
[
3
]
=
0.0
f
;
for
(
i
=
0
;
i
<=
sz
-
4
;
i
+=
4
)
{
hist
[
i
]
=
std
::
min
(
hist
[
i
]
*
scale
,
thresh
);
hist
[
i
+
1
]
=
std
::
min
(
hist
[
i
+
1
]
*
scale
,
thresh
);
hist
[
i
+
2
]
=
std
::
min
(
hist
[
i
+
2
]
*
scale
,
thresh
);
hist
[
i
+
3
]
=
std
::
min
(
hist
[
i
+
3
]
*
scale
,
thresh
);
partSum
[
0
]
+=
hist
[
i
]
*
hist
[
i
];
partSum
[
1
]
+=
hist
[
i
+
1
]
*
hist
[
i
+
1
];
partSum
[
2
]
+=
hist
[
i
+
2
]
*
hist
[
i
+
2
];
partSum
[
3
]
+=
hist
[
i
+
3
]
*
hist
[
i
+
3
];
}
t0
=
partSum
[
0
]
+
partSum
[
1
];
t1
=
partSum
[
2
]
+
partSum
[
3
];
sum
=
t0
+
t1
;
for
(
;
i
<
sz
;
i
++
)
{
hist
[
i
]
=
std
::
min
(
hist
[
i
]
*
scale
,
thresh
);
sum
+=
hist
[
i
]
*
hist
[
i
];
}
scale
=
1.
f
/
(
std
::
sqrt
(
sum
)
+
1e-3
f
);
for
(
i
=
0
;
i
<
sz
;
i
++
)
hist
[
i
]
*=
scale
;
}
Size
HOGCacheTester
::
windowsInImage
(
Size
imageSize
,
Size
winStride
)
const
{
return
Size
((
imageSize
.
width
-
winSize
.
width
)
/
winStride
.
width
+
1
,
(
imageSize
.
height
-
winSize
.
height
)
/
winStride
.
height
+
1
);
}
Rect
HOGCacheTester
::
getWindow
(
Size
imageSize
,
Size
winStride
,
int
idx
)
const
{
int
nwindowsX
=
(
imageSize
.
width
-
winSize
.
width
)
/
winStride
.
width
+
1
;
int
y
=
idx
/
nwindowsX
;
int
x
=
idx
-
nwindowsX
*
y
;
return
Rect
(
x
*
winStride
.
width
,
y
*
winStride
.
height
,
winSize
.
width
,
winSize
.
height
);
}
inline
bool
HOGDescriptorTester
::
is_failed
()
const
{
return
failed
;
}
void
HOGDescriptorTester
::
detect
(
const
Mat
&
img
,
vector
<
Point
>&
hits
,
vector
<
double
>&
weights
,
double
hitThreshold
,
Size
winStride
,
Size
padding
,
const
vector
<
Point
>&
locations
)
const
{
if
(
failed
)
return
;
hits
.
clear
();
if
(
svmDetector
.
empty
()
)
return
;
if
(
winStride
==
Size
()
)
winStride
=
cellSize
;
Size
cacheStride
(
gcd
(
winStride
.
width
,
blockStride
.
width
),
gcd
(
winStride
.
height
,
blockStride
.
height
));
size_t
nwindows
=
locations
.
size
();
padding
.
width
=
(
int
)
alignSize
(
std
::
max
(
padding
.
width
,
0
),
cacheStride
.
width
);
padding
.
height
=
(
int
)
alignSize
(
std
::
max
(
padding
.
height
,
0
),
cacheStride
.
height
);
Size
paddedImgSize
(
img
.
cols
+
padding
.
width
*
2
,
img
.
rows
+
padding
.
height
*
2
);
HOGCacheTester
cache
(
this
,
img
,
padding
,
padding
,
nwindows
==
0
,
cacheStride
);
if
(
!
nwindows
)
nwindows
=
cache
.
windowsInImage
(
paddedImgSize
,
winStride
).
area
();
const
HOGCacheTester
::
BlockData
*
blockData
=
&
cache
.
blockData
[
0
];
int
nblocks
=
cache
.
nblocks
.
area
();
int
blockHistogramSize
=
cache
.
blockHistogramSize
;
size_t
dsize
=
getDescriptorSize
();
double
rho
=
svmDetector
.
size
()
>
dsize
?
svmDetector
[
dsize
]
:
0
;
vector
<
float
>
blockHist
(
blockHistogramSize
);
for
(
size_t
i
=
0
;
i
<
nwindows
;
i
++
)
{
Point
pt0
;
if
(
!
locations
.
empty
()
)
{
pt0
=
locations
[
i
];
if
(
pt0
.
x
<
-
padding
.
width
||
pt0
.
x
>
img
.
cols
+
padding
.
width
-
winSize
.
width
||
pt0
.
y
<
-
padding
.
height
||
pt0
.
y
>
img
.
rows
+
padding
.
height
-
winSize
.
height
)
continue
;
}
else
{
pt0
=
cache
.
getWindow
(
paddedImgSize
,
winStride
,
(
int
)
i
).
tl
()
-
Point
(
padding
);
CV_Assert
(
pt0
.
x
%
cacheStride
.
width
==
0
&&
pt0
.
y
%
cacheStride
.
height
==
0
);
}
double
s
=
rho
;
const
float
*
svmVec
=
&
svmDetector
[
0
];
int
j
,
k
;
for
(
j
=
0
;
j
<
nblocks
;
j
++
,
svmVec
+=
blockHistogramSize
)
{
const
HOGCacheTester
::
BlockData
&
bj
=
blockData
[
j
];
Point
pt
=
pt0
+
bj
.
imgOffset
;
const
float
*
vec
=
cache
.
getBlock
(
pt
,
&
blockHist
[
0
]);
for
(
k
=
0
;
k
<=
blockHistogramSize
-
4
;
k
+=
4
)
s
+=
vec
[
k
]
*
svmVec
[
k
]
+
vec
[
k
+
1
]
*
svmVec
[
k
+
1
]
+
vec
[
k
+
2
]
*
svmVec
[
k
+
2
]
+
vec
[
k
+
3
]
*
svmVec
[
k
+
3
];
for
(
;
k
<
blockHistogramSize
;
k
++
)
s
+=
vec
[
k
]
*
svmVec
[
k
];
}
if
(
s
>=
hitThreshold
)
{
hits
.
push_back
(
pt0
);
weights
.
push_back
(
s
);
}
}
// validation
std
::
vector
<
Point
>
actual_find_locations
;
std
::
vector
<
double
>
actual_weights
;
actual_hog
->
detect
(
img
,
actual_find_locations
,
actual_weights
,
hitThreshold
,
winStride
,
padding
,
locations
);
if
(
!
std
::
equal
(
hits
.
begin
(),
hits
.
end
(),
actual_find_locations
.
begin
()))
{
ts
->
printf
(
cvtest
::
TS
::
SUMMARY
,
"Found locations are not equal (see detect function)
\n
"
);
ts
->
set_failed_test_info
(
cvtest
::
TS
::
FAIL_BAD_ACCURACY
);
ts
->
set_gtest_status
();
failed
=
true
;
return
;
}
const
double
eps
=
0.0
;
double
diff_norm
=
norm
(
Mat
(
actual_weights
)
-
Mat
(
weights
),
CV_L2
);
if
(
diff_norm
>
eps
)
{
ts
->
printf
(
cvtest
::
TS
::
SUMMARY
,
"Weights for found locations aren't equal.
\n
"
"Norm of the difference is %lf
\n
"
,
diff_norm
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Channels: %d
\n
"
,
img
.
channels
());
failed
=
true
;
ts
->
set_failed_test_info
(
cvtest
::
TS
::
FAIL_BAD_ACCURACY
);
ts
->
set_gtest_status
();
return
;
}
}
void
HOGDescriptorTester
::
detect
(
const
Mat
&
img
,
vector
<
Point
>&
hits
,
double
hitThreshold
,
Size
winStride
,
Size
padding
,
const
vector
<
Point
>&
locations
)
const
{
vector
<
double
>
weightsV
;
detect
(
img
,
hits
,
weightsV
,
hitThreshold
,
winStride
,
padding
,
locations
);
}
void
HOGDescriptorTester
::
compute
(
const
Mat
&
img
,
vector
<
float
>&
descriptors
,
Size
winStride
,
Size
padding
,
const
vector
<
Point
>&
locations
)
const
{
if
(
winStride
==
Size
()
)
winStride
=
cellSize
;
Size
cacheStride
(
gcd
(
winStride
.
width
,
blockStride
.
width
),
gcd
(
winStride
.
height
,
blockStride
.
height
));
size_t
nwindows
=
locations
.
size
();
padding
.
width
=
(
int
)
alignSize
(
std
::
max
(
padding
.
width
,
0
),
cacheStride
.
width
);
padding
.
height
=
(
int
)
alignSize
(
std
::
max
(
padding
.
height
,
0
),
cacheStride
.
height
);
Size
paddedImgSize
(
img
.
cols
+
padding
.
width
*
2
,
img
.
rows
+
padding
.
height
*
2
);
HOGCacheTester
cache
(
this
,
img
,
padding
,
padding
,
nwindows
==
0
,
cacheStride
);
if
(
!
nwindows
)
nwindows
=
cache
.
windowsInImage
(
paddedImgSize
,
winStride
).
area
();
const
HOGCacheTester
::
BlockData
*
blockData
=
&
cache
.
blockData
[
0
];
int
nblocks
=
cache
.
nblocks
.
area
();
int
blockHistogramSize
=
cache
.
blockHistogramSize
;
size_t
dsize
=
getDescriptorSize
();
descriptors
.
resize
(
dsize
*
nwindows
);
for
(
size_t
i
=
0
;
i
<
nwindows
;
i
++
)
{
float
*
descriptor
=
&
descriptors
[
i
*
dsize
];
Point
pt0
;
if
(
!
locations
.
empty
()
)
{
pt0
=
locations
[
i
];
if
(
pt0
.
x
<
-
padding
.
width
||
pt0
.
x
>
img
.
cols
+
padding
.
width
-
winSize
.
width
||
pt0
.
y
<
-
padding
.
height
||
pt0
.
y
>
img
.
rows
+
padding
.
height
-
winSize
.
height
)
continue
;
}
else
{
pt0
=
cache
.
getWindow
(
paddedImgSize
,
winStride
,
(
int
)
i
).
tl
()
-
Point
(
padding
);
CV_Assert
(
pt0
.
x
%
cacheStride
.
width
==
0
&&
pt0
.
y
%
cacheStride
.
height
==
0
);
}
for
(
int
j
=
0
;
j
<
nblocks
;
j
++
)
{
const
HOGCacheTester
::
BlockData
&
bj
=
blockData
[
j
];
Point
pt
=
pt0
+
bj
.
imgOffset
;
float
*
dst
=
descriptor
+
bj
.
histOfs
;
const
float
*
src
=
cache
.
getBlock
(
pt
,
dst
);
if
(
src
!=
dst
)
for
(
int
k
=
0
;
k
<
blockHistogramSize
;
k
++
)
dst
[
k
]
=
src
[
k
];
}
}
// validation
std
::
vector
<
float
>
actual_descriptors
;
actual_hog
->
compute
(
img
,
actual_descriptors
,
winStride
,
padding
,
locations
);
double
diff_norm
=
cv
::
norm
(
Mat
(
actual_descriptors
)
-
Mat
(
descriptors
),
CV_L2
);
const
double
eps
=
0.0
;
if
(
diff_norm
>
eps
)
{
ts
->
printf
(
cvtest
::
TS
::
SUMMARY
,
"Norm of the difference: %lf
\n
"
,
diff_norm
);
ts
->
printf
(
cvtest
::
TS
::
SUMMARY
,
"Found descriptors are not equal (see compute function)
\n
"
);
ts
->
set_failed_test_info
(
cvtest
::
TS
::
FAIL_BAD_ACCURACY
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Channels: %d
\n
"
,
img
.
channels
());
ts
->
set_gtest_status
();
failed
=
true
;
return
;
}
}
void
HOGDescriptorTester
::
computeGradient
(
const
Mat
&
img
,
Mat
&
grad
,
Mat
&
qangle
,
Size
paddingTL
,
Size
paddingBR
)
const
{
CV_Assert
(
img
.
type
()
==
CV_8U
||
img
.
type
()
==
CV_8UC3
);
Size
gradsize
(
img
.
cols
+
paddingTL
.
width
+
paddingBR
.
width
,
img
.
rows
+
paddingTL
.
height
+
paddingBR
.
height
);
grad
.
create
(
gradsize
,
CV_32FC2
);
// <magnitude*(1-alpha), magnitude*alpha>
qangle
.
create
(
gradsize
,
CV_8UC2
);
// [0..nbins-1] - quantized gradient orientation
Size
wholeSize
;
Point
roiofs
;
img
.
locateROI
(
wholeSize
,
roiofs
);
int
i
,
x
,
y
;
int
cn
=
img
.
channels
();
Mat_
<
float
>
_lut
(
1
,
256
);
const
float
*
lut
=
&
_lut
(
0
,
0
);
if
(
gammaCorrection
)
for
(
i
=
0
;
i
<
256
;
i
++
)
_lut
(
0
,
i
)
=
std
::
sqrt
((
float
)
i
);
else
for
(
i
=
0
;
i
<
256
;
i
++
)
_lut
(
0
,
i
)
=
(
float
)
i
;
AutoBuffer
<
int
>
mapbuf
(
gradsize
.
width
+
gradsize
.
height
+
4
);
int
*
xmap
=
(
int
*
)
mapbuf
+
1
;
int
*
ymap
=
xmap
+
gradsize
.
width
+
2
;
const
int
borderType
=
(
int
)
BORDER_REFLECT_101
;
for
(
x
=
-
1
;
x
<
gradsize
.
width
+
1
;
x
++
)
xmap
[
x
]
=
borderInterpolate
(
x
-
paddingTL
.
width
+
roiofs
.
x
,
wholeSize
.
width
,
borderType
)
-
roiofs
.
x
;
for
(
y
=
-
1
;
y
<
gradsize
.
height
+
1
;
y
++
)
ymap
[
y
]
=
borderInterpolate
(
y
-
paddingTL
.
height
+
roiofs
.
y
,
wholeSize
.
height
,
borderType
)
-
roiofs
.
y
;
// x- & y- derivatives for the whole row
int
width
=
gradsize
.
width
;
AutoBuffer
<
float
>
_dbuf
(
width
*
4
);
float
*
dbuf
=
_dbuf
;
Mat
Dx
(
1
,
width
,
CV_32F
,
dbuf
);
Mat
Dy
(
1
,
width
,
CV_32F
,
dbuf
+
width
);
Mat
Mag
(
1
,
width
,
CV_32F
,
dbuf
+
width
*
2
);
Mat
Angle
(
1
,
width
,
CV_32F
,
dbuf
+
width
*
3
);
int
_nbins
=
nbins
;
float
angleScale
=
(
float
)(
_nbins
/
CV_PI
);
for
(
y
=
0
;
y
<
gradsize
.
height
;
y
++
)
{
const
uchar
*
imgPtr
=
img
.
data
+
img
.
step
*
ymap
[
y
];
const
uchar
*
prevPtr
=
img
.
data
+
img
.
step
*
ymap
[
y
-
1
];
const
uchar
*
nextPtr
=
img
.
data
+
img
.
step
*
ymap
[
y
+
1
];
float
*
gradPtr
=
(
float
*
)
grad
.
ptr
(
y
);
uchar
*
qanglePtr
=
(
uchar
*
)
qangle
.
ptr
(
y
);
if
(
cn
==
1
)
{
for
(
x
=
0
;
x
<
width
;
x
++
)
{
int
x1
=
xmap
[
x
];
dbuf
[
x
]
=
(
float
)(
lut
[
imgPtr
[
xmap
[
x
+
1
]]]
-
lut
[
imgPtr
[
xmap
[
x
-
1
]]]);
dbuf
[
width
+
x
]
=
(
float
)(
lut
[
nextPtr
[
x1
]]
-
lut
[
prevPtr
[
x1
]]);
}
}
else
{
for
(
x
=
0
;
x
<
width
;
x
++
)
{
int
x1
=
xmap
[
x
]
*
3
;
float
dx0
,
dy0
,
dx
,
dy
,
mag0
,
mag
;
const
uchar
*
p2
=
imgPtr
+
xmap
[
x
+
1
]
*
3
;
const
uchar
*
p0
=
imgPtr
+
xmap
[
x
-
1
]
*
3
;
dx0
=
lut
[
p2
[
2
]]
-
lut
[
p0
[
2
]];
dy0
=
lut
[
nextPtr
[
x1
+
2
]]
-
lut
[
prevPtr
[
x1
+
2
]];
mag0
=
dx0
*
dx0
+
dy0
*
dy0
;
dx
=
lut
[
p2
[
1
]]
-
lut
[
p0
[
1
]];
dy
=
lut
[
nextPtr
[
x1
+
1
]]
-
lut
[
prevPtr
[
x1
+
1
]];
mag
=
dx
*
dx
+
dy
*
dy
;
if
(
mag0
<
mag
)
{
dx0
=
dx
;
dy0
=
dy
;
mag0
=
mag
;
}
dx
=
lut
[
p2
[
0
]]
-
lut
[
p0
[
0
]];
dy
=
lut
[
nextPtr
[
x1
]]
-
lut
[
prevPtr
[
x1
]];
mag
=
dx
*
dx
+
dy
*
dy
;
if
(
mag0
<
mag
)
{
dx0
=
dx
;
dy0
=
dy
;
mag0
=
mag
;
}
dbuf
[
x
]
=
dx0
;
dbuf
[
x
+
width
]
=
dy0
;
}
}
cartToPolar
(
Dx
,
Dy
,
Mag
,
Angle
,
false
);
for
(
x
=
0
;
x
<
width
;
x
++
)
{
float
mag
=
dbuf
[
x
+
width
*
2
],
angle
=
dbuf
[
x
+
width
*
3
]
*
angleScale
-
0.5
f
;
int
hidx
=
cvFloor
(
angle
);
angle
-=
hidx
;
gradPtr
[
x
*
2
]
=
mag
*
(
1.
f
-
angle
);
gradPtr
[
x
*
2
+
1
]
=
mag
*
angle
;
if
(
hidx
<
0
)
hidx
+=
_nbins
;
else
if
(
hidx
>=
_nbins
)
hidx
-=
_nbins
;
assert
(
(
unsigned
)
hidx
<
(
unsigned
)
_nbins
);
qanglePtr
[
x
*
2
]
=
(
uchar
)
hidx
;
hidx
++
;
hidx
&=
hidx
<
_nbins
?
-
1
:
0
;
qanglePtr
[
x
*
2
+
1
]
=
(
uchar
)
hidx
;
}
}
// validation
Mat
actual_mats
[
2
],
reference_mats
[
2
]
=
{
grad
,
qangle
};
const
char
*
args
[]
=
{
"Gradient's"
,
"Qangles's"
};
actual_hog
->
computeGradient
(
img
,
actual_mats
[
0
],
actual_mats
[
1
],
paddingTL
,
paddingBR
);
const
double
eps
=
0.0
;
for
(
i
=
0
;
i
<
2
;
++
i
)
{
double
diff_norm
=
norm
(
reference_mats
[
i
]
-
actual_mats
[
i
],
CV_L2
);
if
(
diff_norm
>
eps
)
{
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"%s matrices are not equal
\n
"
"Norm of the difference is %lf
\n
"
,
args
[
i
],
diff_norm
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Channels: %d
\n
"
,
img
.
channels
());
ts
->
set_failed_test_info
(
cvtest
::
TS
::
FAIL_BAD_ACCURACY
);
ts
->
set_gtest_status
();
failed
=
true
;
return
;
}
}
}
TEST
(
Objdetect_HOGDetector_Strict
,
accuracy
)
{
cvtest
::
TS
*
ts
=
cvtest
::
TS
::
ptr
();
RNG
&
rng
=
ts
->
get_rng
();
HOGDescriptor
actual_hog
;
actual_hog
.
setSVMDetector
(
HOGDescriptor
::
getDefaultPeopleDetector
());
HOGDescriptorTester
reference_hog
(
actual_hog
);
const
unsigned
int
test_case_count
=
5
;
for
(
unsigned
int
i
=
0
;
i
<
test_case_count
&&
!
reference_hog
.
is_failed
();
++
i
)
{
// creating a matrix
Size
ssize
(
rng
.
uniform
(
1
,
10
)
*
actual_hog
.
winSize
.
width
,
rng
.
uniform
(
1
,
10
)
*
actual_hog
.
winSize
.
height
);
int
type
=
rng
.
uniform
(
0
,
1
)
>
0
?
CV_8UC1
:
CV_8UC3
;
Mat
image
(
ssize
,
type
);
rng
.
fill
(
image
,
RNG
::
UNIFORM
,
0
,
256
,
true
);
// checking detect
std
::
vector
<
Point
>
hits
;
std
::
vector
<
double
>
weights
;
reference_hog
.
detect
(
image
,
hits
,
weights
);
// checking compute
std
::
vector
<
float
>
descriptors
;
reference_hog
.
compute
(
image
,
descriptors
);
}
}
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