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
957cff24
Commit
957cff24
authored
Nov 12, 2010
by
Vadim Pisarevsky
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
rewrote matchTemplate in C++; added border awareness to crossCorr (ticket #557)
parent
9e7b8d5f
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
208 additions
and
311 deletions
+208
-311
templmatch.cpp
modules/imgproc/src/templmatch.cpp
+208
-311
No files found.
modules/imgproc/src/templmatch.cpp
View file @
957cff24
...
...
@@ -41,429 +41,320 @@
#include "precomp.hpp"
void
icvCrossCorr
(
const
CvArr
*
_img
,
const
CvArr
*
_templ
,
CvArr
*
_corr
,
CvPoint
anchor
,
double
delta
,
int
borderType
)
namespace
cv
{
const
int
CV_MAX_THREADS
=
1
;
const
double
block_scale
=
4.5
;
const
int
min_block_size
=
256
;
cv
::
Ptr
<
CvMat
>
dft_img
[
CV_MAX_THREADS
];
cv
::
Ptr
<
CvMat
>
dft_templ
;
std
::
vector
<
uchar
>
buf
[
CV_MAX_THREADS
];
int
k
,
num_threads
=
0
;
void
crossCorr
(
const
Mat
&
img
,
const
Mat
&
templ
,
Mat
&
corr
,
Size
corrsize
,
int
ctype
,
Point
anchor
,
double
delta
,
int
borderType
)
{
const
double
blockScale
=
4.5
;
const
int
minBlockSize
=
256
;
std
::
vector
<
uchar
>
buf
;
int
depth
=
img
.
depth
(),
cn
=
img
.
channels
();
int
tdepth
=
templ
.
depth
(),
tcn
=
templ
.
channels
();
int
cdepth
=
CV_MAT_DEPTH
(
ctype
),
ccn
=
CV_MAT_CN
(
ctype
);
CV_Assert
(
img
.
dims
<=
2
&&
templ
.
dims
<=
2
&&
corr
.
dims
<=
2
);
CV_Assert
(
depth
==
CV_8U
||
depth
==
CV_16U
||
depth
==
CV_32F
||
depth
==
CV_64F
);
CV_Assert
(
depth
==
tdepth
||
tdepth
==
CV_32F
);
CV_Assert
(
corrsize
.
height
<=
img
.
rows
+
templ
.
rows
-
1
&&
corrsize
.
width
<=
img
.
cols
+
templ
.
cols
-
1
);
CV_Assert
(
ccn
==
1
||
delta
==
0
);
CvMat
istub
,
*
img
=
(
CvMat
*
)
_img
;
CvMat
tstub
,
*
templ
=
(
CvMat
*
)
_templ
;
CvMat
cstub
,
*
corr
=
(
CvMat
*
)
_corr
;
CvSize
dftsize
,
blocksize
;
int
depth
,
templ_depth
,
corr_depth
,
max_depth
=
CV_32F
,
cn
,
templ_cn
,
corr_cn
,
buf_size
=
0
,
tile_count_x
,
tile_count_y
,
tile_count
;
img
=
cvGetMat
(
img
,
&
istub
);
templ
=
cvGetMat
(
templ
,
&
tstub
);
corr
=
cvGetMat
(
corr
,
&
cstub
);
if
(
CV_MAT_DEPTH
(
img
->
type
)
!=
CV_8U
&&
CV_MAT_DEPTH
(
img
->
type
)
!=
CV_16U
&&
CV_MAT_DEPTH
(
img
->
type
)
!=
CV_32F
&&
CV_MAT_DEPTH
(
img
->
type
)
!=
CV_64F
)
CV_Error
(
CV_StsUnsupportedFormat
,
"The function supports only 8u, 16u and 32f data types"
);
if
(
!
CV_ARE_DEPTHS_EQ
(
img
,
templ
)
&&
CV_MAT_DEPTH
(
templ
->
type
)
!=
CV_32F
)
CV_Error
(
CV_StsUnsupportedFormat
,
"Template (kernel) must be of the same depth as the input image, or be 32f"
);
corr
.
create
(
corrsize
,
ctype
);
int
maxDepth
=
depth
>
CV_8U
?
CV_64F
:
std
::
max
(
std
::
max
(
CV_32F
,
tdepth
),
cdepth
);
Size
blocksize
,
dftsize
;
if
(
!
CV_ARE_DEPTHS_EQ
(
img
,
corr
)
&&
CV_MAT_DEPTH
(
corr
->
type
)
!=
CV_32F
&&
CV_MAT_DEPTH
(
corr
->
type
)
!=
CV_64F
)
CV_Error
(
CV_StsUnsupportedFormat
,
"The output image must have the same depth as the input image, or be 32f/64f"
);
if
(
(
!
CV_ARE_CNS_EQ
(
img
,
corr
)
||
CV_MAT_CN
(
templ
->
type
)
>
1
)
&&
(
CV_MAT_CN
(
corr
->
type
)
>
1
||
!
CV_ARE_CNS_EQ
(
img
,
templ
))
)
CV_Error
(
CV_StsUnsupportedFormat
,
"The output must have the same number of channels as the input (when the template has 1 channel), "
"or the output must have 1 channel when the input and the template have the same number of channels"
);
depth
=
CV_MAT_DEPTH
(
img
->
type
);
cn
=
CV_MAT_CN
(
img
->
type
);
templ_depth
=
CV_MAT_DEPTH
(
templ
->
type
);
templ_cn
=
CV_MAT_CN
(
templ
->
type
);
corr_depth
=
CV_MAT_DEPTH
(
corr
->
type
);
corr_cn
=
CV_MAT_CN
(
corr
->
type
);
CV_Assert
(
corr_cn
==
1
||
delta
==
0
);
max_depth
=
MAX
(
max_depth
,
templ_depth
);
max_depth
=
MAX
(
max_depth
,
depth
);
max_depth
=
MAX
(
max_depth
,
corr_depth
);
if
(
depth
>
CV_8U
)
max_depth
=
CV_64F
;
/*if( img->cols < templ->cols || img->rows < templ->rows )
CV_Error( CV_StsUnmatchedSizes,
"Such a combination of image and template/filter size is not supported" );*/
if
(
corr
->
rows
>
img
->
rows
+
templ
->
rows
-
1
||
corr
->
cols
>
img
->
cols
+
templ
->
cols
-
1
)
CV_Error
(
CV_StsUnmatchedSizes
,
"output image should not be greater than (W + w - 1)x(H + h - 1)"
);
blocksize
.
width
=
cvRound
(
templ
->
cols
*
block_scale
);
blocksize
.
width
=
MAX
(
blocksize
.
width
,
min_block_size
-
templ
->
cols
+
1
);
blocksize
.
width
=
MIN
(
blocksize
.
width
,
corr
->
cols
);
blocksize
.
height
=
cvRound
(
templ
->
rows
*
block_scale
);
blocksize
.
height
=
MAX
(
blocksize
.
height
,
min_block_size
-
templ
->
rows
+
1
);
blocksize
.
height
=
MIN
(
blocksize
.
height
,
corr
->
rows
);
dftsize
.
width
=
cvGetOptimalDFTSize
(
blocksize
.
width
+
templ
->
cols
-
1
);
if
(
dftsize
.
width
==
1
)
dftsize
.
width
=
2
;
dftsize
.
height
=
cvGetOptimalDFTSize
(
blocksize
.
height
+
templ
->
rows
-
1
);
blocksize
.
width
=
cvRound
(
templ
.
cols
*
blockScale
);
blocksize
.
width
=
std
::
max
(
blocksize
.
width
,
minBlockSize
-
templ
.
cols
+
1
);
blocksize
.
width
=
std
::
min
(
blocksize
.
width
,
corr
.
cols
);
blocksize
.
height
=
cvRound
(
templ
.
rows
*
blockScale
);
blocksize
.
height
=
std
::
max
(
blocksize
.
height
,
minBlockSize
-
templ
.
rows
+
1
);
blocksize
.
height
=
std
::
min
(
blocksize
.
height
,
corr
.
rows
);
dftsize
.
width
=
std
::
max
(
getOptimalDFTSize
(
blocksize
.
width
+
templ
.
cols
-
1
),
2
);
dftsize
.
height
=
getOptimalDFTSize
(
blocksize
.
height
+
templ
.
rows
-
1
);
if
(
dftsize
.
width
<=
0
||
dftsize
.
height
<=
0
)
CV_Error
(
CV_StsOutOfRange
,
"the input arrays are too big"
);
// recompute block size
blocksize
.
width
=
dftsize
.
width
-
templ
->
cols
+
1
;
blocksize
.
width
=
MIN
(
blocksize
.
width
,
corr
->
cols
);
blocksize
.
height
=
dftsize
.
height
-
templ
->
rows
+
1
;
blocksize
.
height
=
MIN
(
blocksize
.
height
,
corr
->
rows
);
dft_templ
=
cvCreateMat
(
dftsize
.
height
*
templ_cn
,
dftsize
.
width
,
max_depth
);
#ifdef USE_OPENMP
num_threads
=
cvGetNumThreads
();
#else
num_threads
=
1
;
#endif
blocksize
.
width
=
dftsize
.
width
-
templ
.
cols
+
1
;
blocksize
.
width
=
MIN
(
blocksize
.
width
,
corr
.
cols
);
blocksize
.
height
=
dftsize
.
height
-
templ
.
rows
+
1
;
blocksize
.
height
=
MIN
(
blocksize
.
height
,
corr
.
rows
);
for
(
k
=
0
;
k
<
num_threads
;
k
++
)
dft_img
[
k
]
=
cvCreateMat
(
dftsize
.
height
,
dftsize
.
width
,
max_d
epth
);
Mat
dftTempl
(
dftsize
.
height
*
tcn
,
dftsize
.
width
,
maxDepth
);
Mat
dftImg
(
dftsize
,
maxD
epth
);
if
(
templ_cn
>
1
&&
templ_depth
!=
max_depth
)
buf_size
=
templ
->
cols
*
templ
->
rows
*
CV_ELEM_SIZE
(
templ_depth
);
int
i
,
k
,
bufSize
=
0
;
if
(
tcn
>
1
&&
tdepth
!=
maxDepth
)
bufSize
=
templ
.
cols
*
templ
.
rows
*
CV_ELEM_SIZE
(
tdepth
);
if
(
cn
>
1
&&
depth
!=
max
_d
epth
)
buf
_size
=
MAX
(
buf_size
,
(
blocksize
.
width
+
templ
->
cols
-
1
)
*
(
blocksize
.
height
+
templ
->
rows
-
1
)
*
CV_ELEM_SIZE
(
depth
));
if
(
cn
>
1
&&
depth
!=
max
D
epth
)
buf
Size
=
std
::
max
(
bufSize
,
(
blocksize
.
width
+
templ
.
cols
-
1
)
*
(
blocksize
.
height
+
templ
.
rows
-
1
)
*
CV_ELEM_SIZE
(
depth
));
if
(
(
corr_cn
>
1
||
cn
>
1
)
&&
corr_depth
!=
max_depth
)
buf_size
=
MAX
(
buf_size
,
blocksize
.
width
*
blocksize
.
height
*
CV_ELEM_SIZE
(
corr_depth
));
if
(
buf_size
>
0
)
{
for
(
k
=
0
;
k
<
num_threads
;
k
++
)
buf
[
k
].
resize
(
buf_size
);
}
if
(
(
ccn
>
1
||
cn
>
1
)
&&
cdepth
!=
maxDepth
)
bufSize
=
std
::
max
(
bufSize
,
blocksize
.
width
*
blocksize
.
height
*
CV_ELEM_SIZE
(
cdepth
));
buf
.
resize
(
bufSize
);
// compute DFT of each template plane
for
(
k
=
0
;
k
<
t
empl_
cn
;
k
++
)
for
(
k
=
0
;
k
<
tcn
;
k
++
)
{
CvMat
dstub
,
*
src
,
*
dst
,
temp
;
CvMat
*
planes
[]
=
{
0
,
0
,
0
,
0
};
int
yofs
=
k
*
dftsize
.
height
;
Mat
src
=
templ
;
Mat
dst
(
dftTempl
,
Rect
(
0
,
yofs
,
dftsize
.
width
,
dftsize
.
height
));
Mat
dst1
(
dftTempl
,
Rect
(
0
,
yofs
,
templ
.
cols
,
templ
.
rows
));
src
=
templ
;
dst
=
cvGetSubRect
(
dft_templ
,
&
dstub
,
cvRect
(
0
,
yofs
,
templ
->
cols
,
templ
->
rows
));
if
(
templ_cn
>
1
)
if
(
tcn
>
1
)
{
planes
[
k
]
=
templ_depth
==
max_depth
?
dst
:
cvInitMatHeader
(
&
temp
,
templ
->
rows
,
templ
->
cols
,
templ_depth
,
&
buf
[
0
][
0
]
);
cvSplit
(
templ
,
planes
[
0
],
planes
[
1
],
planes
[
2
],
planes
[
3
]
);
src
=
planes
[
k
];
planes
[
k
]
=
0
;
src
=
tdepth
==
maxDepth
?
dst1
:
Mat
(
templ
.
size
(),
tdepth
,
&
buf
[
0
]);
int
pairs
[]
=
{
k
,
0
};
mixChannels
(
&
templ
,
1
,
&
src
,
1
,
pairs
,
1
);
}
if
(
dst
!=
src
)
cvConvert
(
src
,
dst
);
if
(
dst
1
.
data
!=
src
.
data
)
src
.
convertTo
(
dst1
,
dst1
.
depth
()
);
if
(
d
ft_templ
->
cols
>
templ
->
cols
)
if
(
d
st
.
cols
>
templ
.
cols
)
{
cvGetSubRect
(
dft_templ
,
dst
,
cvRect
(
templ
->
cols
,
yofs
,
dft_templ
->
cols
-
templ
->
cols
,
templ
->
rows
)
);
cvZero
(
dst
);
Mat
part
(
dst
,
Range
(
0
,
templ
.
rows
),
Range
(
templ
.
cols
,
dst
.
cols
));
part
=
Scalar
::
all
(
0
);
}
cvGetSubRect
(
dft_templ
,
dst
,
cvRect
(
0
,
yofs
,
dftsize
.
width
,
dftsize
.
height
)
);
cvDFT
(
dst
,
dst
,
CV_DXT_FORWARD
+
CV_DXT_SCALE
,
templ
->
rows
);
dft
(
dst
,
dst
,
0
,
templ
.
rows
);
}
tile_count_x
=
(
corr
->
cols
+
blocksize
.
width
-
1
)
/
blocksize
.
width
;
tile_count_y
=
(
corr
->
rows
+
blocksize
.
height
-
1
)
/
blocksize
.
height
;
tile_count
=
tile_count_x
*
tile_count_y
;
#if defined _OPENMP && defined USE_OPENMP
#pragma omp parallel for num_threads(num_threads) schedule(dynamic)
#endif
int
tileCountX
=
(
corr
.
cols
+
blocksize
.
width
-
1
)
/
blocksize
.
width
;
int
tileCountY
=
(
corr
.
rows
+
blocksize
.
height
-
1
)
/
blocksize
.
height
;
int
tileCount
=
tileCountX
*
tileCountY
;
Size
wholeSize
=
img
.
size
();
Point
roiofs
(
0
,
0
);
Mat
img0
=
img
;
if
(
!
(
borderType
&
BORDER_ISOLATED
)
)
{
img
.
locateROI
(
wholeSize
,
roiofs
);
img0
.
adjustROI
(
roiofs
.
y
,
wholeSize
.
height
-
img
.
rows
-
roiofs
.
y
,
roiofs
.
x
,
wholeSize
.
width
-
img
.
cols
-
roiofs
.
x
);
}
// calculate correlation by blocks
for
(
k
=
0
;
k
<
tile_count
;
k
++
)
for
(
i
=
0
;
i
<
tileCount
;
i
++
)
{
#ifdef USE_OPENMP
int
thread_idx
=
cvGetThreadNum
();
#else
int
thread_idx
=
0
;
#endif
int
x
=
(
k
%
tile_count_x
)
*
blocksize
.
width
;
int
y
=
(
k
/
tile_count_x
)
*
blocksize
.
height
;
int
i
,
yofs
;
CvMat
sstub
,
dstub
,
*
src
,
*
dst
,
temp
;
CvMat
*
planes
[]
=
{
0
,
0
,
0
,
0
};
CvMat
*
_dft_img
=
dft_img
[
thread_idx
];
uchar
*
_buf
=
buf_size
>
0
?
&
buf
[
thread_idx
][
0
]
:
0
;
CvSize
csz
=
{
blocksize
.
width
,
blocksize
.
height
},
isz
;
int
x0
=
x
-
anchor
.
x
,
y0
=
y
-
anchor
.
y
;
int
x1
=
MAX
(
0
,
x0
),
y1
=
MAX
(
0
,
y0
),
x2
,
y2
;
csz
.
width
=
MIN
(
csz
.
width
,
corr
->
cols
-
x
);
csz
.
height
=
MIN
(
csz
.
height
,
corr
->
rows
-
y
);
isz
.
width
=
csz
.
width
+
templ
->
cols
-
1
;
isz
.
height
=
csz
.
height
+
templ
->
rows
-
1
;
x2
=
MIN
(
img
->
cols
,
x0
+
isz
.
width
);
y2
=
MIN
(
img
->
rows
,
y0
+
isz
.
height
);
int
x
=
(
i
%
tileCountX
)
*
blocksize
.
width
;
int
y
=
(
i
/
tileCountX
)
*
blocksize
.
height
;
Size
bsz
(
std
::
min
(
blocksize
.
width
,
corr
.
cols
-
x
),
std
::
min
(
blocksize
.
height
,
corr
.
rows
-
y
));
Size
dsz
(
bsz
.
width
+
templ
.
cols
-
1
,
bsz
.
height
+
templ
.
rows
-
1
);
int
x0
=
x
-
anchor
.
x
+
roiofs
.
x
,
y0
=
y
-
anchor
.
y
+
roiofs
.
y
;
int
x1
=
std
::
max
(
0
,
x0
),
y1
=
std
::
max
(
0
,
y0
);
int
x2
=
std
::
min
(
img0
.
cols
,
x0
+
dsz
.
width
);
int
y2
=
std
::
min
(
img0
.
rows
,
y0
+
dsz
.
height
);
Mat
src0
(
img0
,
Range
(
y1
,
y2
),
Range
(
x1
,
x2
));
Mat
dst
(
dftImg
,
Rect
(
0
,
0
,
dsz
.
width
,
dsz
.
height
));
Mat
dst1
(
dftImg
,
Rect
(
x1
-
x0
,
y1
-
y0
,
x2
-
x1
,
y2
-
y1
));
Mat
cdst
(
corr
,
Rect
(
x
,
y
,
bsz
.
width
,
bsz
.
height
));
for
(
i
=
0
;
i
<
cn
;
i
++
)
for
(
k
=
0
;
k
<
cn
;
k
++
)
{
CvMat
dstub1
,
*
dst1
;
yofs
=
i
*
dftsize
.
height
;
src
=
cvGetSubRect
(
img
,
&
sstub
,
cvRect
(
x1
,
y1
,
x2
-
x1
,
y2
-
y1
)
);
dst
=
cvGetSubRect
(
_dft_img
,
&
dstub
,
cvRect
(
0
,
0
,
isz
.
width
,
isz
.
height
)
);
dst1
=
dst
;
Mat
src
=
src0
;
if
(
x2
-
x1
<
isz
.
width
||
y2
-
y1
<
isz
.
height
)
dst1
=
cvGetSubRect
(
_dft_img
,
&
dstub1
,
cvRect
(
x1
-
x0
,
y1
-
y0
,
x2
-
x1
,
y2
-
y1
));
if
(
cn
>
1
)
{
planes
[
i
]
=
dst1
;
if
(
depth
!=
max_depth
)
planes
[
i
]
=
cvInitMatHeader
(
&
temp
,
y2
-
y1
,
x2
-
x1
,
depth
,
_buf
);
cvSplit
(
src
,
planes
[
0
],
planes
[
1
],
planes
[
2
],
planes
[
3
]
);
src
=
planes
[
i
];
planes
[
i
]
=
0
;
src
=
depth
==
maxDepth
?
dst1
:
Mat
(
y2
-
y1
,
x2
-
x1
,
depth
,
&
buf
[
0
]);
int
pairs
[]
=
{
k
,
0
};
mixChannels
(
&
src0
,
1
,
&
src
,
1
,
pairs
,
1
);
}
if
(
dst1
!=
src
)
cvConvert
(
src
,
dst1
);
if
(
dst1
.
data
!=
src
.
data
)
src
.
convertTo
(
dst1
,
dst1
.
depth
()
);
if
(
dst
!=
dst1
)
cvCopyMakeBorder
(
dst1
,
dst
,
cvPoint
(
x1
-
x0
,
y1
-
y0
),
borderType
);
if
(
x2
-
x1
<
dsz
.
width
||
y2
-
y1
<
dsz
.
height
)
copyMakeBorder
(
dst1
,
dst
,
y1
-
y0
,
dst
.
rows
-
dst1
.
rows
-
(
y1
-
y0
),
x1
-
x0
,
dst
.
cols
-
dst1
.
cols
-
(
x1
-
x0
),
borderType
);
if
(
dftsize
.
width
>
i
sz
.
width
)
if
(
dftsize
.
width
>
d
sz
.
width
)
{
cvGetSubRect
(
_dft_img
,
dst
,
cvRect
(
isz
.
width
,
0
,
dftsize
.
width
-
isz
.
width
,
dftsize
.
height
)
);
cvZero
(
dst
);
Mat
part
(
dftImg
,
Range
(
0
,
dsz
.
height
),
Range
(
dsz
.
width
,
dftsize
.
width
));
part
=
Scalar
::
all
(
0
);
}
cvDFT
(
_dft_img
,
_dft_img
,
CV_DXT_FORWARD
,
isz
.
height
);
cvGetSubRect
(
dft_templ
,
dst
,
cvRect
(
0
,(
templ_cn
>
1
?
yofs
:
0
),
dftsize
.
width
,
dftsize
.
height
)
);
cvMulSpectrums
(
_dft_img
,
dst
,
_dft_img
,
CV_DXT_MUL_CONJ
);
cvDFT
(
_dft_img
,
_dft_img
,
CV_DXT_INVERSE
,
csz
.
height
);
dft
(
dftImg
,
dftImg
,
0
,
dsz
.
height
);
Mat
dftTempl1
(
dftTempl
,
Rect
(
0
,
tcn
>
1
?
k
*
dftsize
.
height
:
0
,
dftsize
.
width
,
dftsize
.
height
));
mulSpectrums
(
dftImg
,
dftTempl1
,
dftImg
,
0
,
true
);
dft
(
dftImg
,
dftImg
,
DFT_INVERSE
+
DFT_SCALE
,
bsz
.
height
);
src
=
cvGetSubRect
(
_dft_img
,
&
sstub
,
cvRect
(
0
,
0
,
csz
.
width
,
csz
.
height
)
);
dst
=
cvGetSubRect
(
corr
,
&
dstub
,
cvRect
(
x
,
y
,
csz
.
width
,
csz
.
height
)
);
src
=
dftImg
(
Rect
(
0
,
0
,
bsz
.
width
,
bsz
.
height
));
if
(
c
orr_
cn
>
1
)
if
(
ccn
>
1
)
{
planes
[
i
]
=
src
;
if
(
corr_depth
!=
max_depth
)
if
(
cdepth
!=
maxDepth
)
{
planes
[
i
]
=
cvInitMatHeader
(
&
temp
,
csz
.
height
,
csz
.
width
,
corr_depth
,
_buf
);
cvConvertScale
(
src
,
planes
[
i
],
1
,
delta
)
;
Mat
plane
(
bsz
,
cdepth
,
&
buf
[
0
]);
src
.
convertTo
(
plane
,
cdepth
,
1
,
delta
);
src
=
plane
;
}
cvMerge
(
planes
[
0
],
planes
[
1
],
planes
[
2
],
planes
[
3
],
dst
)
;
planes
[
i
]
=
0
;
int
pairs
[]
=
{
0
,
k
}
;
mixChannels
(
&
src
,
1
,
&
cdst
,
1
,
pairs
,
1
);
}
else
{
if
(
i
==
0
)
cvConvertScale
(
src
,
dst
,
1
,
delta
);
if
(
k
==
0
)
src
.
convertTo
(
cdst
,
cdepth
,
1
,
delta
);
else
{
if
(
max
_depth
>
corr_
depth
)
if
(
max
Depth
!=
c
depth
)
{
cvInitMatHeader
(
&
temp
,
csz
.
height
,
csz
.
width
,
corr_depth
,
_buf
);
cvConvert
(
src
,
&
temp
);
src
=
&
temp
;
Mat
plane
(
bsz
,
cdepth
,
&
buf
[
0
]);
src
.
convertTo
(
plane
,
cdepth
);
src
=
plane
;
}
cvAcc
(
src
,
dst
);
add
(
src
,
cdst
,
cdst
);
}
}
}
}
}
void
/*
void
cv::crossCorr( const Mat& img, const Mat& templ, Mat& corr,
Point anchor, double delta, int borderType )
{
CvMat _img = img, _templ = templ, _corr = corr;
icvCrossCorr( &_img, &_templ, &_corr, anchor, delta, borderType );
}
}
*/
/*****************************************************************************************/
CV_IMPL
void
cvMatchTemplate
(
const
CvArr
*
_img
,
const
CvArr
*
_templ
,
CvArr
*
_result
,
int
method
)
void
matchTemplate
(
const
Mat
&
_img
,
const
Mat
&
_templ
,
Mat
&
result
,
int
method
)
{
cv
::
Ptr
<
CvMat
>
sum
,
sqsum
;
CV_Assert
(
CV_TM_SQDIFF
<=
method
&&
method
<=
CV_TM_CCOEFF_NORMED
)
;
int
coi1
=
0
,
coi2
=
0
;
int
depth
,
cn
;
int
i
,
j
,
k
;
CvMat
stub
,
*
img
=
(
CvMat
*
)
_img
;
CvMat
tstub
,
*
templ
=
(
CvMat
*
)
_templ
;
CvMat
rstub
,
*
result
=
(
CvMat
*
)
_result
;
CvScalar
templ_mean
=
cvScalarAll
(
0
);
double
templ_norm
=
0
,
templ_sum2
=
0
;
int
idx
=
0
,
idx2
=
0
;
double
*
p0
,
*
p1
,
*
p2
,
*
p3
;
double
*
q0
,
*
q1
,
*
q2
,
*
q3
;
double
inv_area
;
int
sum_step
,
sqsum_step
;
int
num_type
=
method
==
CV_TM_CCORR
||
method
==
CV_TM_CCORR_NORMED
?
0
:
method
==
CV_TM_CCOEFF
||
method
==
CV_TM_CCOEFF_NORMED
?
1
:
2
;
int
is_normed
=
method
==
CV_TM_CCORR_NORMED
||
int
numType
=
method
==
CV_TM_CCORR
||
method
==
CV_TM_CCORR_NORMED
?
0
:
method
==
CV_TM_CCOEFF
||
method
==
CV_TM_CCOEFF_NORMED
?
1
:
2
;
bool
isNormed
=
method
==
CV_TM_CCORR_NORMED
||
method
==
CV_TM_SQDIFF_NORMED
||
method
==
CV_TM_CCOEFF_NORMED
;
img
=
cvGetMat
(
img
,
&
stub
,
&
coi1
);
templ
=
cvGetMat
(
templ
,
&
tstub
,
&
coi2
);
result
=
cvGetMat
(
result
,
&
rstub
);
if
(
CV_MAT_DEPTH
(
img
->
type
)
!=
CV_8U
&&
CV_MAT_DEPTH
(
img
->
type
)
!=
CV_32F
)
CV_Error
(
CV_StsUnsupportedFormat
,
"The function supports only 8u and 32f data types"
);
if
(
!
CV_ARE_TYPES_EQ
(
img
,
templ
))
CV_Error
(
CV_StsUnmatchedSizes
,
"image and template should have the same type"
);
if
(
CV_MAT_TYPE
(
result
->
type
)
!=
CV_32FC1
)
CV_Error
(
CV_StsUnsupportedFormat
,
"output image should have 32f type"
);
if
(
img
->
rows
<
templ
->
rows
||
img
->
cols
<
templ
->
cols
)
{
CvMat
*
t
;
CV_SWAP
(
img
,
templ
,
t
);
}
if
(
result
->
rows
!=
img
->
rows
-
templ
->
rows
+
1
||
result
->
cols
!=
img
->
cols
-
templ
->
cols
+
1
)
CV_Error
(
CV_StsUnmatchedSizes
,
"output image should be (W - w + 1)x(H - h + 1)"
);
if
(
method
<
CV_TM_SQDIFF
||
method
>
CV_TM_CCOEFF_NORMED
)
CV_Error
(
CV_StsBadArg
,
"unknown comparison method"
);
depth
=
CV_MAT_DEPTH
(
img
->
type
);
cn
=
CV_MAT_CN
(
img
->
type
);
Mat
img
=
_img
,
templ
=
_templ
;
if
(
img
.
rows
<
templ
.
rows
||
img
.
cols
<
templ
.
cols
)
std
::
swap
(
img
,
templ
);
CV_Assert
(
(
img
.
depth
()
==
CV_8U
||
img
.
depth
()
==
CV_32F
)
&&
img
.
type
()
==
templ
.
type
()
);
icvCrossCorr
(
img
,
templ
,
result
);
int
cn
=
img
.
channels
();
crossCorr
(
img
,
templ
,
result
,
Size
(
img
.
cols
-
templ
.
cols
+
1
,
img
.
rows
-
templ
.
rows
+
1
),
CV_32F
,
Point
(
0
,
0
),
0
,
0
);
if
(
method
==
CV_TM_CCORR
)
return
;
inv_area
=
1.
/
((
double
)
templ
->
rows
*
templ
->
cols
);
double
invArea
=
1.
/
((
double
)
templ
.
rows
*
templ
.
cols
);
sum
=
cvCreateMat
(
img
->
rows
+
1
,
img
->
cols
+
1
,
CV_MAKETYPE
(
CV_64F
,
cn
));
Mat
sum
,
sqsum
;
Scalar
templMean
,
templSdv
;
double
*
q0
=
0
,
*
q1
=
0
,
*
q2
=
0
,
*
q3
=
0
;
double
templNorm
=
0
,
templSum2
=
0
;
if
(
method
==
CV_TM_CCOEFF
)
{
cvIntegral
(
img
,
sum
,
0
,
0
);
templ_mean
=
cvAvg
(
templ
);
q0
=
q1
=
q2
=
q3
=
0
;
integral
(
img
,
sum
,
CV_64F
);
templMean
=
mean
(
templ
);
}
else
{
CvScalar
_templ_sdv
=
cvScalarAll
(
0
);
sqsum
=
cvCreateMat
(
img
->
rows
+
1
,
img
->
cols
+
1
,
CV_MAKETYPE
(
CV_64F
,
cn
));
cvIntegral
(
img
,
sum
,
sqsum
,
0
);
cvAvgSdv
(
templ
,
&
templ_mean
,
&
_templ_sdv
);
integral
(
img
,
sum
,
sqsum
,
CV_64F
);
meanStdDev
(
templ
,
templMean
,
templSdv
);
templ
_norm
=
CV_SQR
(
_templ_sdv
.
val
[
0
])
+
CV_SQR
(
_templ_sdv
.
val
[
1
])
+
CV_SQR
(
_templ_sdv
.
val
[
2
])
+
CV_SQR
(
_templ_sdv
.
val
[
3
]);
templ
Norm
=
CV_SQR
(
templSdv
[
0
])
+
CV_SQR
(
templSdv
[
1
])
+
CV_SQR
(
templSdv
[
2
])
+
CV_SQR
(
templSdv
[
3
]);
if
(
templ
_n
orm
<
DBL_EPSILON
&&
method
==
CV_TM_CCOEFF_NORMED
)
if
(
templ
N
orm
<
DBL_EPSILON
&&
method
==
CV_TM_CCOEFF_NORMED
)
{
cvSet
(
result
,
cvScalarAll
(
1.
)
);
result
=
Scalar
::
all
(
1
);
return
;
}
templ
_sum2
=
templ_n
orm
+
CV_SQR
(
templ
_mean
.
val
[
0
])
+
CV_SQR
(
templ_mean
.
val
[
1
])
+
CV_SQR
(
templ
_mean
.
val
[
2
])
+
CV_SQR
(
templ_mean
.
val
[
3
]);
templ
Sum2
=
templN
orm
+
CV_SQR
(
templ
Mean
[
0
])
+
CV_SQR
(
templMean
[
1
])
+
CV_SQR
(
templ
Mean
[
2
])
+
CV_SQR
(
templMean
[
3
]);
if
(
num
_t
ype
!=
1
)
if
(
num
T
ype
!=
1
)
{
templ
_mean
=
cvScalarA
ll
(
0
);
templ
_norm
=
templ_s
um2
;
templ
Mean
=
Scalar
::
a
ll
(
0
);
templ
Norm
=
templS
um2
;
}
templ
_sum2
/=
inv_a
rea
;
templ
_norm
=
sqrt
(
templ_n
orm
);
templ
_norm
/=
sqrt
(
inv_a
rea
);
// care of accuracy here
q0
=
(
double
*
)
sqsum
->
data
.
ptr
;
q1
=
q0
+
templ
->
cols
*
cn
;
q2
=
(
double
*
)(
sqsum
->
data
.
ptr
+
templ
->
rows
*
sqsum
->
step
);
q3
=
q2
+
templ
->
cols
*
cn
;
templ
Sum2
/=
invA
rea
;
templ
Norm
=
sqrt
(
templN
orm
);
templ
Norm
/=
sqrt
(
invA
rea
);
// care of accuracy here
q0
=
(
double
*
)
sqsum
.
data
;
q1
=
q0
+
templ
.
cols
*
cn
;
q2
=
(
double
*
)(
sqsum
.
data
+
templ
.
rows
*
sqsum
.
step
);
q3
=
q2
+
templ
.
cols
*
cn
;
}
p0
=
(
double
*
)
sum
->
data
.
ptr
;
p1
=
p0
+
templ
->
cols
*
cn
;
p2
=
(
double
*
)(
sum
->
data
.
ptr
+
templ
->
rows
*
sum
->
step
);
p3
=
p2
+
templ
->
cols
*
cn
;
double
*
p0
=
(
double
*
)
sum
.
data
;
double
*
p1
=
p0
+
templ
.
cols
*
cn
;
double
*
p2
=
(
double
*
)(
sum
.
data
+
templ
.
rows
*
sum
.
step
);
double
*
p3
=
p2
+
templ
.
cols
*
cn
;
sum_step
=
sum
?
sum
->
step
/
sizeof
(
double
)
:
0
;
sqsum_step
=
sqsum
?
sqsum
->
step
/
sizeof
(
double
)
:
0
;
int
sumstep
=
sum
.
data
?
sum
.
step
/
sizeof
(
double
)
:
0
;
int
sqstep
=
sqsum
.
data
?
sqsum
.
step
/
sizeof
(
double
)
:
0
;
for
(
i
=
0
;
i
<
result
->
rows
;
i
++
)
int
i
,
j
,
k
;
for
(
i
=
0
;
i
<
result
.
rows
;
i
++
)
{
float
*
rrow
=
(
float
*
)(
result
->
data
.
ptr
+
i
*
result
->
step
);
i
dx
=
i
*
sum_
step
;
i
dx2
=
i
*
sqsum_
step
;
float
*
rrow
=
(
float
*
)(
result
.
data
+
i
*
result
.
step
);
i
nt
idx
=
i
*
sum
step
;
i
nt
idx2
=
i
*
sq
step
;
for
(
j
=
0
;
j
<
result
->
cols
;
j
++
,
idx
+=
cn
,
idx2
+=
cn
)
for
(
j
=
0
;
j
<
result
.
cols
;
j
++
,
idx
+=
cn
,
idx2
+=
cn
)
{
double
num
=
rrow
[
j
],
t
;
double
wnd
_mean2
=
0
,
wnd_s
um2
=
0
;
double
wnd
Mean2
=
0
,
wndS
um2
=
0
;
if
(
num
_t
ype
==
1
)
if
(
num
T
ype
==
1
)
{
for
(
k
=
0
;
k
<
cn
;
k
++
)
{
t
=
p0
[
idx
+
k
]
-
p1
[
idx
+
k
]
-
p2
[
idx
+
k
]
+
p3
[
idx
+
k
];
wnd
_m
ean2
+=
CV_SQR
(
t
);
num
-=
t
*
templ
_mean
.
val
[
k
];
wnd
M
ean2
+=
CV_SQR
(
t
);
num
-=
t
*
templ
Mean
[
k
];
}
wnd
_mean2
*=
inv_a
rea
;
wnd
Mean2
*=
invA
rea
;
}
if
(
is
_normed
||
num_t
ype
==
2
)
if
(
is
Normed
||
numT
ype
==
2
)
{
for
(
k
=
0
;
k
<
cn
;
k
++
)
{
t
=
q0
[
idx2
+
k
]
-
q1
[
idx2
+
k
]
-
q2
[
idx2
+
k
]
+
q3
[
idx2
+
k
];
wnd
_s
um2
+=
t
;
wnd
S
um2
+=
t
;
}
if
(
num
_t
ype
==
2
)
num
=
wnd
_sum2
-
2
*
num
+
templ_s
um2
;
if
(
num
T
ype
==
2
)
num
=
wnd
Sum2
-
2
*
num
+
templS
um2
;
}
if
(
is
_n
ormed
)
if
(
is
N
ormed
)
{
t
=
sqrt
(
MAX
(
wnd
_sum2
-
wnd_mean2
,
0
))
*
templ_n
orm
;
t
=
sqrt
(
MAX
(
wnd
Sum2
-
wndMean2
,
0
))
*
templN
orm
;
if
(
fabs
(
num
)
<
t
)
num
/=
t
;
else
if
(
fabs
(
num
)
<
t
*
1.125
)
...
...
@@ -477,12 +368,18 @@ cvMatchTemplate( const CvArr* _img, const CvArr* _templ, CvArr* _result, int met
}
}
void
cv
::
matchTemplate
(
const
Mat
&
image
,
const
Mat
&
templ
,
Mat
&
result
,
int
method
)
}
CV_IMPL
void
cvMatchTemplate
(
const
CvArr
*
_img
,
const
CvArr
*
_templ
,
CvArr
*
_result
,
int
method
)
{
result
.
create
(
std
::
abs
(
image
.
rows
-
templ
.
rows
)
+
1
,
std
::
abs
(
image
.
cols
-
templ
.
cols
)
+
1
,
CV_32F
);
CvMat
_image
=
image
,
_templ
=
templ
,
_result
=
result
;
cvMatchTemplate
(
&
_image
,
&
_templ
,
&
_result
,
method
);
cv
::
Mat
img
=
cv
::
cvarrToMat
(
_img
),
templ
=
cv
::
cvarrToMat
(
_templ
),
result
=
cv
::
cvarrToMat
(
_result
);
CV_Assert
(
result
.
size
()
==
cv
::
Size
(
std
::
abs
(
img
.
cols
-
templ
.
cols
)
+
1
,
std
::
abs
(
img
.
rows
-
templ
.
rows
)
+
1
)
&&
result
.
type
()
==
CV_32F
);
matchTemplate
(
img
,
templ
,
result
,
method
);
}
/* End of file. */
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