Skip to content

Commit 57648c2

Browse files
committed
Merge pull request #876 from alalek:fix_contrib_872
2 parents bd619c5 + 31d1137 commit 57648c2

File tree

4 files changed

+61
-86
lines changed

4 files changed

+61
-86
lines changed

modules/text/samples/detect_er_chars.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import cv2
77
import numpy as np
8-
from matplotlib import pyplot as plt
98

109
print('\ndetect_er_chars.py')
1110
print(' A simple demo script using the Extremal Region Filter algorithm described in:')
@@ -32,8 +31,8 @@
3231
#Visualization
3332
rects = [cv2.boundingRect(p.reshape(-1, 1, 2)) for p in regions]
3433
for rect in rects:
35-
cv2.rectangle(img, rect[0:2], (rect[0]+rect[2],rect[1]+rect[3]), (0, 0, 255), 2)
36-
img = img[:,:,::-1] #flip the colors dimension from BGR to RGB
37-
plt.imshow(img)
38-
plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis
39-
plt.show()
34+
cv2.rectangle(img, rect[0:2], (rect[0]+rect[2],rect[1]+rect[3]), (0, 0, 0), 2)
35+
for rect in rects:
36+
cv2.rectangle(img, rect[0:2], (rect[0]+rect[2],rect[1]+rect[3]), (255, 255, 255), 1)
37+
cv2.imshow("Text detection result", img)
38+
cv2.waitKey(0)

modules/text/samples/textdetection.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ int main(int argc, const char * argv[])
3232

3333
if (argc < 2) show_help_and_exit(argv[0]);
3434

35-
namedWindow("grouping",WINDOW_NORMAL);
3635
Mat src = imread(argv[1]);
3736

3837
// Extract channels to be processed individually
@@ -70,8 +69,8 @@ int main(int argc, const char * argv[])
7069
imshow("grouping",src);
7170

7271
cout << "Done!" << endl << endl;
73-
cout << "Press 'e' to show the extracted Extremal Regions, any other key to exit." << endl << endl;
74-
if( waitKey (-1) == 101)
72+
cout << "Press 'space' to show the extracted Extremal Regions, any other key to exit." << endl << endl;
73+
if ((waitKey()&0xff) == ' ')
7574
er_show(channels,regions);
7675

7776
// memory clean-up

modules/text/samples/textdetection.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import cv2
77
import numpy as np
8-
from matplotlib import pyplot as plt
98

109
print('\ntextdetection.py')
1110
print(' A demo script of the Extremal Region Filter algorithm described in:')
@@ -50,11 +49,10 @@
5049
#Visualization
5150
for r in range(0,np.shape(rects)[0]):
5251
rect = rects[r]
53-
cv2.rectangle(vis, (rect[0],rect[1]), (rect[0]+rect[2],rect[1]+rect[3]), (0, 255, 255), 2)
52+
cv2.rectangle(vis, (rect[0],rect[1]), (rect[0]+rect[2],rect[1]+rect[3]), (0, 0, 0), 2)
53+
cv2.rectangle(vis, (rect[0],rect[1]), (rect[0]+rect[2],rect[1]+rect[3]), (255, 255, 255), 1)
5454

5555

5656
#Visualization
57-
vis = vis[:,:,::-1] #flip the colors dimension from BGR to RGB
58-
plt.imshow(vis)
59-
plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis
60-
plt.show()
57+
cv2.imshow("Text detection result", vis)
58+
cv2.waitKey(0)

modules/text/src/erfilter.cpp

Lines changed: 50 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -275,24 +275,18 @@ void ERFilterNM::er_tree_extract( InputArray image )
275275
// the component stack
276276
vector<ERStat*> er_stack;
277277

278-
//the quads for euler number calculation
279-
unsigned char quads[3][4];
280-
quads[0][0] = 1 << 3;
281-
quads[0][1] = 1 << 2;
282-
quads[0][2] = 1 << 1;
283-
quads[0][3] = 1;
284-
quads[1][0] = (1<<2)|(1<<1)|(1);
285-
quads[1][1] = (1<<3)|(1<<1)|(1);
286-
quads[1][2] = (1<<3)|(1<<2)|(1);
287-
quads[1][3] = (1<<3)|(1<<2)|(1<<1);
288-
quads[2][0] = (1<<2)|(1<<1);
289-
quads[2][1] = (1<<3)|(1);
290-
// quads[2][2] and quads[2][3] are never used so no need to initialize them.
278+
// the quads for euler number calculation
279+
// quads[2][2] and quads[2][3] are never used.
291280
// The four lowest bits in each quads[i][j] correspond to the 2x2 binary patterns
292281
// Q_1, Q_2, Q_3 in the Neumann and Matas CVPR 2012 paper
293282
// (see in page 4 at the end of first column).
294283
// Q_1 and Q_2 have four patterns, while Q_3 has only two.
295-
284+
const int quads[3][4] =
285+
{
286+
{ 1<<3 , 1<<2 , 1<<1 , 1<<0 },
287+
{ (1<<2)|(1<<1)|(1), (1<<3)| (1<<1)|(1), (1<<3)|(1<<2)| (1), (1<<3)|(1<<2)|(1<<1) },
288+
{ (1<<2)|(1<<1) , (1<<3)| (1), /*unused*/-1, /*unused*/-1 }
289+
};
296290

297291
// masks to know if a pixel is accessible and if it has been already added to some region
298292
vector<bool> accessible_pixel_mask(width * height);
@@ -392,8 +386,8 @@ void ERFilterNM::er_tree_extract( InputArray image )
392386
int non_boundary_neighbours = 0;
393387
int non_boundary_neighbours_horiz = 0;
394388

395-
unsigned char quad_before[4] = {0,0,0,0};
396-
unsigned char quad_after[4] = {0,0,0,0};
389+
int quad_before[4] = {0,0,0,0};
390+
int quad_after[4] = {0,0,0,0};
397391
quad_after[0] = 1<<1;
398392
quad_after[1] = 1<<3;
399393
quad_after[2] = 1<<2;
@@ -542,9 +536,9 @@ void ERFilterNM::er_tree_extract( InputArray image )
542536
current_edge = boundary_edges[threshold_level].back();
543537
boundary_edges[threshold_level].erase(boundary_edges[threshold_level].end()-1);
544538

545-
while (boundary_pixes[threshold_level].empty() && (threshold_level < (255/thresholdDelta)+1))
546-
threshold_level++;
547-
539+
for (; threshold_level < (255/thresholdDelta)+1; threshold_level++)
540+
if (!boundary_pixes[threshold_level].empty())
541+
break;
548542

549543
int new_level = image_data[current_pixel];
550544

@@ -784,28 +778,27 @@ ERStat* ERFilterNM::er_save( ERStat *er, ERStat *parent, ERStat *prev )
784778
// recursively walk the tree and filter (remove) regions using the callback classifier
785779
ERStat* ERFilterNM::er_tree_filter ( InputArray image, ERStat * stat, ERStat *parent, ERStat *prev )
786780
{
787-
Mat src = image.getMat();
788781
// assert correct image type
789-
CV_Assert( src.type() == CV_8UC1 );
782+
CV_Assert( image.type() == CV_8UC1 );
783+
784+
Mat src = image.getMat();
790785

791786
//Fill the region and calculate 2nd stage features
792-
Mat region = region_mask(Rect(Point(stat->rect.x,stat->rect.y),Point(stat->rect.br().x+2,stat->rect.br().y+2)));
787+
Mat region = region_mask(Rect(stat->rect.tl(), stat->rect.br() + Point(2,2)));
793788
region = Scalar(0);
794789
int newMaskVal = 255;
795790
int flags = 4 + (newMaskVal << 8) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
796791
Rect rect;
797792

798-
floodFill( src(Rect(Point(stat->rect.x,stat->rect.y),Point(stat->rect.br().x,stat->rect.br().y))),
799-
region, Point(stat->pixel%src.cols - stat->rect.x, stat->pixel/src.cols - stat->rect.y),
793+
floodFill( src(stat->rect),
794+
region, Point(stat->pixel%src.cols, stat->pixel/src.cols) - stat->rect.tl(),
800795
Scalar(255), &rect, Scalar(stat->level), Scalar(0), flags );
801-
rect.width += 2;
802-
rect.height += 2;
803-
region = region(rect);
796+
region = region(Rect(1, 1, rect.width, rect.height));
804797

805798
vector<vector<Point> > contours;
806799
vector<Point> contour_poly;
807800
vector<Vec4i> hierarchy;
808-
findContours( region(Rect(1, 1, region.cols - 2, region.rows - 2)), contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, Point(1, 1) );
801+
findContours( region, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0) );
809802
//TODO check epsilon parameter of approxPolyDP (set empirically) : we want more precission
810803
// if the region is very small because otherwise we'll loose all the convexities
811804
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)
28592852
}
28602853

28612854

2862-
float extract_features(Mat &grey, Mat& channel, vector<ERStat> &regions, vector<ERFeatures> &features);
2863-
2864-
float extract_features(Mat &grey, Mat& channel, vector<ERStat> &regions, vector<ERFeatures> &features)
2855+
static float extract_features(Mat &grey, Mat& channel, vector<ERStat> &regions, vector<ERFeatures> &features)
28652856
{
28662857
// assert correct image type
28672858
CV_Assert(( channel.type() == CV_8UC1 ) && ( grey.type() == CV_8UC1 ));
@@ -2890,18 +2881,15 @@ float extract_features(Mat &grey, Mat& channel, vector<ERStat> &regions, vector<
28902881
{
28912882

28922883
//Fill the region and calculate features
2893-
Mat region = region_mask(Rect(Point(stat->rect.x,stat->rect.y),
2894-
Point(stat->rect.br().x+2,stat->rect.br().y+2)));
2884+
Mat region = region_mask(Rect(stat->rect.tl(),
2885+
stat->rect.br() + Point(2,2)));
28952886
region = Scalar(0);
28962887
int newMaskVal = 255;
28972888
int flags = 4 + (newMaskVal << 8) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
2898-
Rect rect;
28992889

2900-
floodFill( channel(Rect(Point(stat->rect.x,stat->rect.y),Point(stat->rect.br().x,stat->rect.br().y))),
2890+
floodFill( channel(stat->rect),
29012891
region, Point(stat->pixel%channel.cols - stat->rect.x, stat->pixel/channel.cols - stat->rect.y),
2902-
Scalar(255), &rect, Scalar(stat->level), Scalar(0), flags );
2903-
rect.width += 2;
2904-
rect.height += 2;
2892+
Scalar(255), NULL, Scalar(stat->level), Scalar(0), flags );
29052893
Mat rect_mask = region_mask(Rect(stat->rect.x+1,stat->rect.y+1,stat->rect.width,stat->rect.height));
29062894

29072895

@@ -2911,7 +2899,7 @@ float extract_features(Mat &grey, Mat& channel, vector<ERStat> &regions, vector<
29112899
f.intensity_std = (float)std[0];
29122900

29132901
Mat tmp,bw;
2914-
region_mask(Rect(stat->rect.x+1,stat->rect.y+1,stat->rect.width,stat->rect.height)).copyTo(bw);
2902+
rect_mask.copyTo(bw);
29152903
distanceTransform(bw, tmp, DIST_L1,3); //L1 gives distance in round integers while L2 floats
29162904

29172905
// 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<
35133501
i = &regions[idx1[0]][idx1[1]];
35143502
j = &regions[idx2[0]][idx2[1]];
35153503

3516-
Mat region = mask(Rect(Point(i->rect.x,i->rect.y),
3517-
Point(i->rect.br().x+2,i->rect.br().y+2)));
3504+
Mat region = mask(Rect(i->rect.tl(),
3505+
i->rect.br()+ Point(2,2)));
35183506
region = Scalar(0);
35193507

35203508
int newMaskVal = 255;
35213509
int flags = 4 + (newMaskVal << 8) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
3522-
Rect rect;
35233510

3524-
floodFill( channels[idx1[0]](Rect(Point(i->rect.x,i->rect.y),Point(i->rect.br().x,i->rect.br().y))),
3525-
region, Point(i->pixel%grey.cols - i->rect.x, i->pixel/grey.cols - i->rect.y),
3526-
Scalar(255), &rect, Scalar(i->level), Scalar(0), flags);
3527-
rect.width += 2;
3528-
rect.height += 2;
3511+
floodFill( channels[idx1[0]](i->rect),
3512+
region, Point(i->pixel%grey.cols, i->pixel/grey.cols) - i->rect.tl(),
3513+
Scalar(255), NULL, Scalar(i->level), Scalar(0), flags);
35293514
Mat rect_mask = mask(Rect(i->rect.x+1,i->rect.y+1,i->rect.width,i->rect.height));
35303515

35313516
Scalar mean,std;
@@ -3535,15 +3520,12 @@ bool isValidPair(Mat &grey, Mat &lab, Mat &mask, vector<Mat> &channels, vector<
35353520
float a_mean1 = (float)mean[1];
35363521
float b_mean1 = (float)mean[2];
35373522

3538-
region = mask(Rect(Point(j->rect.x,j->rect.y),
3539-
Point(j->rect.br().x+2,j->rect.br().y+2)));
3523+
region = mask(Rect(j->rect.tl(), j->rect.br()+ Point(2,2)));
35403524
region = Scalar(0);
35413525

3542-
floodFill( channels[idx2[0]](Rect(Point(j->rect.x,j->rect.y),Point(j->rect.br().x,j->rect.br().y))),
3543-
region, Point(j->pixel%grey.cols - j->rect.x, j->pixel/grey.cols - j->rect.y),
3544-
Scalar(255), &rect, Scalar(j->level), Scalar(0), flags);
3545-
rect.width += 2;
3546-
rect.height += 2;
3526+
floodFill( channels[idx2[0]](j->rect),
3527+
region, Point(j->pixel%grey.cols, j->pixel/grey.cols) - j->rect.tl(),
3528+
Scalar(255), NULL, Scalar(j->level), Scalar(0), flags);
35473529
rect_mask = mask(Rect(j->rect.x+1,j->rect.y+1,j->rect.width,j->rect.height));
35483530

35493531
meanStdDev(grey(j->rect),mean,std,rect_mask);
@@ -4181,7 +4163,7 @@ void MSERsToERStats(InputArray image, vector<vector<Point> > &contours, vector<v
41814163
void detectRegions(InputArray image, const Ptr<ERFilter>& er_filter1, const Ptr<ERFilter>& er_filter2, CV_OUT vector< vector<Point> >& regions)
41824164
{
41834165
// assert correct image type
4184-
CV_Assert( image.getMat().type() == CV_8UC1 );
4166+
CV_Assert( image.type() == CV_8UC1 );
41854167
// at least one ERFilter must be passed
41864168
CV_Assert( !er_filter1.empty() );
41874169

@@ -4195,36 +4177,33 @@ void detectRegions(InputArray image, const Ptr<ERFilter>& er_filter1, const Ptr<
41954177
}
41964178

41974179
//Convert each ER to vector<Point> and push it to output regions
4198-
Mat src = image.getMat();
4199-
Mat region_mask = Mat::zeros(src.rows+2, src.cols+2, CV_8UC1);
4180+
const Mat src = image.getMat();
42004181
for (size_t i=1; i < ers.size(); i++) //start from 1 to deprecate root region
42014182
{
42024183
ERStat* stat = &ers[i];
42034184

42044185
//Fill the region and calculate 2nd stage features
4205-
Mat region = region_mask(Rect(Point(stat->rect.x,stat->rect.y),Point(stat->rect.br().x+2,stat->rect.br().y+2)));
4206-
region = Scalar(0);
4186+
Mat region_mask(Size(stat->rect.width + 2, stat->rect.height + 2), CV_8UC1, Scalar(0));
4187+
Mat region = region_mask(Rect(1, 1, stat->rect.width, stat->rect.height));
4188+
42074189
int newMaskVal = 255;
42084190
int flags = 4 + (newMaskVal << 8) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
4209-
Rect rect;
42104191

4211-
floodFill( src(Rect(Point(stat->rect.x,stat->rect.y),Point(stat->rect.br().x,stat->rect.br().y))),
4212-
region, Point(stat->pixel%src.cols - stat->rect.x, stat->pixel/src.cols - stat->rect.y),
4213-
Scalar(255), &rect, Scalar(stat->level), Scalar(0), flags );
4214-
rect.width += 2;
4215-
rect.height += 2;
4216-
region = region(rect);
4192+
const Point seed_pt(stat->pixel%src.cols, stat->pixel/src.cols);
4193+
uchar seed_v = src.at<uchar>(seed_pt);
4194+
CV_Assert((int)seed_v <= stat->level);
4195+
4196+
floodFill( src(stat->rect),
4197+
region_mask,
4198+
seed_pt - stat->rect.tl(),
4199+
Scalar(255), NULL, Scalar(/*stat->level*/255), Scalar(0), flags );
42174200

42184201
vector<vector<Point> > contours;
42194202
vector<Vec4i> hierarchy;
4220-
findContours( region, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0) );
4221-
4222-
for (size_t j=0; j < contours[0].size(); j++)
4223-
contours[0][j] += (stat->rect.tl()-Point(1,1));
4203+
findContours( region, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, stat->rect.tl() );
42244204

42254205
regions.push_back(contours[0]);
42264206
}
4227-
42284207
}
42294208

42304209
}

0 commit comments

Comments
 (0)