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
fde8a6ab
Commit
fde8a6ab
authored
Nov 30, 2016
by
Alexander Alekhin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #874 from StevenPuttemans:master
parents
6f793bde
fb0cb3d3
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 @
fde8a6ab
...
...
@@ -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 @
fde8a6ab
#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 @
fde8a6ab
...
...
@@ -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 @
fde8a6ab
// 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