diff --git a/modules/text/samples/detect_er_chars.py b/modules/text/samples/detect_er_chars.py index 0c43aa47d85..e0433e74820 100644 --- a/modules/text/samples/detect_er_chars.py +++ b/modules/text/samples/detect_er_chars.py @@ -5,7 +5,6 @@ import cv2 import numpy as np -from matplotlib import pyplot as plt print('\ndetect_er_chars.py') print(' A simple demo script using the Extremal Region Filter algorithm described in:') @@ -32,8 +31,8 @@ #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) diff --git a/modules/text/samples/textdetection.cpp b/modules/text/samples/textdetection.cpp index 2cf67b0cb2b..6d167b4a001 100644 --- a/modules/text/samples/textdetection.cpp +++ b/modules/text/samples/textdetection.cpp @@ -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 'space' to show the extracted Extremal Regions, any other key to exit." << endl << endl; + if ((waitKey()&0xff) == ' ') er_show(channels,regions); // memory clean-up diff --git a/modules/text/samples/textdetection.py b/modules/text/samples/textdetection.py index 9636a028470..1da2833f1ed 100644 --- a/modules/text/samples/textdetection.py +++ b/modules/text/samples/textdetection.py @@ -5,7 +5,6 @@ import cv2 import numpy as np -from matplotlib import pyplot as plt print('\ntextdetection.py') print(' A demo script of the Extremal Region Filter algorithm described in:') @@ -50,11 +49,10 @@ #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) diff --git a/modules/text/src/erfilter.cpp b/modules/text/src/erfilter.cpp index 5d1ed8f9b09..f438c750eb1 100644 --- a/modules/text/src/erfilter.cpp +++ b/modules/text/src/erfilter.cpp @@ -275,24 +275,18 @@ void ERFilterNM::er_tree_extract( InputArray image ) // the component stack vector 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 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 > contours; vector contour_poly; vector 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 ®ions, vector &features); - -float extract_features(Mat &grey, Mat& channel, vector ®ions, vector &features) +static float extract_features(Mat &grey, Mat& channel, vector ®ions, vector &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 ®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 ®ions, vector< f.intensity_std = (float)std[0]; Mat tmp,bw; - region_mask(Rect(stat->rect.x+1,stat->rect.y+1,stat->rect.width,stat->rect.height)).copyTo(bw); + rect_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 &channels, vector< i = ®ions[idx1[0]][idx1[1]]; j = ®ions[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 &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 > &contours, vector& er_filter1, const Ptr& er_filter2, CV_OUT vector< vector >& 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& er_filter1, const Ptr< } //Convert each ER to vector 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(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 > contours; vector 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]); } - } }