Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv_contrib
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_contrib
Commits
fb0cb3d3
Commit
fb0cb3d3
authored
Nov 25, 2016
by
StevenPuttemans
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added multiple thinning algorithms
added thinning sample added thinning tests
parent
5deedac2
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
160 additions
and
27 deletions
+160
-27
ximgproc.hpp
modules/ximgproc/include/opencv2/ximgproc.hpp
+7
-1
thinning.cpp
modules/ximgproc/samples/thinning.cpp
+44
-0
thinning.cpp
modules/ximgproc/src/thinning.cpp
+55
-26
test_thinning.cpp
modules/ximgproc/test/test_thinning.cpp
+54
-0
No files found.
modules/ximgproc/include/opencv2/ximgproc.hpp
View file @
fb0cb3d3
...
...
@@ -71,6 +71,11 @@ namespace cv
namespace
ximgproc
{
enum
ThinningTypes
{
THINNING_ZHANGSUEN
=
0
,
// Thinning technique of Zhang-Suen
THINNING_GUOHALL
=
1
// Thinning technique of Guo-Hall
};
//! @addtogroup ximgproc
//! @{
...
...
@@ -110,8 +115,9 @@ The function transforms a binary blob image into a skeletized form using the tec
@param src Source 8-bit single-channel image, containing binary blobs, with blobs having 255 pixel values.
@param dst Destination image of the same size and the same type as src. The function can work in-place.
@param thinningType Value that defines which thinning algorithm should be used. See cv::ThinningTypes
*/
CV_EXPORTS_W
void
thinning
(
InputArray
src
,
OutputArray
dst
);
CV_EXPORTS_W
void
thinning
(
InputArray
src
,
OutputArray
dst
,
int
thinningType
=
THINNING_ZHANGSUEN
);
//! @}
...
...
modules/ximgproc/samples/thinning.cpp
0 → 100644
View file @
fb0cb3d3
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/ximgproc.hpp"
using
namespace
std
;
using
namespace
cv
;
int
main
()
{
Mat
img
=
imread
(
"opencv-logo.png"
,
IMREAD_COLOR
);
/// Threshold the input image
Mat
img_grayscale
,
img_binary
;
cvtColor
(
img
,
img_grayscale
,
COLOR_BGR2GRAY
);
threshold
(
img_grayscale
,
img_binary
,
0
,
255
,
THRESH_OTSU
|
THRESH_BINARY_INV
);
/// Apply thinning to get a skeleton
Mat
img_thinning_ZS
,
img_thinning_GH
;
//ximgproc::thinning(img_binary, img_thinning_ZS, THINNING_ZHANGSUEN);
//ximgproc::thinning(img_binary, img_thinning_GH, THINNING_GUOHALL);
/// Make 3 channel images from thinning result
Mat
result_ZS
(
img
.
rows
,
img
.
cols
,
CV_8UC3
),
result_GH
(
img
.
rows
,
img
.
cols
,
CV_8UC3
);
Mat
in
[]
=
{
img_thinning_ZS
,
img_thinning_ZS
,
img_thinning_ZS
};
Mat
in2
[]
=
{
img_thinning_GH
,
img_thinning_GH
,
img_thinning_GH
};
int
from_to
[]
=
{
0
,
0
,
1
,
1
,
2
,
2
};
mixChannels
(
in
,
3
,
&
result_ZS
,
1
,
from_to
,
3
);
mixChannels
(
in2
,
3
,
&
result_GH
,
1
,
from_to
,
3
);
/// Combine everything into a canvas
Mat
canvas
(
img
.
rows
,
img
.
cols
*
3
,
CV_8UC3
);
img
.
copyTo
(
canvas
(
Rect
(
0
,
0
,
img
.
cols
,
img
.
rows
)
)
);
result_ZS
.
copyTo
(
canvas
(
Rect
(
img
.
cols
,
0
,
img
.
cols
,
img
.
rows
)
)
);
result_GH
.
copyTo
(
canvas
(
Rect
(
img
.
cols
*
2
,
0
,
img
.
cols
,
img
.
rows
)
)
);
/// Visualize result
imshow
(
"Skeleton"
,
canvas
);
waitKey
(
0
);
return
0
;
}
modules/ximgproc/src/thinning.cpp
View file @
fb0cb3d3
...
...
@@ -6,31 +6,60 @@ namespace cv {
namespace
ximgproc
{
// Applies a thinning iteration to a binary image
static
void
thinningIteration
(
Mat
img
,
int
iter
){
static
void
thinningIteration
(
Mat
img
,
int
iter
,
int
thinningType
){
Mat
marker
=
Mat
::
zeros
(
img
.
size
(),
CV_8UC1
);
for
(
int
i
=
1
;
i
<
img
.
rows
-
1
;
i
++
)
{
for
(
int
j
=
1
;
j
<
img
.
cols
-
1
;
j
++
)
if
(
thinningType
==
THINNING_ZHANGSUEN
){
for
(
int
i
=
1
;
i
<
img
.
rows
-
1
;
i
++
)
{
for
(
int
j
=
1
;
j
<
img
.
cols
-
1
;
j
++
)
{
uchar
p2
=
img
.
at
<
uchar
>
(
i
-
1
,
j
);
uchar
p3
=
img
.
at
<
uchar
>
(
i
-
1
,
j
+
1
);
uchar
p4
=
img
.
at
<
uchar
>
(
i
,
j
+
1
);
uchar
p5
=
img
.
at
<
uchar
>
(
i
+
1
,
j
+
1
);
uchar
p6
=
img
.
at
<
uchar
>
(
i
+
1
,
j
);
uchar
p7
=
img
.
at
<
uchar
>
(
i
+
1
,
j
-
1
);
uchar
p8
=
img
.
at
<
uchar
>
(
i
,
j
-
1
);
uchar
p9
=
img
.
at
<
uchar
>
(
i
-
1
,
j
-
1
);
int
A
=
(
p2
==
0
&&
p3
==
1
)
+
(
p3
==
0
&&
p4
==
1
)
+
(
p4
==
0
&&
p5
==
1
)
+
(
p5
==
0
&&
p6
==
1
)
+
(
p6
==
0
&&
p7
==
1
)
+
(
p7
==
0
&&
p8
==
1
)
+
(
p8
==
0
&&
p9
==
1
)
+
(
p9
==
0
&&
p2
==
1
);
int
B
=
p2
+
p3
+
p4
+
p5
+
p6
+
p7
+
p8
+
p9
;
int
m1
=
iter
==
0
?
(
p2
*
p4
*
p6
)
:
(
p2
*
p4
*
p8
);
int
m2
=
iter
==
0
?
(
p4
*
p6
*
p8
)
:
(
p2
*
p6
*
p8
);
if
(
A
==
1
&&
(
B
>=
2
&&
B
<=
6
)
&&
m1
==
0
&&
m2
==
0
)
marker
.
at
<
uchar
>
(
i
,
j
)
=
1
;
}
}
}
if
(
thinningType
==
THINNING_GUOHALL
){
for
(
int
i
=
1
;
i
<
img
.
rows
-
1
;
i
++
)
{
uchar
p2
=
img
.
at
<
uchar
>
(
i
-
1
,
j
);
uchar
p3
=
img
.
at
<
uchar
>
(
i
-
1
,
j
+
1
);
uchar
p4
=
img
.
at
<
uchar
>
(
i
,
j
+
1
);
uchar
p5
=
img
.
at
<
uchar
>
(
i
+
1
,
j
+
1
);
uchar
p6
=
img
.
at
<
uchar
>
(
i
+
1
,
j
);
uchar
p7
=
img
.
at
<
uchar
>
(
i
+
1
,
j
-
1
);
uchar
p8
=
img
.
at
<
uchar
>
(
i
,
j
-
1
);
uchar
p9
=
img
.
at
<
uchar
>
(
i
-
1
,
j
-
1
);
int
A
=
(
p2
==
0
&&
p3
==
1
)
+
(
p3
==
0
&&
p4
==
1
)
+
(
p4
==
0
&&
p5
==
1
)
+
(
p5
==
0
&&
p6
==
1
)
+
(
p6
==
0
&&
p7
==
1
)
+
(
p7
==
0
&&
p8
==
1
)
+
(
p8
==
0
&&
p9
==
1
)
+
(
p9
==
0
&&
p2
==
1
);
int
B
=
p2
+
p3
+
p4
+
p5
+
p6
+
p7
+
p8
+
p9
;
int
m1
=
iter
==
0
?
(
p2
*
p4
*
p6
)
:
(
p2
*
p4
*
p8
);
int
m2
=
iter
==
0
?
(
p4
*
p6
*
p8
)
:
(
p2
*
p6
*
p8
);
if
(
A
==
1
&&
(
B
>=
2
&&
B
<=
6
)
&&
m1
==
0
&&
m2
==
0
)
marker
.
at
<
uchar
>
(
i
,
j
)
=
1
;
for
(
int
j
=
1
;
j
<
img
.
cols
-
1
;
j
++
)
{
uchar
p2
=
img
.
at
<
uchar
>
(
i
-
1
,
j
);
uchar
p3
=
img
.
at
<
uchar
>
(
i
-
1
,
j
+
1
);
uchar
p4
=
img
.
at
<
uchar
>
(
i
,
j
+
1
);
uchar
p5
=
img
.
at
<
uchar
>
(
i
+
1
,
j
+
1
);
uchar
p6
=
img
.
at
<
uchar
>
(
i
+
1
,
j
);
uchar
p7
=
img
.
at
<
uchar
>
(
i
+
1
,
j
-
1
);
uchar
p8
=
img
.
at
<
uchar
>
(
i
,
j
-
1
);
uchar
p9
=
img
.
at
<
uchar
>
(
i
-
1
,
j
-
1
);
int
C
=
((
!
p2
)
&
(
p3
|
p4
))
+
((
!
p4
)
&
(
p5
|
p6
))
+
((
!
p6
)
&
(
p7
|
p8
))
+
((
!
p8
)
&
(
p9
|
p2
));
int
N1
=
(
p9
|
p2
)
+
(
p3
|
p4
)
+
(
p5
|
p6
)
+
(
p7
|
p8
);
int
N2
=
(
p2
|
p3
)
+
(
p4
|
p5
)
+
(
p6
|
p7
)
+
(
p8
|
p9
);
int
N
=
N1
<
N2
?
N1
:
N2
;
int
m
=
iter
==
0
?
((
p6
|
p7
|
(
!
p9
))
&
p8
)
:
((
p2
|
p3
|
(
!
p5
))
&
p4
);
if
((
C
==
1
)
&&
((
N
>=
2
)
&&
((
N
<=
3
))
&
(
m
==
0
)))
marker
.
at
<
uchar
>
(
i
,
j
)
=
1
;
}
}
}
...
...
@@ -38,7 +67,7 @@ static void thinningIteration(Mat img, int iter){
}
// Apply the thinning procedure to a given image
void
thinning
(
InputArray
input
,
OutputArray
output
){
void
thinning
(
InputArray
input
,
OutputArray
output
,
int
thinningType
){
Mat
processed
=
input
.
getMat
().
clone
();
// Enforce the range of the input image to be in between 0 - 255
processed
/=
255
;
...
...
@@ -47,8 +76,8 @@ void thinning(InputArray input, OutputArray output){
Mat
diff
;
do
{
thinningIteration
(
processed
,
0
);
thinningIteration
(
processed
,
1
);
thinningIteration
(
processed
,
0
,
thinningType
);
thinningIteration
(
processed
,
1
,
thinningType
);
absdiff
(
processed
,
prev
,
diff
);
processed
.
copyTo
(
prev
);
}
...
...
modules/ximgproc/test/test_thinning.cpp
0 → 100644
View file @
fb0cb3d3
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
using
namespace
cv
;
using
namespace
cv
::
ximgproc
;
namespace
{
static
int
createTestImage
(
Mat
&
src
)
{
src
=
Mat
::
zeros
(
Size
(
256
,
256
),
CV_8UC1
);
for
(
int
x
=
50
;
x
<
src
.
cols
-
50
;
x
+=
50
)
{
cv
::
circle
(
src
,
Point
(
x
,
x
/
2
),
30
+
x
/
2
,
Scalar
(
255
),
5
);
}
int
src_pixels
=
countNonZero
(
src
);
EXPECT_GT
(
src_pixels
,
0
);
return
src_pixels
;
}
TEST
(
ximpgroc_Thinning
,
simple_ZHANGSUEN
)
{
Mat
src
;
int
src_pixels
=
createTestImage
(
src
);
Mat
dst
;
thinning
(
src
,
dst
,
THINNING_ZHANGSUEN
);
int
dst_pixels
=
countNonZero
(
dst
);
EXPECT_LE
(
dst_pixels
,
src_pixels
);
#if 0
imshow("src", src); imshow("dst", dst); waitKey();
#endif
}
TEST
(
ximpgroc_Thinning
,
simple_GUOHALL
)
{
Mat
src
;
int
src_pixels
=
createTestImage
(
src
);
Mat
dst
;
thinning
(
src
,
dst
,
THINNING_GUOHALL
);
int
dst_pixels
=
countNonZero
(
dst
);
EXPECT_LE
(
dst_pixels
,
src_pixels
);
#if 0
imshow("src", src); imshow("dst", dst); waitKey();
#endif
}
}
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