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
27cddfb8
Commit
27cddfb8
authored
Jan 25, 2018
by
Alexander Alekhin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #10661 from alalek:parallel_kmeans
parents
3f116468
90aac764
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
256 additions
and
195 deletions
+256
-195
perf_math.cpp
modules/core/perf/perf_math.cpp
+100
-25
kmeans.cpp
modules/core/src/kmeans.cpp
+156
-170
No files found.
modules/core/perf/perf_math.cpp
View file @
27cddfb8
...
@@ -3,13 +3,10 @@
...
@@ -3,13 +3,10 @@
using
namespace
std
;
using
namespace
std
;
using
namespace
cv
;
using
namespace
cv
;
using
namespace
perf
;
using
namespace
perf
;
using
std
::
tr1
::
make_tuple
;
using
std
::
tr1
::
get
;
typedef
perf
::
TestBaseWithParam
<
size_t
>
VectorLength
;
namespace
{
typedef
std
::
tr1
::
tuple
<
int
,
int
>
MaxDim_MaxPoints_t
;
typedef
perf
::
TestBaseWithParam
<
size_t
>
VectorLength
;
typedef
perf
::
TestBaseWithParam
<
MaxDim_MaxPoints_t
>
MaxDim_MaxPoints
;
PERF_TEST_P
(
VectorLength
,
phase32f
,
testing
::
Values
(
128
,
1000
,
128
*
1024
,
512
*
1024
,
1024
*
1024
))
PERF_TEST_P
(
VectorLength
,
phase32f
,
testing
::
Values
(
128
,
1000
,
128
*
1024
,
512
*
1024
,
1024
*
1024
))
{
{
...
@@ -39,47 +36,125 @@ PERF_TEST_P(VectorLength, phase64f, testing::Values(128, 1000, 128*1024, 512*102
...
@@ -39,47 +36,125 @@ PERF_TEST_P(VectorLength, phase64f, testing::Values(128, 1000, 128*1024, 512*102
SANITY_CHECK
(
angle
,
5e-5
);
SANITY_CHECK
(
angle
,
5e-5
);
}
}
PERF_TEST_P
(
MaxDim_MaxPoints
,
kmeans
,
typedef
perf
::
TestBaseWithParam
<
testing
::
tuple
<
int
,
int
,
int
>
>
KMeans
;
testing
::
Combine
(
testing
::
Values
(
16
,
32
,
64
),
testing
::
Values
(
300
,
400
,
500
)
)
)
PERF_TEST_P_
(
KMeans
,
single_iter
)
{
{
RNG
&
rng
=
theRNG
();
RNG
&
rng
=
theRNG
();
const
int
MAX_DIM
=
get
<
0
>
(
GetParam
());
const
int
K
=
testing
::
get
<
0
>
(
GetParam
());
const
int
MAX_POINTS
=
get
<
1
>
(
GetParam
());
const
int
dims
=
testing
::
get
<
1
>
(
GetParam
());
const
int
N
=
testing
::
get
<
2
>
(
GetParam
());
const
int
attempts
=
5
;
const
int
attempts
=
5
;
Mat
labels
,
centers
;
Mat
data
(
N
,
dims
,
CV_32F
);
int
i
,
N
=
0
,
N0
=
0
,
K
=
0
,
dims
=
0
;
rng
.
fill
(
data
,
RNG
::
UNIFORM
,
-
0.1
,
0.1
);
dims
=
rng
.
uniform
(
1
,
MAX_DIM
+
1
);
N
=
rng
.
uniform
(
1
,
MAX_POINTS
+
1
);
N0
=
rng
.
uniform
(
1
,
MAX
(
N
/
10
,
2
));
K
=
rng
.
uniform
(
1
,
N
+
1
);
const
int
N0
=
K
;
Mat
data0
(
N0
,
dims
,
CV_32F
);
Mat
data0
(
N0
,
dims
,
CV_32F
);
rng
.
fill
(
data0
,
RNG
::
UNIFORM
,
-
1
,
1
);
rng
.
fill
(
data0
,
RNG
::
UNIFORM
,
-
1
,
1
);
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
int
base
=
rng
.
uniform
(
0
,
N0
);
cv
::
add
(
data0
.
row
(
base
),
data
.
row
(
i
),
data
.
row
(
i
));
}
declare
.
in
(
data
);
Mat
labels
,
centers
;
TEST_CYCLE
()
{
kmeans
(
data
,
K
,
labels
,
TermCriteria
(
TermCriteria
::
MAX_ITER
+
TermCriteria
::
EPS
,
1
,
0
),
attempts
,
KMEANS_PP_CENTERS
,
centers
);
}
SANITY_CHECK_NOTHING
();
}
PERF_TEST_P_
(
KMeans
,
good
)
{
RNG
&
rng
=
theRNG
();
const
int
K
=
testing
::
get
<
0
>
(
GetParam
());
const
int
dims
=
testing
::
get
<
1
>
(
GetParam
());
const
int
N
=
testing
::
get
<
2
>
(
GetParam
());
const
int
attempts
=
5
;
Mat
data
(
N
,
dims
,
CV_32F
);
Mat
data
(
N
,
dims
,
CV_32F
);
for
(
i
=
0
;
i
<
N
;
i
++
)
rng
.
fill
(
data
,
RNG
::
UNIFORM
,
-
0.1
,
0.1
);
data0
.
row
(
rng
.
uniform
(
0
,
N0
)).
copyTo
(
data
.
row
(
i
));
const
int
N0
=
K
;
Mat
data0
(
N0
,
dims
,
CV_32F
);
rng
.
fill
(
data0
,
RNG
::
UNIFORM
,
-
1
,
1
);
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
int
base
=
rng
.
uniform
(
0
,
N0
);
cv
::
add
(
data0
.
row
(
base
),
data
.
row
(
i
),
data
.
row
(
i
));
}
declare
.
in
(
data
);
declare
.
in
(
data
);
Mat
labels
,
centers
;
TEST_CYCLE
()
TEST_CYCLE
()
{
{
kmeans
(
data
,
K
,
labels
,
TermCriteria
(
TermCriteria
::
MAX_ITER
+
TermCriteria
::
EPS
,
30
,
0
),
kmeans
(
data
,
K
,
labels
,
TermCriteria
(
TermCriteria
::
MAX_ITER
+
TermCriteria
::
EPS
,
30
,
0
),
attempts
,
KMEANS_PP_CENTERS
,
centers
);
attempts
,
KMEANS_PP_CENTERS
,
centers
);
}
}
Mat
clusterPointsNumber
=
Mat
::
zeros
(
1
,
K
,
CV_32S
);
SANITY_CHECK_NOTHING
();
}
PERF_TEST_P_
(
KMeans
,
with_duplicates
)
{
RNG
&
rng
=
theRNG
();
const
int
K
=
testing
::
get
<
0
>
(
GetParam
());
const
int
dims
=
testing
::
get
<
1
>
(
GetParam
());
const
int
N
=
testing
::
get
<
2
>
(
GetParam
());
const
int
attempts
=
5
;
Mat
data
(
N
,
dims
,
CV_32F
,
Scalar
::
all
(
0
));
const
int
N0
=
std
::
max
(
2
,
K
*
2
/
3
);
Mat
data0
(
N0
,
dims
,
CV_32F
);
rng
.
fill
(
data0
,
RNG
::
UNIFORM
,
-
1
,
1
);
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
int
base
=
rng
.
uniform
(
0
,
N0
);
data0
.
row
(
base
).
copyTo
(
data
.
row
(
i
));
}
declare
.
in
(
data
);
for
(
i
=
0
;
i
<
labels
.
rows
;
i
++
)
Mat
labels
,
centers
;
TEST_CYCLE
()
{
{
int
clusterIdx
=
labels
.
at
<
int
>
(
i
);
kmeans
(
data
,
K
,
labels
,
TermCriteria
(
TermCriteria
::
MAX_ITER
+
TermCriteria
::
EPS
,
30
,
0
),
clusterPointsNumber
.
at
<
int
>
(
clusterIdx
)
++
;
attempts
,
KMEANS_PP_CENTERS
,
centers
)
;
}
}
Mat
sortedClusterPointsNumber
;
SANITY_CHECK_NOTHING
();
cv
::
sort
(
clusterPointsNumber
,
sortedClusterPointsNumber
,
cv
::
SORT_EVERY_ROW
+
cv
::
SORT_ASCENDING
);
}
INSTANTIATE_TEST_CASE_P
(
/*nothing*/
,
KMeans
,
testing
::
Values
(
// K clusters, dims, N points
testing
::
make_tuple
(
2
,
3
,
100000
),
testing
::
make_tuple
(
4
,
3
,
500
),
testing
::
make_tuple
(
4
,
3
,
1000
),
testing
::
make_tuple
(
4
,
3
,
10000
),
testing
::
make_tuple
(
8
,
3
,
1000
),
testing
::
make_tuple
(
8
,
16
,
1000
),
testing
::
make_tuple
(
8
,
64
,
1000
),
testing
::
make_tuple
(
16
,
16
,
1000
),
testing
::
make_tuple
(
16
,
32
,
1000
),
testing
::
make_tuple
(
32
,
16
,
1000
),
testing
::
make_tuple
(
32
,
32
,
1000
),
testing
::
make_tuple
(
100
,
2
,
1000
)
)
);
SANITY_CHECK
(
sortedClusterPointsNumber
);
}
}
modules/core/src/kmeans.cpp
View file @
27cddfb8
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
// License Agreement
// License Agreement
// For Open Source Computer Vision Library
// For Open Source Computer Vision Library
//
//
// Copyright (C) 2000-20
0
8, Intel Corporation, all rights reserved.
// Copyright (C) 2000-20
1
8, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
// Third party copyrights are property of their respective owners.
...
@@ -42,105 +42,100 @@
...
@@ -42,105 +42,100 @@
//M*/
//M*/
#include "precomp.hpp"
#include "precomp.hpp"
#include <opencv2/core/utils/configuration.private.hpp>
////////////////////////////////////////// kmeans ////////////////////////////////////////////
////////////////////////////////////////// kmeans ////////////////////////////////////////////
namespace
cv
namespace
cv
{
{
static
void
generateRandomCenter
(
const
std
::
vector
<
Vec2f
>&
box
,
float
*
center
,
RNG
&
rng
)
static
int
CV_KMEANS_PARALLEL_GRANULARITY
=
(
int
)
utils
::
getConfigurationParameterSizeT
(
"OPENCV_KMEANS_PARALLEL_GRANULARITY"
,
1000
);
static
void
generateRandomCenter
(
int
dims
,
const
Vec2f
*
box
,
float
*
center
,
RNG
&
rng
)
{
{
size_t
j
,
dims
=
box
.
size
();
float
margin
=
1.
f
/
dims
;
float
margin
=
1.
f
/
dims
;
for
(
j
=
0
;
j
<
dims
;
j
++
)
for
(
int
j
=
0
;
j
<
dims
;
j
++
)
center
[
j
]
=
((
float
)
rng
*
(
1.
f
+
margin
*
2.
f
)
-
margin
)
*
(
box
[
j
][
1
]
-
box
[
j
][
0
])
+
box
[
j
][
0
];
center
[
j
]
=
((
float
)
rng
*
(
1.
f
+
margin
*
2.
f
)
-
margin
)
*
(
box
[
j
][
1
]
-
box
[
j
][
0
])
+
box
[
j
][
0
];
}
}
class
KMeansPPDistanceComputer
:
public
ParallelLoopBody
class
KMeansPPDistanceComputer
:
public
ParallelLoopBody
{
{
public
:
public
:
KMeansPPDistanceComputer
(
float
*
_tdist2
,
KMeansPPDistanceComputer
(
float
*
tdist2_
,
const
Mat
&
data_
,
const
float
*
dist_
,
int
ci_
)
:
const
float
*
_data
,
tdist2
(
tdist2_
),
data
(
data_
),
dist
(
dist_
),
ci
(
ci_
)
const
float
*
_dist
,
{
}
int
_dims
,
size_t
_step
,
size_t
_stepci
)
:
tdist2
(
_tdist2
),
data
(
_data
),
dist
(
_dist
),
dims
(
_dims
),
step
(
_step
),
stepci
(
_stepci
)
{
}
void
operator
()(
const
cv
::
Range
&
range
)
const
void
operator
()(
const
cv
::
Range
&
range
)
const
{
{
CV_TRACE_FUNCTION
();
CV_TRACE_FUNCTION
();
const
int
begin
=
range
.
start
;
const
int
begin
=
range
.
start
;
const
int
end
=
range
.
end
;
const
int
end
=
range
.
end
;
const
int
dims
=
data
.
cols
;
for
(
int
i
=
begin
;
i
<
end
;
i
++
)
for
(
int
i
=
begin
;
i
<
end
;
i
++
)
{
{
tdist2
[
i
]
=
std
::
min
(
normL2Sqr
(
data
+
step
*
i
,
data
+
stepci
,
dims
),
dist
[
i
]);
tdist2
[
i
]
=
std
::
min
(
normL2Sqr
(
data
.
ptr
<
float
>
(
i
),
data
.
ptr
<
float
>
(
ci
)
,
dims
),
dist
[
i
]);
}
}
}
}
private
:
private
:
KMeansPPDistanceComputer
&
operator
=
(
const
KMeansPPDistanceComputer
&
);
//
to quiet MSVC
KMeansPPDistanceComputer
&
operator
=
(
const
KMeansPPDistanceComputer
&
);
//
= delete
float
*
tdist2
;
float
*
tdist2
;
const
float
*
data
;
const
Mat
&
data
;
const
float
*
dist
;
const
float
*
dist
;
const
int
dims
;
const
int
ci
;
const
size_t
step
;
const
size_t
stepci
;
};
};
/*
/*
k-means center initialization using the following algorithm:
k-means center initialization using the following algorithm:
Arthur & Vassilvitskii (2007) k-means++: The Advantages of Careful Seeding
Arthur & Vassilvitskii (2007) k-means++: The Advantages of Careful Seeding
*/
*/
static
void
generateCentersPP
(
const
Mat
&
_
data
,
Mat
&
_out_centers
,
static
void
generateCentersPP
(
const
Mat
&
data
,
Mat
&
_out_centers
,
int
K
,
RNG
&
rng
,
int
trials
)
int
K
,
RNG
&
rng
,
int
trials
)
{
{
CV_TRACE_FUNCTION
();
CV_TRACE_FUNCTION
();
int
i
,
j
,
k
,
dims
=
_data
.
cols
,
N
=
_data
.
rows
;
const
int
dims
=
data
.
cols
,
N
=
data
.
rows
;
const
float
*
data
=
_data
.
ptr
<
float
>
(
0
);
cv
::
AutoBuffer
<
int
,
64
>
_centers
(
K
);
size_t
step
=
_data
.
step
/
sizeof
(
data
[
0
]);
std
::
vector
<
int
>
_centers
(
K
);
int
*
centers
=
&
_centers
[
0
];
int
*
centers
=
&
_centers
[
0
];
std
::
vector
<
float
>
_dist
(
N
*
3
);
cv
::
AutoBuffer
<
float
,
0
>
_dist
(
N
*
3
);
float
*
dist
=
&
_dist
[
0
],
*
tdist
=
dist
+
N
,
*
tdist2
=
tdist
+
N
;
float
*
dist
=
&
_dist
[
0
],
*
tdist
=
dist
+
N
,
*
tdist2
=
tdist
+
N
;
double
sum0
=
0
;
double
sum0
=
0
;
centers
[
0
]
=
(
unsigned
)
rng
%
N
;
centers
[
0
]
=
(
unsigned
)
rng
%
N
;
for
(
i
=
0
;
i
<
N
;
i
++
)
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
{
dist
[
i
]
=
normL2Sqr
(
data
+
step
*
i
,
data
+
step
*
centers
[
0
]
,
dims
);
dist
[
i
]
=
normL2Sqr
(
data
.
ptr
<
float
>
(
i
),
data
.
ptr
<
float
>
(
centers
[
0
])
,
dims
);
sum0
+=
dist
[
i
];
sum0
+=
dist
[
i
];
}
}
for
(
k
=
1
;
k
<
K
;
k
++
)
for
(
int
k
=
1
;
k
<
K
;
k
++
)
{
{
double
bestSum
=
DBL_MAX
;
double
bestSum
=
DBL_MAX
;
int
bestCenter
=
-
1
;
int
bestCenter
=
-
1
;
for
(
j
=
0
;
j
<
trials
;
j
++
)
for
(
int
j
=
0
;
j
<
trials
;
j
++
)
{
{
double
p
=
(
double
)
rng
*
sum0
,
s
=
0
;
double
p
=
(
double
)
rng
*
sum0
;
for
(
i
=
0
;
i
<
N
-
1
;
i
++
)
int
ci
=
0
;
if
(
(
p
-=
dist
[
i
])
<=
0
)
for
(;
ci
<
N
-
1
;
ci
++
)
{
p
-=
dist
[
ci
];
if
(
p
<=
0
)
break
;
break
;
int
ci
=
i
;
}
parallel_for_
(
Range
(
0
,
N
),
parallel_for_
(
Range
(
0
,
N
),
KMeansPPDistanceComputer
(
tdist2
,
data
,
dist
,
dims
,
step
,
step
*
ci
));
KMeansPPDistanceComputer
(
tdist2
,
data
,
dist
,
ci
),
for
(
i
=
0
;
i
<
N
;
i
++
)
divUp
(
dims
*
N
,
CV_KMEANS_PARALLEL_GRANULARITY
));
double
s
=
0
;
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
{
s
+=
tdist2
[
i
];
s
+=
tdist2
[
i
];
}
}
if
(
s
<
bestSum
)
if
(
s
<
bestSum
)
{
{
bestSum
=
s
;
bestSum
=
s
;
bestCenter
=
ci
;
bestCenter
=
ci
;
...
@@ -152,39 +147,39 @@ static void generateCentersPP(const Mat& _data, Mat& _out_centers,
...
@@ -152,39 +147,39 @@ static void generateCentersPP(const Mat& _data, Mat& _out_centers,
std
::
swap
(
dist
,
tdist
);
std
::
swap
(
dist
,
tdist
);
}
}
for
(
k
=
0
;
k
<
K
;
k
++
)
for
(
int
k
=
0
;
k
<
K
;
k
++
)
{
{
const
float
*
src
=
data
+
step
*
centers
[
k
]
;
const
float
*
src
=
data
.
ptr
<
float
>
(
centers
[
k
])
;
float
*
dst
=
_out_centers
.
ptr
<
float
>
(
k
);
float
*
dst
=
_out_centers
.
ptr
<
float
>
(
k
);
for
(
j
=
0
;
j
<
dims
;
j
++
)
for
(
int
j
=
0
;
j
<
dims
;
j
++
)
dst
[
j
]
=
src
[
j
];
dst
[
j
]
=
src
[
j
];
}
}
}
}
template
<
bool
onlyDistance
>
class
KMeansDistanceComputer
:
public
ParallelLoopBody
class
KMeansDistanceComputer
:
public
ParallelLoopBody
{
{
public
:
public
:
KMeansDistanceComputer
(
double
*
_distances
,
KMeansDistanceComputer
(
double
*
distances_
,
int
*
_labels
,
int
*
labels_
,
const
Mat
&
_data
,
const
Mat
&
data_
,
const
Mat
&
_centers
,
const
Mat
&
centers_
)
bool
_onlyDistance
=
false
)
:
distances
(
distances_
),
:
distances
(
_distances
),
labels
(
labels_
),
labels
(
_labels
),
data
(
data_
),
data
(
_data
),
centers
(
centers_
)
centers
(
_centers
),
onlyDistance
(
_onlyDistance
)
{
{
}
}
void
operator
()(
const
Range
&
range
)
const
void
operator
()(
const
Range
&
range
)
const
{
{
CV_TRACE_FUNCTION
();
const
int
begin
=
range
.
start
;
const
int
begin
=
range
.
start
;
const
int
end
=
range
.
end
;
const
int
end
=
range
.
end
;
const
int
K
=
centers
.
rows
;
const
int
K
=
centers
.
rows
;
const
int
dims
=
centers
.
cols
;
const
int
dims
=
centers
.
cols
;
for
(
int
i
=
begin
;
i
<
end
;
++
i
)
for
(
int
i
=
begin
;
i
<
end
;
++
i
)
{
{
const
float
*
sample
=
data
.
ptr
<
float
>
(
i
);
const
float
*
sample
=
data
.
ptr
<
float
>
(
i
);
if
(
onlyDistance
)
if
(
onlyDistance
)
...
@@ -193,34 +188,36 @@ public:
...
@@ -193,34 +188,36 @@ public:
distances
[
i
]
=
normL2Sqr
(
sample
,
center
,
dims
);
distances
[
i
]
=
normL2Sqr
(
sample
,
center
,
dims
);
continue
;
continue
;
}
}
int
k_best
=
0
;
else
double
min_dist
=
DBL_MAX
;
for
(
int
k
=
0
;
k
<
K
;
k
++
)
{
{
const
float
*
center
=
centers
.
ptr
<
float
>
(
k
)
;
int
k_best
=
0
;
const
double
dist
=
normL2Sqr
(
sample
,
center
,
dims
)
;
double
min_dist
=
DBL_MAX
;
if
(
min_dist
>
dist
)
for
(
int
k
=
0
;
k
<
K
;
k
++
)
{
{
min_dist
=
dist
;
const
float
*
center
=
centers
.
ptr
<
float
>
(
k
);
k_best
=
k
;
const
double
dist
=
normL2Sqr
(
sample
,
center
,
dims
);
if
(
min_dist
>
dist
)
{
min_dist
=
dist
;
k_best
=
k
;
}
}
}
}
distances
[
i
]
=
min_dist
;
distances
[
i
]
=
min_dist
;
labels
[
i
]
=
k_best
;
labels
[
i
]
=
k_best
;
}
}
}
}
}
private
:
private
:
KMeansDistanceComputer
&
operator
=
(
const
KMeansDistanceComputer
&
);
//
to quiet MSVC
KMeansDistanceComputer
&
operator
=
(
const
KMeansDistanceComputer
&
);
//
= delete
double
*
distances
;
double
*
distances
;
int
*
labels
;
int
*
labels
;
const
Mat
&
data
;
const
Mat
&
data
;
const
Mat
&
centers
;
const
Mat
&
centers
;
bool
onlyDistance
;
};
};
}
}
...
@@ -231,13 +228,12 @@ double cv::kmeans( InputArray _data, int K,
...
@@ -231,13 +228,12 @@ double cv::kmeans( InputArray _data, int K,
int
flags
,
OutputArray
_centers
)
int
flags
,
OutputArray
_centers
)
{
{
CV_INSTRUMENT_REGION
()
CV_INSTRUMENT_REGION
()
const
int
SPP_TRIALS
=
3
;
const
int
SPP_TRIALS
=
3
;
Mat
data0
=
_data
.
getMat
();
Mat
data0
=
_data
.
getMat
();
bool
isrow
=
data0
.
rows
==
1
;
const
bool
isrow
=
data0
.
rows
==
1
;
int
N
=
isrow
?
data0
.
cols
:
data0
.
rows
;
const
int
N
=
isrow
?
data0
.
cols
:
data0
.
rows
;
int
dims
=
(
isrow
?
1
:
data0
.
cols
)
*
data0
.
channels
();
const
int
dims
=
(
isrow
?
1
:
data0
.
cols
)
*
data0
.
channels
();
int
type
=
data0
.
depth
();
const
int
type
=
data0
.
depth
();
attempts
=
std
::
max
(
attempts
,
1
);
attempts
=
std
::
max
(
attempts
,
1
);
CV_Assert
(
data0
.
dims
<=
2
&&
type
==
CV_32F
&&
K
>
0
);
CV_Assert
(
data0
.
dims
<=
2
&&
type
==
CV_32F
&&
K
>
0
);
...
@@ -248,129 +244,115 @@ double cv::kmeans( InputArray _data, int K,
...
@@ -248,129 +244,115 @@ double cv::kmeans( InputArray _data, int K,
_bestLabels
.
create
(
N
,
1
,
CV_32S
,
-
1
,
true
);
_bestLabels
.
create
(
N
,
1
,
CV_32S
,
-
1
,
true
);
Mat
_labels
,
best_labels
=
_bestLabels
.
getMat
();
Mat
_labels
,
best_labels
=
_bestLabels
.
getMat
();
if
(
flags
&
CV_KMEANS_USE_INITIAL_LABELS
)
if
(
flags
&
CV_KMEANS_USE_INITIAL_LABELS
)
{
{
CV_Assert
(
(
best_labels
.
cols
==
1
||
best_labels
.
rows
==
1
)
&&
CV_Assert
(
(
best_labels
.
cols
==
1
||
best_labels
.
rows
==
1
)
&&
best_labels
.
cols
*
best_labels
.
rows
==
N
&&
best_labels
.
cols
*
best_labels
.
rows
==
N
&&
best_labels
.
type
()
==
CV_32S
&&
best_labels
.
type
()
==
CV_32S
&&
best_labels
.
isContinuous
());
best_labels
.
isContinuous
());
best_labels
.
copyTo
(
_labels
);
best_labels
.
reshape
(
1
,
N
).
copyTo
(
_labels
);
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
CV_Assert
((
unsigned
)
_labels
.
at
<
int
>
(
i
)
<
(
unsigned
)
K
);
}
}
}
else
else
{
{
if
(
!
((
best_labels
.
cols
==
1
||
best_labels
.
rows
==
1
)
&&
if
(
!
((
best_labels
.
cols
==
1
||
best_labels
.
rows
==
1
)
&&
best_labels
.
cols
*
best_labels
.
rows
==
N
&&
best_labels
.
cols
*
best_labels
.
rows
==
N
&&
best_labels
.
type
()
==
CV_32S
&&
best_labels
.
type
()
==
CV_32S
&&
best_labels
.
isContinuous
()))
best_labels
.
isContinuous
()))
best_labels
.
create
(
N
,
1
,
CV_32S
);
{
_bestLabels
.
create
(
N
,
1
,
CV_32S
);
best_labels
=
_bestLabels
.
getMat
();
}
_labels
.
create
(
best_labels
.
size
(),
best_labels
.
type
());
_labels
.
create
(
best_labels
.
size
(),
best_labels
.
type
());
}
}
int
*
labels
=
_labels
.
ptr
<
int
>
();
int
*
labels
=
_labels
.
ptr
<
int
>
();
Mat
centers
(
K
,
dims
,
type
),
old_centers
(
K
,
dims
,
type
),
temp
(
1
,
dims
,
type
);
Mat
centers
(
K
,
dims
,
type
),
old_centers
(
K
,
dims
,
type
),
temp
(
1
,
dims
,
type
);
std
::
vector
<
int
>
counters
(
K
);
cv
::
AutoBuffer
<
int
,
64
>
counters
(
K
);
std
::
vector
<
Vec2f
>
_box
(
dims
);
cv
::
AutoBuffer
<
double
,
64
>
dists
(
N
);
Mat
dists
(
1
,
N
,
CV_64F
);
Vec2f
*
box
=
&
_box
[
0
];
double
best_compactness
=
DBL_MAX
,
compactness
=
0
;
RNG
&
rng
=
theRNG
();
RNG
&
rng
=
theRNG
();
int
a
,
iter
,
i
,
j
,
k
;
if
(
criteria
.
type
&
TermCriteria
::
EPS
)
if
(
criteria
.
type
&
TermCriteria
::
EPS
)
criteria
.
epsilon
=
std
::
max
(
criteria
.
epsilon
,
0.
);
criteria
.
epsilon
=
std
::
max
(
criteria
.
epsilon
,
0.
);
else
else
criteria
.
epsilon
=
FLT_EPSILON
;
criteria
.
epsilon
=
FLT_EPSILON
;
criteria
.
epsilon
*=
criteria
.
epsilon
;
criteria
.
epsilon
*=
criteria
.
epsilon
;
if
(
criteria
.
type
&
TermCriteria
::
COUNT
)
if
(
criteria
.
type
&
TermCriteria
::
COUNT
)
criteria
.
maxCount
=
std
::
min
(
std
::
max
(
criteria
.
maxCount
,
2
),
100
);
criteria
.
maxCount
=
std
::
min
(
std
::
max
(
criteria
.
maxCount
,
2
),
100
);
else
else
criteria
.
maxCount
=
100
;
criteria
.
maxCount
=
100
;
if
(
K
==
1
)
if
(
K
==
1
)
{
{
attempts
=
1
;
attempts
=
1
;
criteria
.
maxCount
=
2
;
criteria
.
maxCount
=
2
;
}
}
const
float
*
sample
=
data
.
ptr
<
float
>
(
0
);
cv
::
AutoBuffer
<
Vec2f
,
64
>
box
(
dims
);
for
(
j
=
0
;
j
<
dims
;
j
++
)
if
(
!
(
flags
&
KMEANS_PP_CENTERS
))
box
[
j
]
=
Vec2f
(
sample
[
j
],
sample
[
j
]);
for
(
i
=
1
;
i
<
N
;
i
++
)
{
{
sample
=
data
.
ptr
<
float
>
(
i
);
for
(
j
=
0
;
j
<
dims
;
j
++
)
{
{
float
v
=
sample
[
j
];
const
float
*
sample
=
data
.
ptr
<
float
>
(
0
);
box
[
j
][
0
]
=
std
::
min
(
box
[
j
][
0
],
v
);
for
(
int
j
=
0
;
j
<
dims
;
j
++
)
box
[
j
][
1
]
=
std
::
max
(
box
[
j
][
1
],
v
);
box
[
j
]
=
Vec2f
(
sample
[
j
],
sample
[
j
]);
}
for
(
int
i
=
1
;
i
<
N
;
i
++
)
{
const
float
*
sample
=
data
.
ptr
<
float
>
(
i
);
for
(
int
j
=
0
;
j
<
dims
;
j
++
)
{
float
v
=
sample
[
j
];
box
[
j
][
0
]
=
std
::
min
(
box
[
j
][
0
],
v
);
box
[
j
][
1
]
=
std
::
max
(
box
[
j
][
1
],
v
);
}
}
}
}
}
for
(
a
=
0
;
a
<
attempts
;
a
++
)
double
best_compactness
=
DBL_MAX
;
for
(
int
a
=
0
;
a
<
attempts
;
a
++
)
{
{
double
max_center_shift
=
DBL_MAX
;
double
compactness
=
0
;
for
(
iter
=
0
;;
)
for
(
int
iter
=
0
;
;)
{
{
double
max_center_shift
=
iter
==
0
?
DBL_MAX
:
0.0
;
swap
(
centers
,
old_centers
);
swap
(
centers
,
old_centers
);
if
(
iter
==
0
&&
(
a
>
0
||
!
(
flags
&
KMEANS_USE_INITIAL_LABELS
))
)
if
(
iter
==
0
&&
(
a
>
0
||
!
(
flags
&
KMEANS_USE_INITIAL_LABELS
))
)
{
{
if
(
flags
&
KMEANS_PP_CENTERS
)
if
(
flags
&
KMEANS_PP_CENTERS
)
generateCentersPP
(
data
,
centers
,
K
,
rng
,
SPP_TRIALS
);
generateCentersPP
(
data
,
centers
,
K
,
rng
,
SPP_TRIALS
);
else
else
{
{
for
(
k
=
0
;
k
<
K
;
k
++
)
for
(
int
k
=
0
;
k
<
K
;
k
++
)
generateRandomCenter
(
_
box
,
centers
.
ptr
<
float
>
(
k
),
rng
);
generateRandomCenter
(
dims
,
box
,
centers
.
ptr
<
float
>
(
k
),
rng
);
}
}
}
}
else
else
{
{
if
(
iter
==
0
&&
a
==
0
&&
(
flags
&
KMEANS_USE_INITIAL_LABELS
)
)
{
for
(
i
=
0
;
i
<
N
;
i
++
)
CV_Assert
(
(
unsigned
)
labels
[
i
]
<
(
unsigned
)
K
);
}
// compute centers
// compute centers
centers
=
Scalar
(
0
);
centers
=
Scalar
(
0
);
for
(
k
=
0
;
k
<
K
;
k
++
)
for
(
int
k
=
0
;
k
<
K
;
k
++
)
counters
[
k
]
=
0
;
counters
[
k
]
=
0
;
for
(
i
=
0
;
i
<
N
;
i
++
)
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
{
sample
=
data
.
ptr
<
float
>
(
i
);
const
float
*
sample
=
data
.
ptr
<
float
>
(
i
);
k
=
labels
[
i
];
int
k
=
labels
[
i
];
float
*
center
=
centers
.
ptr
<
float
>
(
k
);
float
*
center
=
centers
.
ptr
<
float
>
(
k
);
j
=
0
;
for
(
int
j
=
0
;
j
<
dims
;
j
++
)
#if CV_ENABLE_UNROLLED
for
(;
j
<=
dims
-
4
;
j
+=
4
)
{
float
t0
=
center
[
j
]
+
sample
[
j
];
float
t1
=
center
[
j
+
1
]
+
sample
[
j
+
1
];
center
[
j
]
=
t0
;
center
[
j
+
1
]
=
t1
;
t0
=
center
[
j
+
2
]
+
sample
[
j
+
2
];
t1
=
center
[
j
+
3
]
+
sample
[
j
+
3
];
center
[
j
+
2
]
=
t0
;
center
[
j
+
3
]
=
t1
;
}
#endif
for
(
;
j
<
dims
;
j
++
)
center
[
j
]
+=
sample
[
j
];
center
[
j
]
+=
sample
[
j
];
counters
[
k
]
++
;
counters
[
k
]
++
;
}
}
if
(
iter
>
0
)
for
(
int
k
=
0
;
k
<
K
;
k
++
)
max_center_shift
=
0
;
for
(
k
=
0
;
k
<
K
;
k
++
)
{
{
if
(
counters
[
k
]
!=
0
)
if
(
counters
[
k
]
!=
0
)
continue
;
continue
;
// if some cluster appeared to be empty then:
// if some cluster appeared to be empty then:
...
@@ -378,29 +360,28 @@ double cv::kmeans( InputArray _data, int K,
...
@@ -378,29 +360,28 @@ double cv::kmeans( InputArray _data, int K,
// 2. find the farthest from the center point in the biggest cluster
// 2. find the farthest from the center point in the biggest cluster
// 3. exclude the farthest point from the biggest cluster and form a new 1-point cluster.
// 3. exclude the farthest point from the biggest cluster and form a new 1-point cluster.
int
max_k
=
0
;
int
max_k
=
0
;
for
(
int
k1
=
1
;
k1
<
K
;
k1
++
)
for
(
int
k1
=
1
;
k1
<
K
;
k1
++
)
{
{
if
(
counters
[
max_k
]
<
counters
[
k1
]
)
if
(
counters
[
max_k
]
<
counters
[
k1
]
)
max_k
=
k1
;
max_k
=
k1
;
}
}
double
max_dist
=
0
;
double
max_dist
=
0
;
int
farthest_i
=
-
1
;
int
farthest_i
=
-
1
;
float
*
new_center
=
centers
.
ptr
<
float
>
(
k
);
float
*
base_center
=
centers
.
ptr
<
float
>
(
max_k
);
float
*
old_center
=
centers
.
ptr
<
float
>
(
max_k
);
float
*
_base_center
=
temp
.
ptr
<
float
>
();
// normalized
float
*
_old_center
=
temp
.
ptr
<
float
>
();
// normalized
float
scale
=
1.
f
/
counters
[
max_k
];
float
scale
=
1.
f
/
counters
[
max_k
];
for
(
j
=
0
;
j
<
dims
;
j
++
)
for
(
int
j
=
0
;
j
<
dims
;
j
++
)
_
old_center
[
j
]
=
old
_center
[
j
]
*
scale
;
_
base_center
[
j
]
=
base
_center
[
j
]
*
scale
;
for
(
i
=
0
;
i
<
N
;
i
++
)
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
{
if
(
labels
[
i
]
!=
max_k
)
if
(
labels
[
i
]
!=
max_k
)
continue
;
continue
;
sample
=
data
.
ptr
<
float
>
(
i
);
const
float
*
sample
=
data
.
ptr
<
float
>
(
i
);
double
dist
=
normL2Sqr
(
sample
,
_
old
_center
,
dims
);
double
dist
=
normL2Sqr
(
sample
,
_
base
_center
,
dims
);
if
(
max_dist
<=
dist
)
if
(
max_dist
<=
dist
)
{
{
max_dist
=
dist
;
max_dist
=
dist
;
farthest_i
=
i
;
farthest_i
=
i
;
...
@@ -410,29 +391,30 @@ double cv::kmeans( InputArray _data, int K,
...
@@ -410,29 +391,30 @@ double cv::kmeans( InputArray _data, int K,
counters
[
max_k
]
--
;
counters
[
max_k
]
--
;
counters
[
k
]
++
;
counters
[
k
]
++
;
labels
[
farthest_i
]
=
k
;
labels
[
farthest_i
]
=
k
;
sample
=
data
.
ptr
<
float
>
(
farthest_i
);
for
(
j
=
0
;
j
<
dims
;
j
++
)
const
float
*
sample
=
data
.
ptr
<
float
>
(
farthest_i
);
float
*
cur_center
=
centers
.
ptr
<
float
>
(
k
);
for
(
int
j
=
0
;
j
<
dims
;
j
++
)
{
{
old
_center
[
j
]
-=
sample
[
j
];
base
_center
[
j
]
-=
sample
[
j
];
new
_center
[
j
]
+=
sample
[
j
];
cur
_center
[
j
]
+=
sample
[
j
];
}
}
}
}
for
(
k
=
0
;
k
<
K
;
k
++
)
for
(
int
k
=
0
;
k
<
K
;
k
++
)
{
{
float
*
center
=
centers
.
ptr
<
float
>
(
k
);
float
*
center
=
centers
.
ptr
<
float
>
(
k
);
CV_Assert
(
counters
[
k
]
!=
0
);
CV_Assert
(
counters
[
k
]
!=
0
);
float
scale
=
1.
f
/
counters
[
k
];
float
scale
=
1.
f
/
counters
[
k
];
for
(
j
=
0
;
j
<
dims
;
j
++
)
for
(
int
j
=
0
;
j
<
dims
;
j
++
)
center
[
j
]
*=
scale
;
center
[
j
]
*=
scale
;
if
(
iter
>
0
)
if
(
iter
>
0
)
{
{
double
dist
=
0
;
double
dist
=
0
;
const
float
*
old_center
=
old_centers
.
ptr
<
float
>
(
k
);
const
float
*
old_center
=
old_centers
.
ptr
<
float
>
(
k
);
for
(
j
=
0
;
j
<
dims
;
j
++
)
for
(
int
j
=
0
;
j
<
dims
;
j
++
)
{
{
double
t
=
center
[
j
]
-
old_center
[
j
];
double
t
=
center
[
j
]
-
old_center
[
j
];
dist
+=
t
*
t
;
dist
+=
t
*
t
;
...
@@ -444,25 +426,29 @@ double cv::kmeans( InputArray _data, int K,
...
@@ -444,25 +426,29 @@ double cv::kmeans( InputArray _data, int K,
bool
isLastIter
=
(
++
iter
==
MAX
(
criteria
.
maxCount
,
2
)
||
max_center_shift
<=
criteria
.
epsilon
);
bool
isLastIter
=
(
++
iter
==
MAX
(
criteria
.
maxCount
,
2
)
||
max_center_shift
<=
criteria
.
epsilon
);
// assign labels
dists
=
0
;
double
*
dist
=
dists
.
ptr
<
double
>
(
0
);
parallel_for_
(
Range
(
0
,
N
),
KMeansDistanceComputer
(
dist
,
labels
,
data
,
centers
,
isLastIter
));
compactness
=
sum
(
dists
)[
0
];
if
(
isLastIter
)
if
(
isLastIter
)
{
// don't re-assign labels to avoid creation of empty clusters
parallel_for_
(
Range
(
0
,
N
),
KMeansDistanceComputer
<
true
>
(
dists
,
labels
,
data
,
centers
),
divUp
(
dims
*
N
,
CV_KMEANS_PARALLEL_GRANULARITY
));
compactness
=
sum
(
Mat
(
Size
(
N
,
1
),
CV_64F
,
&
dists
[
0
]))[
0
];
break
;
break
;
}
else
{
// assign labels
parallel_for_
(
Range
(
0
,
N
),
KMeansDistanceComputer
<
false
>
(
dists
,
labels
,
data
,
centers
),
divUp
(
dims
*
N
*
K
,
CV_KMEANS_PARALLEL_GRANULARITY
));
}
}
}
if
(
compactness
<
best_compactness
)
if
(
compactness
<
best_compactness
)
{
{
best_compactness
=
compactness
;
best_compactness
=
compactness
;
if
(
_centers
.
needed
()
)
if
(
_centers
.
needed
()
)
{
{
Mat
reshaped
=
centers
;
if
(
_centers
.
fixedType
()
&&
_centers
.
channels
()
==
dims
)
if
(
_centers
.
fixedType
()
&&
_centers
.
channels
()
==
dims
)
centers
.
reshape
(
dims
).
copyTo
(
_centers
);
reshaped
=
centers
.
reshape
(
dims
);
else
reshaped
.
copyTo
(
_centers
);
centers
.
copyTo
(
_centers
);
}
}
_labels
.
copyTo
(
best_labels
);
_labels
.
copyTo
(
best_labels
);
}
}
...
...
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