bool Segmentation::Ransac_for_buildings(float dem_spacing, double ransac_threshold, cv::Mat original_tiles_merged) { StepResource pStep("Computing RANSAC on all the identified buildings", "app", "a2beb9b8-218e-11e4-969b-b2227cce2b54"); ProgressResource pResource("ProgressBar"); Progress *pProgress = pResource.get(); pProgress-> setSettingAutoClose(true); pProgress->updateProgress("Computing RANSAC on all buildings", 0, NORMAL); Ransac_buildings = Ransac(Segmentation::path); cv::Mat roof_image = cv::Mat::zeros(original_tiles_merged.size(), CV_8UC3); buildingS.resize(blobs.size()); buildingS_inliers.resize(blobs.size()); buildingS_outliers.resize(blobs.size()); buildingS_plane_coefficients.resize(blobs.size()); buldingS_number_inliers.resize(blobs.size()); std::ofstream building_file; std::ofstream cont_file; cont_file.open (std::string(path) + "/Results/Number_of_RANSAC_applications.txt"); for(int i = 0; i < blobs.size(); i++) {// i index is the building (blob) index pProgress->updateProgress("Computing RANSAC on all buildings\nBuilding "+ StringUtilities::toDisplayString(i) + " on "+ StringUtilities::toDisplayString(blobs.size()), static_cast<double>(static_cast<double>(i)/blobs.size()*100), NORMAL); building_file.open (std::string(path) + "/Results/Building_" + StringUtilities::toDisplayString(i)+".txt"); building_file << 'i' << '\t' << 'j' << '\t' << 'X' << '\t' << 'Y' << '\t' << 'Z' << '\n'; buildingS[i].setConstant(blobs[i].size(), 3, 0.0); // the j loop retrieves the X, Y, Z coordinate for each pixel of all the buildings for(int j = 0; j < blobs[i].size(); j++) {// j index is the pixel index for the single building // loop on all the pixel of the SINGLE building int pixel_column = blobs[i][j].x; int pixel_row = blobs[i][j].y; double x_building = pixel_column * dem_spacing;// xMin + pixel_column * dem_spacing // object coordinate double y_building = pixel_row * dem_spacing;// yMin + pixel_row * dem_spacing // object coordinate double z_building = original_tiles_merged.at<float>(pixel_row, pixel_column);//object coordinate buildingS[i](j,0) = x_building; buildingS[i](j,1) = y_building; buildingS[i](j,2) = z_building; building_file << pixel_row+1 << '\t' << pixel_column+1 << '\t' << buildingS[i](j,0) << '\t' << buildingS[i](j,1) << '\t' << buildingS[i](j,2) << '\n'; //+1 on the imae coordinates to verify with opticks' rasters (origin is 1,1) } building_file.close(); std::ofstream inliers_file; std::ofstream parameters_file; inliers_file.open (std::string(path) + "/Results/Inliers_building_" + StringUtilities::toDisplayString(i)+".txt"); parameters_file.open (std::string(path) + "/Results/plane_parameters_building_" + StringUtilities::toDisplayString(i)+".txt"); //parameters_file << "a\tb\tc\td\tmean_dist\tstd_dist\n"; int cont = 0; Ransac_buildings.ransac_msg += "\n____________Building number " + StringUtilities::toDisplayString(i) +"____________\n"; Ransac_buildings.ransac_msg += "\nITERATION NUMBER " + StringUtilities::toDisplayString(cont) +"\n"; Ransac_buildings.ComputeModel(buildingS[i], ransac_threshold); buldingS_number_inliers[i]= Ransac_buildings.n_best_inliers_count; buildingS_inliers[i] = Ransac_buildings.final_inliers; buildingS_outliers[i] = Ransac_buildings.final_outliers; buildingS_plane_coefficients[i] = Ransac_buildings.final_model_coefficients; double inliers_percentage = static_cast<double>( (Ransac_buildings.n_best_inliers_count) ) / static_cast<double> (buildingS[i].rows()); int inliers_so_far = Ransac_buildings.n_best_inliers_count; std::vector<int> old_final_outliers = Ransac_buildings.final_outliers; // DRAWS THE ROOFS yellow for (int k = 0; k < Ransac_buildings.n_best_inliers_count; k++) { int pixel_row = static_cast<int>(buildingS[i](Ransac_buildings.final_inliers[k], 1) / dem_spacing); int pixel_column = static_cast<int>(buildingS[i](Ransac_buildings.final_inliers[k], 0) / dem_spacing); unsigned char r = 255;// unsigned char(255 * (rand()/(1.0 + RAND_MAX))); unsigned char g = 255;// unsigned char(255 * (rand()/(1.0 + RAND_MAX))); unsigned char b = 0;//unsigned char(255 * (rand()/(1.0 + RAND_MAX))); roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[0] = b; roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[1] = g; roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[2] = r; } while (inliers_percentage < 0.90) { cont ++; Ransac_buildings.ransac_msg += "\nITERATION NUMBER " + StringUtilities::toDisplayString(cont) +"\n"; Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> building_outliers; building_outliers.setConstant(buildingS[i].rows() - inliers_so_far, 3, 0.0); //* forse il metodo va già bene così, perchè riempio la matrice deglio outlier in maniera ordinata, //* solo che gli indici degli inlier/outlier non sono più indicativi rispetto alla matrice di building originale, ma rispetto alla matrice di innput //* devo riporatre gli ID degli indici alla loro posizione originale for (int w = 0; w <building_outliers.rows(); w++) { building_outliers(w, 0) = buildingS[i](old_final_outliers[w], 0); building_outliers(w, 1) = buildingS[i](old_final_outliers[w], 1); building_outliers(w, 2) = buildingS[i](old_final_outliers[w], 2); //Ransac_buildings.ransac_msg += "\n" + StringUtilities::toDisplayString(pixel_row+1) + "\t" + StringUtilities::toDisplayString(pixel_column+1) + "\t" + StringUtilities::toDisplayString(final_outliers[w]) + "\t" + StringUtilities::toDisplayString(building_outliers(w, 0))+ "\t"+ StringUtilities::toDisplayString(building_outliers(w, 1)) + "\t" + StringUtilities::toDisplayString(building_outliers(w, 2))+"\n"; // needed for tesing (test passed at first iteration) } Ransac_buildings.ransac_msg += "\n"; //Ransac_buildings.ransac_msg += "\nprova "+ StringUtilities::toDisplayString(inliers_percentage*100)+"\n"; Ransac_buildings.ComputeModel(building_outliers, ransac_threshold); //inliers_percentage = inliers_percentage + static_cast<double>( (n_best_inliers_count) ) / static_cast<double> (building_outliers.rows()); inliers_percentage = inliers_percentage + static_cast<double>( (Ransac_buildings.n_best_inliers_count) ) / static_cast<double> (buildingS[i].rows()); Ransac_buildings.ransac_msg += "\nINLIERS IN RELATION TO GLOBAL INDEX ("+ StringUtilities::toDisplayString(Ransac_buildings.n_best_inliers_count) + ")\n"; for(size_t i = 0; i < Ransac_buildings.n_best_inliers_count; i++) { Ransac_buildings.ransac_msg += StringUtilities::toDisplayString(old_final_outliers[Ransac_buildings.final_inliers[i]])+" "; inliers_file << old_final_outliers[Ransac_buildings.final_inliers[i]] << "\t"; } Ransac_buildings.ransac_msg += "\n"; inliers_file << "\n"; //old_final_outliers.resize(building_outliers.rows() - Ransac_buildings.n_best_inliers_count); Ransac_buildings.ransac_msg += "\nOUTLIERS IN RELATION TO GLOBAL INDEX("+ StringUtilities::toDisplayString(building_outliers.rows() - Ransac_buildings.n_best_inliers_count) + ")\n"; for(size_t i = 0; i < building_outliers.rows() - Ransac_buildings.n_best_inliers_count; i++) { Ransac_buildings.ransac_msg += StringUtilities::toDisplayString(old_final_outliers[Ransac_buildings.final_outliers[i]])+" "; old_final_outliers[i] = old_final_outliers[Ransac_buildings.final_outliers[i]];// in this way I refer the outliers indexes to the global indexes (those referred to the original eigen matrix) } //parameters_file << Ransac_buildings.final_model_coefficients[0] << "\t" << Ransac_buildings.final_model_coefficients[1] << "\t" << Ransac_buildings.final_model_coefficients[2] << "\t" << Ransac_buildings.final_model_coefficients[3] << "\t" << Ransac_buildings.mean_distances << "\t"<< Ransac_buildings.std_distances << "\n"; parameters_file << Ransac_buildings.final_model_coefficients[0] << "\t" << Ransac_buildings.final_model_coefficients[1] << "\t" << Ransac_buildings.final_model_coefficients[2] << "\t" << Ransac_buildings.final_model_coefficients[3] << "\n"; if (cont == 1) { // DRAWS THE ROOFS blue for (int k = 0; k < Ransac_buildings.n_best_inliers_count; k++) { int pixel_row = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 1) / dem_spacing); int pixel_column = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 0) / dem_spacing); unsigned char r = 0;// unsigned char(255 * (rand()/(1.0 + RAND_MAX))); unsigned char g = 0;// unsigned char(255 * (rand()/(1.0 + RAND_MAX))); unsigned char b = 255;//unsigned char(255 * (rand()/(1.0 + RAND_MAX))); roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[0] = b; roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[1] = g; roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[2] = r; } } if (cont ==2) { // DRAWS THE ROOFS green for (int k = 0; k < Ransac_buildings.n_best_inliers_count; k++) { int pixel_row = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 1) / dem_spacing); int pixel_column = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 0) / dem_spacing); unsigned char r = 0;// unsigned char(255 * (rand()/(1.0 + RAND_MAX))); unsigned char g = 255;// unsigned char(255 * (rand()/(1.0 + RAND_MAX))); unsigned char b = 0;//unsigned char(255 * (rand()/(1.0 + RAND_MAX))); roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[0] = b; roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[1] = g; roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[2] = r; } } if (cont ==3) { // DRAWS THE ROOFS brown for (int k = 0; k < Ransac_buildings.n_best_inliers_count; k++) { int pixel_row = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 1) / dem_spacing); int pixel_column = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 0) / dem_spacing); unsigned char r = 128;// unsigned char(255 * (rand()/(1.0 + RAND_MAX))); unsigned char g = 0;// unsigned char(255 * (rand()/(1.0 + RAND_MAX))); unsigned char b = 0;//unsigned char(255 * (rand()/(1.0 + RAND_MAX))); roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[0] = b; roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[1] = g; roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[2] = r; } } //if (cont == 4) //{ // // DRAWS THE ROOFS white // for (int k = 0; k < Ransac_buildings.n_best_inliers_count; k++) // { // int pixel_row = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 1) / dem_spacing); // int pixel_column = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 0) / dem_spacing); // unsigned char r = 255;// unsigned char(255 * (rand()/(1.0 + RAND_MAX))); // unsigned char g = 255;// unsigned char(255 * (rand()/(1.0 + RAND_MAX))); // unsigned char b = 255;//unsigned char(255 * (rand()/(1.0 + RAND_MAX))); // roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[0] = b; // roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[1] = g; // roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[2] = r; // } //} Ransac_buildings.ransac_msg += "\n"; inliers_so_far += Ransac_buildings.n_best_inliers_count; }// fine while Ransac_buildings.ransac_msg += "__________________________________________________________________\n"; //boh_file.close(); cont_file << i << "\t" << cont << "\n"; } building_file.close(); cont_file.close(); cv::imshow("roofs", roof_image); cv::imwrite(path + "/Results/building_roofs.png", roof_image); cv::waitKey(0); pProgress->updateProgress("All buildings have been processed with RANSAC.", 100, NORMAL); pStep->finalize(); return true; }
int DetectorBarcode::Detect() { std::cout << "DetectorBarcode::Detect()" << std::endl; assert(this->image_.data != NULL); bool debugstripecode = true; //@TODO MAKE SURE TO SET ME TO FALSE IN PRODUCTION bool useAdaptiveThersholding = true; int dpi = 400; //this works well for all scales and sizes.. Mat matImageK; cvtColor(this->image_, matImageK, cv::COLOR_BGR2GRAY); cv::Mat matThres; // VARIABLES // double bar_height_mm_min = 3.7; //[7.5mm=our NMNH c39] [10.7mm=NMNH cover c39] double bar_height_mm_max = 20; double bar_ar_min = 4; double bar_ar_max = 110; int min_characters = 5; //minimum characters in barcode string double bar_dist_group_mm_max = 9.0; //Maximum distance between any grouped bar to be part of the bar group // COMPUTE // double bar_height_px_min = bar_height_mm_min/25.4*dpi; double bar_height_px_max = bar_height_mm_max/25.4*dpi; double bar_area_px_min = bar_height_px_min*(bar_height_px_min*1.0/bar_ar_max); //Dont allow the area to be less than 1px row bar_area_px_min = bar_area_px_min < bar_height_px_min ? bar_height_px_min : bar_area_px_min; double bar_area_px_max = bar_height_px_max*(bar_height_px_max*1.0/bar_ar_min); double bar_dist_group_px_max = bar_dist_group_mm_max/25.4*dpi; if (useAdaptiveThersholding) { //int AT_blocksize = dpi*0.05; int AT_blocksize = bar_height_px_min*0.5; int AT_iseven=AT_blocksize%2; AT_blocksize += 1+AT_iseven; //Makes sure the blocksize is an even number //cout << "AT_blocksize=" << AT_blocksize << endl; adaptiveThreshold(matImageK, matThres, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, AT_blocksize, 20); } else { threshold(matImageK, matThres, 127, 255, THRESH_BINARY_INV); } if (debugstripecode) { //cout << "dpi=" << dpi << endl; imwrite("/Users/tzaman/Desktop/bc/matImage.tif", this->image_); imwrite("/Users/tzaman/Desktop/bc/matThres.tif", matThres); } vector< vector<Point> > contours; vector<Vec4i> hierarchy; findContours( matThres, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE ); //cout << "contours.size()=" << contours.size() << endl; if (contours.size() == 0) { string strErr = "No contours found."; cout << strErr << endl; return RET_NONE_FOUND; } //RANSAC vars int min_inliers = (min_characters+2)*5*0.75; //+2 (start&stop), *5 (stripes per char), *0.x (margin) double max_px_dist = (bar_height_px_min+bar_height_px_max)*0.5*0.05; //Maximum distance from RANSAC line to a point vector<RotatedRect> stripeCandidates; for(int i = 0; i >= 0; i = hierarchy[i][0] ) { double cArea = contourArea( contours[i],false); if (cArea < bar_area_px_min*0.5){ continue; } if (cArea > bar_area_px_max){ continue; } //cout << "[" << i << "]" << " cArea=" << cArea << endl; RotatedRect rotRect= minAreaRect(contours[i]); double ar = max(double(rotRect.size.width),double(rotRect.size.height)) / min(double(rotRect.size.width),double(rotRect.size.height)); if (ar < bar_ar_min){ continue; } if (ar > bar_ar_max){ continue; } double width = std::min(rotRect.size.width, rotRect.size.height); double height = std::max(rotRect.size.width, rotRect.size.height); //Check the length if (height < bar_height_px_min){ //Stripe too small continue; } if (height > bar_height_px_max ){ //Stripe too long continue; } //cout << i << " rotRect: sz=" << rotRect.size << " cp=" << rotRect.center << " a=" << rotRect.angle << " ar=" << ar << endl; Rect rCrop = boundingRect(contours[i]); //Below parameter is dynamic, plz note double min_area_fill=0.15;// = 0.25 ;// 0.4 means 40% of the bounding rectangle of the contour needs to be filled //The min_area_fill threshold should be dependent on the width in pixels, because there's more noise in thinner ones if (width<3){ min_area_fill = 0.05; } else if (width <5){ min_area_fill = 0.10; } //Check if the rectangle is actually filled well int fullarea = rCrop.area(); if ( (double(cArea)/double(fullarea)) < min_area_fill){ continue; } //cout << i << " fullarea=" << fullarea << " carea=" << cArea << endl; if (debugstripecode){ imwrite("/Users/tzaman/Desktop/seg/" + std::to_string(i) + ".tif", matImageK(rCrop)); } stripeCandidates.push_back(rotRect); } if (debugstripecode){ Mat matBarcodeFull = this->image_.clone(); for (int j=0; j<stripeCandidates.size(); j++){ util::rectangle(matBarcodeFull, stripeCandidates[j], cv::Scalar(255,0,0), 2); } imwrite("/Users/tzaman/Desktop/bc/_candidates.tif", matBarcodeFull); } //cout << "stripeCandidates.size()=" << stripeCandidates.size() << endl; if (stripeCandidates.size() < min_inliers){ string strErr = "Code 39 did not find enough bars to accurately make a code."; cout << strErr << endl; return RET_NONE_FOUND; } std::vector<Point> vecPtRectCenter = util::vecrotrect2vecpt(stripeCandidates); std::vector<std::vector<int> > vecGroupIdxs = util::groupPoints(vecPtRectCenter, bar_dist_group_px_max, min_inliers); //std::vector<std::vector<cv::Point> > vecGroupPts(vecGroupIdxs.size()); std::vector<std::vector<cv::RotatedRect> > vecGroupRects(vecGroupIdxs.size()); //Relate indexes to points and add to group vector for (int i=0; i<vecGroupIdxs.size(); i++){ //vecGroupPts[i].resize(vecGroupIdxs[i].size()); vecGroupRects[i].resize(vecGroupIdxs[i].size()); for (int j=0; j<vecGroupIdxs[i].size(); j++){ //cout << i << "," << j << endl; //vecGroupPts[i][j] = vecPtRectCenter[vecGroupIdxs[i][j]]; vecGroupRects[i][j] = stripeCandidates[vecGroupIdxs[i][j]]; } } //Draw all groups //if(debugstripecode){ // for (int i=0; i<vecGroupPts.size(); i++){ // Mat matGroup = matImage.clone(); // for (int j=0; j<vecGroupPts[i].size(); j++){ // circle(matGroup, vecGroupPts[i][j], 5, Scalar(255,0,255), 1, CV_AA,0); // } // imwrite("/Users/tzaman/Desktop/bc/_group_" + std::to_string(i) + ".tif", matGroup); // } //} //exit(-1); //cout << "vecGroupPts.size()=" << vecGroupPts.size() << endl; //Erase small groups //for (int i=vecGroupPts.size()-1; i>=0; i--){ // if (vecGroupPts[i].size() < min_inliers){ // //Skipping group, too small. // vecGroupIdxs.erase(vecGroupIdxs.begin()+i); // vecGroupPts.erase(vecGroupPts.begin()+i); // } //} //cout << "vecGroupPts.size()=" << vecGroupPts.size() << endl; if (vecGroupIdxs.size() == 0) { string strErr = "Code 39 failed to ransac bars in a line."; cout << strErr << endl; return RET_NONE_FOUND; } //Now cycle over the groups vector<vector<int> > vecVecInlierIdx; vector<Vec4f> vecLines; vector<int> vecFromGroup; //Keeps track of which group the vecvecInlierIdx belongs to for (int i = 0; i < vecGroupRects.size(); i++) { Ransac(vecGroupRects[i], min_inliers, max_px_dist, vecVecInlierIdx, vecLines, this->image_); vecFromGroup.resize(vecVecInlierIdx.size(), i); } if (vecLines.size() == 0) { string strErr = "Code 39 failed to ransac bars in a line."; cout << strErr << endl; return RET_NONE_FOUND; } else { //cout << "Code39 ransac succesfull" << endl; } //for (int i=0; i<vecGroupIdxs.size(); i++){ // cout << "Group " << i << " (" << vecGroupIdxs[i].size() << ") : "; // for (int j=0; j<vecGroupIdxs[i].size(); j++){ // cout << vecGroupIdxs[i][j] << " "; // } // cout << endl; //} //Convert back vecVecInlierIdx to original indices for (int i=0; i<vecVecInlierIdx.size(); i++){ //cout << "vecVecInlierIdx[" << i << "] is from group " << vecFromGroup[i] << endl; for (int j=0; j<vecVecInlierIdx[i].size(); j++){ //cout << " " << vecVecInlierIdx[i][j] << " -> " << vecGroupIdxs[vecFromGroup[i]][vecVecInlierIdx[i][j]] << endl; vecVecInlierIdx[i][j] = vecGroupIdxs[vecFromGroup[i]][vecVecInlierIdx[i][j]]; } } for (int i=0; i < vecLines.size(); i++){ int numpts = vecVecInlierIdx[i].size(); cout << "Potential barcode #" << i << " with " << numpts << " points." << endl; //double angle=atan2(vecLines[i][1],vecLines[i][0])*180/M_PI; //For some reason it clips from [-90,90] double angle_rad = atan2(vecLines[i][1],vecLines[i][0]); //For some reason it clips from [-90,90] double angle_deg = angle_rad*180.0/M_PI; //cout << " angle_deg=" << angle_deg << endl; vector<double> bar_heights(numpts); vector<double> bar_widths(numpts); vector<double> coords_x(numpts); //Loop over all found and ransac-verified stripes in this barcode vector<cv::RotatedRect> stripesVerified(numpts); for (int j=0; j < numpts; j++){ //cout << vecVecInlierIdx[i][j] << endl; //cout << "checking out stripecandidate[" << vecVecInlierIdx[i][j] << "] #" << vecVecInlierIdx[i][j] << endl; stripesVerified[j] = stripeCandidates[vecVecInlierIdx[i][j]]; double dim_smallest = min(stripesVerified[j].size.width, stripesVerified[j].size.height); //For rotation invariance double dim_tallest = max(stripesVerified[j].size.width, stripesVerified[j].size.height); //For rotation invariance bar_heights[j] = dim_tallest; bar_widths[j] = dim_smallest; //Rotate the points straight Point2f ptRot = util::rotatePoint(stripesVerified[j].center, Point(matImageK.cols, matImageK.rows), angle_rad); //cout << ptRot << endl; coords_x[j] = ptRot.x; } double height_median = util::calcMedian(bar_heights); double width_mean = util::calcMean(bar_widths); //cout << "height_median=" << height_median <<" width_mean=" << width_mean << endl; //Find the start and end position for reading vector<size_t> coords_sorted_index; vector<double> coords_x_sorted; sort(coords_x, coords_x_sorted, coords_sorted_index); //cout << coords_x_sorted[0] << " -> " << coords_x_sorted[coords_x_sorted.size()-1] << endl; //Get extrema-stripes Point2f pt_stripe_left = stripeCandidates[vecVecInlierIdx[i][coords_sorted_index[0]]].center; Point2f pt_stripe_right = stripeCandidates[vecVecInlierIdx[i][coords_sorted_index[coords_sorted_index.size() - 1]]].center; //cout << "pt_stripe_left=" << pt_stripe_left << endl; //cout << "pt_stripe_right=" << pt_stripe_right << endl; Point2f pt_barcode_center = (pt_stripe_left + pt_stripe_right) * 0.5; //cout << "pt_barcode_center=" << pt_barcode_center << endl; //Calculate width of the barcode double barcode_width = util::pointDist(pt_stripe_left, pt_stripe_right); //cout << "barcode_width=" << barcode_width << endl; //Make the rotated rectangle around the barcode cv::RotatedRect rotrect_candidate(pt_barcode_center, Size2f(barcode_width, height_median), angle_deg); const double add_width_on_sides_before_decoding = 7.0; // this number will be multiplied by average bar width //Add margin (of a few median widths) rotrect_candidate.size += Size2f(width_mean * add_width_on_sides_before_decoding, 0); const double height_retrainer_for_collapse = 0.25; //Extract the barcode itself cv::RotatedRect rotrect_candidate_thin = rotrect_candidate; //Crop off some margin in thickness because we dont want to collapse the entire barcode. if (rotrect_candidate_thin.size.width < rotrect_candidate_thin.size.height) { rotrect_candidate_thin.size.width *= height_retrainer_for_collapse; } else { rotrect_candidate_thin.size.height *= height_retrainer_for_collapse; } openbarcode::code code_candidate; code_candidate.rotrect = rotrect_candidate_thin; this->code_candidates_.push_back(code_candidate); } return RET_SUCCESS; }