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
57648c2c
Commit
57648c2c
authored
Dec 02, 2016
by
Alexander Alekhin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #876 from alalek:fix_contrib_872
parents
bd619c55
31d11378
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
61 additions
and
86 deletions
+61
-86
detect_er_chars.py
modules/text/samples/detect_er_chars.py
+5
-6
textdetection.cpp
modules/text/samples/textdetection.cpp
+2
-3
textdetection.py
modules/text/samples/textdetection.py
+4
-6
erfilter.cpp
modules/text/src/erfilter.cpp
+50
-71
No files found.
modules/text/samples/detect_er_chars.py
View file @
57648c2c
...
...
@@ -5,7 +5,6 @@ import os
import
cv2
import
numpy
as
np
from
matplotlib
import
pyplot
as
plt
print
(
'
\n
detect_er_chars.py'
)
print
(
' A simple demo script using the Extremal Region Filter algorithm described in:'
)
...
...
@@ -32,8 +31,8 @@ regions = cv2.text.detectRegions(gray,er1,er2)
#Visualization
rects
=
[
cv2
.
boundingRect
(
p
.
reshape
(
-
1
,
1
,
2
))
for
p
in
regions
]
for
rect
in
rects
:
cv2
.
rectangle
(
img
,
rect
[
0
:
2
],
(
rect
[
0
]
+
rect
[
2
],
rect
[
1
]
+
rect
[
3
]),
(
0
,
0
,
255
),
2
)
img
=
img
[:,:,::
-
1
]
#flip the colors dimension from BGR to RGB
plt
.
imshow
(
img
)
plt
.
xticks
([]),
plt
.
yticks
([])
# to hide tick values on X and Y axis
plt
.
show
(
)
cv2
.
rectangle
(
img
,
rect
[
0
:
2
],
(
rect
[
0
]
+
rect
[
2
],
rect
[
1
]
+
rect
[
3
]),
(
0
,
0
,
0
),
2
)
for
rect
in
rects
:
cv2
.
rectangle
(
img
,
rect
[
0
:
2
],
(
rect
[
0
]
+
rect
[
2
],
rect
[
1
]
+
rect
[
3
]),
(
255
,
255
,
255
),
1
)
cv2
.
imshow
(
"Text detection result"
,
img
)
cv2
.
waitKey
(
0
)
modules/text/samples/textdetection.cpp
View file @
57648c2c
...
...
@@ -32,7 +32,6 @@ int main(int argc, const char * argv[])
if
(
argc
<
2
)
show_help_and_exit
(
argv
[
0
]);
namedWindow
(
"grouping"
,
WINDOW_NORMAL
);
Mat
src
=
imread
(
argv
[
1
]);
// Extract channels to be processed individually
...
...
@@ -70,8 +69,8 @@ int main(int argc, const char * argv[])
imshow
(
"grouping"
,
src
);
cout
<<
"Done!"
<<
endl
<<
endl
;
cout
<<
"Press 'e' to show the extracted Extremal Regions, any other key to exit."
<<
endl
<<
endl
;
if
(
waitKey
(
-
1
)
==
101
)
cout
<<
"Press '
spac
e' to show the extracted Extremal Regions, any other key to exit."
<<
endl
<<
endl
;
if
((
waitKey
()
&
0xff
)
==
' '
)
er_show
(
channels
,
regions
);
// memory clean-up
...
...
modules/text/samples/textdetection.py
View file @
57648c2c
...
...
@@ -5,7 +5,6 @@ import os
import
cv2
import
numpy
as
np
from
matplotlib
import
pyplot
as
plt
print
(
'
\n
textdetection.py'
)
print
(
' A demo script of the Extremal Region Filter algorithm described in:'
)
...
...
@@ -50,11 +49,10 @@ for channel in channels:
#Visualization
for
r
in
range
(
0
,
np
.
shape
(
rects
)[
0
]):
rect
=
rects
[
r
]
cv2
.
rectangle
(
vis
,
(
rect
[
0
],
rect
[
1
]),
(
rect
[
0
]
+
rect
[
2
],
rect
[
1
]
+
rect
[
3
]),
(
0
,
255
,
255
),
2
)
cv2
.
rectangle
(
vis
,
(
rect
[
0
],
rect
[
1
]),
(
rect
[
0
]
+
rect
[
2
],
rect
[
1
]
+
rect
[
3
]),
(
0
,
0
,
0
),
2
)
cv2
.
rectangle
(
vis
,
(
rect
[
0
],
rect
[
1
]),
(
rect
[
0
]
+
rect
[
2
],
rect
[
1
]
+
rect
[
3
]),
(
255
,
255
,
255
),
1
)
#Visualization
vis
=
vis
[:,:,::
-
1
]
#flip the colors dimension from BGR to RGB
plt
.
imshow
(
vis
)
plt
.
xticks
([]),
plt
.
yticks
([])
# to hide tick values on X and Y axis
plt
.
show
()
cv2
.
imshow
(
"Text detection result"
,
vis
)
cv2
.
waitKey
(
0
)
modules/text/src/erfilter.cpp
View file @
57648c2c
...
...
@@ -275,24 +275,18 @@ void ERFilterNM::er_tree_extract( InputArray image )
// the component stack
vector
<
ERStat
*>
er_stack
;
//the quads for euler number calculation
unsigned
char
quads
[
3
][
4
];
quads
[
0
][
0
]
=
1
<<
3
;
quads
[
0
][
1
]
=
1
<<
2
;
quads
[
0
][
2
]
=
1
<<
1
;
quads
[
0
][
3
]
=
1
;
quads
[
1
][
0
]
=
(
1
<<
2
)
|
(
1
<<
1
)
|
(
1
);
quads
[
1
][
1
]
=
(
1
<<
3
)
|
(
1
<<
1
)
|
(
1
);
quads
[
1
][
2
]
=
(
1
<<
3
)
|
(
1
<<
2
)
|
(
1
);
quads
[
1
][
3
]
=
(
1
<<
3
)
|
(
1
<<
2
)
|
(
1
<<
1
);
quads
[
2
][
0
]
=
(
1
<<
2
)
|
(
1
<<
1
);
quads
[
2
][
1
]
=
(
1
<<
3
)
|
(
1
);
// quads[2][2] and quads[2][3] are never used so no need to initialize them.
// the quads for euler number calculation
// quads[2][2] and quads[2][3] are never used.
// The four lowest bits in each quads[i][j] correspond to the 2x2 binary patterns
// Q_1, Q_2, Q_3 in the Neumann and Matas CVPR 2012 paper
// (see in page 4 at the end of first column).
// Q_1 and Q_2 have four patterns, while Q_3 has only two.
const
int
quads
[
3
][
4
]
=
{
{
1
<<
3
,
1
<<
2
,
1
<<
1
,
1
<<
0
},
{
(
1
<<
2
)
|
(
1
<<
1
)
|
(
1
),
(
1
<<
3
)
|
(
1
<<
1
)
|
(
1
),
(
1
<<
3
)
|
(
1
<<
2
)
|
(
1
),
(
1
<<
3
)
|
(
1
<<
2
)
|
(
1
<<
1
)
},
{
(
1
<<
2
)
|
(
1
<<
1
)
,
(
1
<<
3
)
|
(
1
),
/*unused*/
-
1
,
/*unused*/
-
1
}
};
// masks to know if a pixel is accessible and if it has been already added to some region
vector
<
bool
>
accessible_pixel_mask
(
width
*
height
);
...
...
@@ -392,8 +386,8 @@ void ERFilterNM::er_tree_extract( InputArray image )
int
non_boundary_neighbours
=
0
;
int
non_boundary_neighbours_horiz
=
0
;
unsigned
char
quad_before
[
4
]
=
{
0
,
0
,
0
,
0
};
unsigned
char
quad_after
[
4
]
=
{
0
,
0
,
0
,
0
};
int
quad_before
[
4
]
=
{
0
,
0
,
0
,
0
};
int
quad_after
[
4
]
=
{
0
,
0
,
0
,
0
};
quad_after
[
0
]
=
1
<<
1
;
quad_after
[
1
]
=
1
<<
3
;
quad_after
[
2
]
=
1
<<
2
;
...
...
@@ -542,9 +536,9 @@ void ERFilterNM::er_tree_extract( InputArray image )
current_edge
=
boundary_edges
[
threshold_level
].
back
();
boundary_edges
[
threshold_level
].
erase
(
boundary_edges
[
threshold_level
].
end
()
-
1
);
while
(
boundary_pixes
[
threshold_level
].
empty
()
&&
(
threshold_level
<
(
255
/
thresholdDelta
)
+
1
)
)
threshold_level
++
;
for
(;
threshold_level
<
(
255
/
thresholdDelta
)
+
1
;
threshold_level
++
)
if
(
!
boundary_pixes
[
threshold_level
].
empty
())
break
;
int
new_level
=
image_data
[
current_pixel
];
...
...
@@ -784,28 +778,27 @@ ERStat* ERFilterNM::er_save( ERStat *er, ERStat *parent, ERStat *prev )
// recursively walk the tree and filter (remove) regions using the callback classifier
ERStat
*
ERFilterNM
::
er_tree_filter
(
InputArray
image
,
ERStat
*
stat
,
ERStat
*
parent
,
ERStat
*
prev
)
{
Mat
src
=
image
.
getMat
();
// assert correct image type
CV_Assert
(
src
.
type
()
==
CV_8UC1
);
CV_Assert
(
image
.
type
()
==
CV_8UC1
);
Mat
src
=
image
.
getMat
();
//Fill the region and calculate 2nd stage features
Mat
region
=
region_mask
(
Rect
(
Point
(
stat
->
rect
.
x
,
stat
->
rect
.
y
),
Point
(
stat
->
rect
.
br
().
x
+
2
,
stat
->
rect
.
br
().
y
+
2
)));
Mat
region
=
region_mask
(
Rect
(
stat
->
rect
.
tl
(),
stat
->
rect
.
br
()
+
Point
(
2
,
2
)));
region
=
Scalar
(
0
);
int
newMaskVal
=
255
;
int
flags
=
4
+
(
newMaskVal
<<
8
)
+
FLOODFILL_FIXED_RANGE
+
FLOODFILL_MASK_ONLY
;
Rect
rect
;
floodFill
(
src
(
Rect
(
Point
(
stat
->
rect
.
x
,
stat
->
rect
.
y
),
Point
(
stat
->
rect
.
br
().
x
,
stat
->
rect
.
br
().
y
))
),
region
,
Point
(
stat
->
pixel
%
src
.
cols
-
stat
->
rect
.
x
,
stat
->
pixel
/
src
.
cols
-
stat
->
rect
.
y
),
floodFill
(
src
(
stat
->
rect
),
region
,
Point
(
stat
->
pixel
%
src
.
cols
,
stat
->
pixel
/
src
.
cols
)
-
stat
->
rect
.
tl
(
),
Scalar
(
255
),
&
rect
,
Scalar
(
stat
->
level
),
Scalar
(
0
),
flags
);
rect
.
width
+=
2
;
rect
.
height
+=
2
;
region
=
region
(
rect
);
region
=
region
(
Rect
(
1
,
1
,
rect
.
width
,
rect
.
height
));
vector
<
vector
<
Point
>
>
contours
;
vector
<
Point
>
contour_poly
;
vector
<
Vec4i
>
hierarchy
;
findContours
(
region
(
Rect
(
1
,
1
,
region
.
cols
-
2
,
region
.
rows
-
2
)),
contours
,
hierarchy
,
RETR_TREE
,
CHAIN_APPROX_NONE
,
Point
(
1
,
1
)
);
findContours
(
region
,
contours
,
hierarchy
,
RETR_TREE
,
CHAIN_APPROX_NONE
,
Point
(
0
,
0
)
);
//TODO check epsilon parameter of approxPolyDP (set empirically) : we want more precission
// if the region is very small because otherwise we'll loose all the convexities
approxPolyDP
(
Mat
(
contours
[
0
]),
contour_poly
,
(
float
)
min
(
rect
.
width
,
rect
.
height
)
/
17
,
true
);
...
...
@@ -2859,9 +2852,7 @@ bool guo_hall_thinning(const Mat1b & img, Mat& skeleton)
}
float
extract_features
(
Mat
&
grey
,
Mat
&
channel
,
vector
<
ERStat
>
&
regions
,
vector
<
ERFeatures
>
&
features
);
float
extract_features
(
Mat
&
grey
,
Mat
&
channel
,
vector
<
ERStat
>
&
regions
,
vector
<
ERFeatures
>
&
features
)
static
float
extract_features
(
Mat
&
grey
,
Mat
&
channel
,
vector
<
ERStat
>
&
regions
,
vector
<
ERFeatures
>
&
features
)
{
// assert correct image type
CV_Assert
((
channel
.
type
()
==
CV_8UC1
)
&&
(
grey
.
type
()
==
CV_8UC1
));
...
...
@@ -2890,18 +2881,15 @@ float extract_features(Mat &grey, Mat& channel, vector<ERStat> ®ions, vector<
{
//Fill the region and calculate features
Mat
region
=
region_mask
(
Rect
(
Point
(
stat
->
rect
.
x
,
stat
->
rect
.
y
),
Point
(
stat
->
rect
.
br
().
x
+
2
,
stat
->
rect
.
br
().
y
+
2
)));
Mat
region
=
region_mask
(
Rect
(
stat
->
rect
.
tl
(
),
stat
->
rect
.
br
()
+
Point
(
2
,
2
)));
region
=
Scalar
(
0
);
int
newMaskVal
=
255
;
int
flags
=
4
+
(
newMaskVal
<<
8
)
+
FLOODFILL_FIXED_RANGE
+
FLOODFILL_MASK_ONLY
;
Rect
rect
;
floodFill
(
channel
(
Rect
(
Point
(
stat
->
rect
.
x
,
stat
->
rect
.
y
),
Point
(
stat
->
rect
.
br
().
x
,
stat
->
rect
.
br
().
y
))
),
floodFill
(
channel
(
stat
->
rect
),
region
,
Point
(
stat
->
pixel
%
channel
.
cols
-
stat
->
rect
.
x
,
stat
->
pixel
/
channel
.
cols
-
stat
->
rect
.
y
),
Scalar
(
255
),
&
rect
,
Scalar
(
stat
->
level
),
Scalar
(
0
),
flags
);
rect
.
width
+=
2
;
rect
.
height
+=
2
;
Scalar
(
255
),
NULL
,
Scalar
(
stat
->
level
),
Scalar
(
0
),
flags
);
Mat
rect_mask
=
region_mask
(
Rect
(
stat
->
rect
.
x
+
1
,
stat
->
rect
.
y
+
1
,
stat
->
rect
.
width
,
stat
->
rect
.
height
));
...
...
@@ -2911,7 +2899,7 @@ float extract_features(Mat &grey, Mat& channel, vector<ERStat> ®ions, vector<
f
.
intensity_std
=
(
float
)
std
[
0
];
Mat
tmp
,
bw
;
re
gion_mask
(
Rect
(
stat
->
rect
.
x
+
1
,
stat
->
rect
.
y
+
1
,
stat
->
rect
.
width
,
stat
->
rect
.
height
))
.
copyTo
(
bw
);
re
ct_mask
.
copyTo
(
bw
);
distanceTransform
(
bw
,
tmp
,
DIST_L1
,
3
);
//L1 gives distance in round integers while L2 floats
// Add border because if region span all the image size skeleton will crash
...
...
@@ -3513,19 +3501,16 @@ bool isValidPair(Mat &grey, Mat &lab, Mat &mask, vector<Mat> &channels, vector<
i
=
&
regions
[
idx1
[
0
]][
idx1
[
1
]];
j
=
&
regions
[
idx2
[
0
]][
idx2
[
1
]];
Mat
region
=
mask
(
Rect
(
Point
(
i
->
rect
.
x
,
i
->
rect
.
y
),
Point
(
i
->
rect
.
br
().
x
+
2
,
i
->
rect
.
br
().
y
+
2
)));
Mat
region
=
mask
(
Rect
(
i
->
rect
.
tl
(
),
i
->
rect
.
br
()
+
Point
(
2
,
2
)));
region
=
Scalar
(
0
);
int
newMaskVal
=
255
;
int
flags
=
4
+
(
newMaskVal
<<
8
)
+
FLOODFILL_FIXED_RANGE
+
FLOODFILL_MASK_ONLY
;
Rect
rect
;
floodFill
(
channels
[
idx1
[
0
]](
Rect
(
Point
(
i
->
rect
.
x
,
i
->
rect
.
y
),
Point
(
i
->
rect
.
br
().
x
,
i
->
rect
.
br
().
y
))),
region
,
Point
(
i
->
pixel
%
grey
.
cols
-
i
->
rect
.
x
,
i
->
pixel
/
grey
.
cols
-
i
->
rect
.
y
),
Scalar
(
255
),
&
rect
,
Scalar
(
i
->
level
),
Scalar
(
0
),
flags
);
rect
.
width
+=
2
;
rect
.
height
+=
2
;
floodFill
(
channels
[
idx1
[
0
]](
i
->
rect
),
region
,
Point
(
i
->
pixel
%
grey
.
cols
,
i
->
pixel
/
grey
.
cols
)
-
i
->
rect
.
tl
(),
Scalar
(
255
),
NULL
,
Scalar
(
i
->
level
),
Scalar
(
0
),
flags
);
Mat
rect_mask
=
mask
(
Rect
(
i
->
rect
.
x
+
1
,
i
->
rect
.
y
+
1
,
i
->
rect
.
width
,
i
->
rect
.
height
));
Scalar
mean
,
std
;
...
...
@@ -3535,15 +3520,12 @@ bool isValidPair(Mat &grey, Mat &lab, Mat &mask, vector<Mat> &channels, vector<
float
a_mean1
=
(
float
)
mean
[
1
];
float
b_mean1
=
(
float
)
mean
[
2
];
region
=
mask
(
Rect
(
Point
(
j
->
rect
.
x
,
j
->
rect
.
y
),
Point
(
j
->
rect
.
br
().
x
+
2
,
j
->
rect
.
br
().
y
+
2
)));
region
=
mask
(
Rect
(
j
->
rect
.
tl
(),
j
->
rect
.
br
()
+
Point
(
2
,
2
)));
region
=
Scalar
(
0
);
floodFill
(
channels
[
idx2
[
0
]](
Rect
(
Point
(
j
->
rect
.
x
,
j
->
rect
.
y
),
Point
(
j
->
rect
.
br
().
x
,
j
->
rect
.
br
().
y
))),
region
,
Point
(
j
->
pixel
%
grey
.
cols
-
j
->
rect
.
x
,
j
->
pixel
/
grey
.
cols
-
j
->
rect
.
y
),
Scalar
(
255
),
&
rect
,
Scalar
(
j
->
level
),
Scalar
(
0
),
flags
);
rect
.
width
+=
2
;
rect
.
height
+=
2
;
floodFill
(
channels
[
idx2
[
0
]](
j
->
rect
),
region
,
Point
(
j
->
pixel
%
grey
.
cols
,
j
->
pixel
/
grey
.
cols
)
-
j
->
rect
.
tl
(),
Scalar
(
255
),
NULL
,
Scalar
(
j
->
level
),
Scalar
(
0
),
flags
);
rect_mask
=
mask
(
Rect
(
j
->
rect
.
x
+
1
,
j
->
rect
.
y
+
1
,
j
->
rect
.
width
,
j
->
rect
.
height
));
meanStdDev
(
grey
(
j
->
rect
),
mean
,
std
,
rect_mask
);
...
...
@@ -4181,7 +4163,7 @@ void MSERsToERStats(InputArray image, vector<vector<Point> > &contours, vector<v
void
detectRegions
(
InputArray
image
,
const
Ptr
<
ERFilter
>&
er_filter1
,
const
Ptr
<
ERFilter
>&
er_filter2
,
CV_OUT
vector
<
vector
<
Point
>
>&
regions
)
{
// assert correct image type
CV_Assert
(
image
.
getMat
().
type
()
==
CV_8UC1
);
CV_Assert
(
image
.
type
()
==
CV_8UC1
);
// at least one ERFilter must be passed
CV_Assert
(
!
er_filter1
.
empty
()
);
...
...
@@ -4195,36 +4177,33 @@ void detectRegions(InputArray image, const Ptr<ERFilter>& er_filter1, const Ptr<
}
//Convert each ER to vector<Point> and push it to output regions
Mat
src
=
image
.
getMat
();
Mat
region_mask
=
Mat
::
zeros
(
src
.
rows
+
2
,
src
.
cols
+
2
,
CV_8UC1
);
const
Mat
src
=
image
.
getMat
();
for
(
size_t
i
=
1
;
i
<
ers
.
size
();
i
++
)
//start from 1 to deprecate root region
{
ERStat
*
stat
=
&
ers
[
i
];
//Fill the region and calculate 2nd stage features
Mat
region
=
region_mask
(
Rect
(
Point
(
stat
->
rect
.
x
,
stat
->
rect
.
y
),
Point
(
stat
->
rect
.
br
().
x
+
2
,
stat
->
rect
.
br
().
y
+
2
)));
region
=
Scalar
(
0
);
Mat
region_mask
(
Size
(
stat
->
rect
.
width
+
2
,
stat
->
rect
.
height
+
2
),
CV_8UC1
,
Scalar
(
0
));
Mat
region
=
region_mask
(
Rect
(
1
,
1
,
stat
->
rect
.
width
,
stat
->
rect
.
height
));
int
newMaskVal
=
255
;
int
flags
=
4
+
(
newMaskVal
<<
8
)
+
FLOODFILL_FIXED_RANGE
+
FLOODFILL_MASK_ONLY
;
Rect
rect
;
floodFill
(
src
(
Rect
(
Point
(
stat
->
rect
.
x
,
stat
->
rect
.
y
),
Point
(
stat
->
rect
.
br
().
x
,
stat
->
rect
.
br
().
y
))),
region
,
Point
(
stat
->
pixel
%
src
.
cols
-
stat
->
rect
.
x
,
stat
->
pixel
/
src
.
cols
-
stat
->
rect
.
y
),
Scalar
(
255
),
&
rect
,
Scalar
(
stat
->
level
),
Scalar
(
0
),
flags
);
rect
.
width
+=
2
;
rect
.
height
+=
2
;
region
=
region
(
rect
);
const
Point
seed_pt
(
stat
->
pixel
%
src
.
cols
,
stat
->
pixel
/
src
.
cols
);
uchar
seed_v
=
src
.
at
<
uchar
>
(
seed_pt
);
CV_Assert
((
int
)
seed_v
<=
stat
->
level
);
floodFill
(
src
(
stat
->
rect
),
region_mask
,
seed_pt
-
stat
->
rect
.
tl
(),
Scalar
(
255
),
NULL
,
Scalar
(
/*stat->level*/
255
),
Scalar
(
0
),
flags
);
vector
<
vector
<
Point
>
>
contours
;
vector
<
Vec4i
>
hierarchy
;
findContours
(
region
,
contours
,
hierarchy
,
RETR_TREE
,
CHAIN_APPROX_NONE
,
Point
(
0
,
0
)
);
for
(
size_t
j
=
0
;
j
<
contours
[
0
].
size
();
j
++
)
contours
[
0
][
j
]
+=
(
stat
->
rect
.
tl
()
-
Point
(
1
,
1
));
findContours
(
region
,
contours
,
hierarchy
,
RETR_TREE
,
CHAIN_APPROX_NONE
,
stat
->
rect
.
tl
()
);
regions
.
push_back
(
contours
[
0
]);
}
}
}
...
...
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