#include "line2Dup.h"#include <memory>#include <iostream>#include <assert.h>#include <chrono>using namespace std;using namespace cv;static std::string prefix = "/home/meiqua/shape_based_matching/test/";class Timer{public:Timer() : beg_(clock_::now()) {}void reset() { beg_ = clock_::now(); }double elapsed() const {return std::chrono::duration_cast<second_>(clock_::now() - beg_).count(); }void out(std::string message = ""){double t = elapsed();std::cout << message << "\nelasped time:" << t << "s" << std::endl;reset();}private:typedef std::chrono::high_resolution_clock clock_;typedef std::chrono::duration<double, std::ratio<1> > second_;std::chrono::time_point<clock_> beg_;};// NMS, got from cv::dnn so we don't need opencv contrib// just collapse itnamespace cv_dnn {namespace{template <typename T>static inline bool SortScorePairDescend(const std::pair<float, T>& pair1,const std::pair<float, T>& pair2){return pair1.first > pair2.first;}} // namespaceinline void GetMaxScoreIndex(const std::vector<float>& scores, const float threshold, const int top_k,std::vector<std::pair<float, int> >& score_index_vec){for (size_t i = 0; i < scores.size(); ++i){if (scores[i] > threshold){score_index_vec.push_back(std::make_pair(scores[i], i));}}std::stable_sort(score_index_vec.begin(), score_index_vec.end(),SortScorePairDescend<int>);if (top_k > 0 && top_k < (int)score_index_vec.size()){score_index_vec.resize(top_k);}}template <typename BoxType>inline void NMSFast_(const std::vector<BoxType>& bboxes,const std::vector<float>& scores, const float score_threshold,const float nms_threshold, const float eta, const int top_k,std::vector<int>& indices, float (*computeOverlap)(const BoxType&, const BoxType&)){CV_Assert(bboxes.size() == scores.size());std::vector<std::pair<float, int> > score_index_vec;GetMaxScoreIndex(scores, score_threshold, top_k, score_index_vec);// Do nms.float adaptive_threshold = nms_threshold;indices.clear();for (size_t i = 0; i < score_index_vec.size(); ++i) {const int idx = score_index_vec[i].second;bool keep = true;for (int k = 0; k < (int)indices.size() && keep; ++k) {const int kept_idx = indices[k];float overlap = computeOverlap(bboxes[idx], bboxes[kept_idx]);keep = overlap <= adaptive_threshold;}if (keep)indices.push_back(idx);if (keep && eta < 1 && adaptive_threshold > 0.5) {adaptive_threshold *= eta;}}}// copied from opencv 3.4, not exist in 3.0template<typename _Tp> static inlinedouble jaccardDistance__(const Rect_<_Tp>& a, const Rect_<_Tp>& b) {_Tp Aa = a.area();_Tp Ab = b.area();if ((Aa + Ab) <= std::numeric_limits<_Tp>::epsilon()) {// jaccard_index = 1 -> distance = 0return 0.0;}double Aab = (a & b).area();// distance = 1 - jaccard_indexreturn 1.0 - Aab / (Aa + Ab - Aab);}template <typename T>static inline float rectOverlap(const T& a, const T& b){return 1.f - static_cast<float>(jaccardDistance__(a, b));}void NMSBoxes(const std::vector<Rect>& bboxes, const std::vector<float>& scores,const float score_threshold, const float nms_threshold,std::vector<int>& indices, const float eta=1, const int top_k=0){NMSFast_(bboxes, scores, score_threshold, nms_threshold, eta, top_k, indices, rectOverlap);}}void scale_test(string mode = "test"){int num_feature = 150;// feature numbers(how many ori in one templates?)// two pyramids, lower pyramid(more pixels) in stride 4, lower in stride 8line2Dup::Detector detector(num_feature, {4, 8});// mode = "test";if(mode == "train"){Mat img = cv::imread(prefix+"case0/templ/circle.png");assert(!img.empty() && "check your img path");shape_based_matching::shapeInfo_producer shapes(img);shapes.scale_range = {0.1f, 1};shapes.scale_step = 0.01f;shapes.produce_infos();std::vector<shape_based_matching::shapeInfo_producer::Info> infos_have_templ;string class_id = "circle";for(auto& info: shapes.infos){// template img, id, mask,//feature numbers(missing it means using the detector initial num)int templ_id = detector.addTemplate(shapes.src_of(info), class_id, shapes.mask_of(info),int(num_feature*info.scale));std::cout << "templ_id: " << templ_id << std::endl;// may fail when asking for too many feature_nums for small training imgif(templ_id != -1){ // only record info when we successfully add templateinfos_have_templ.push_back(info);}}// save templatesdetector.writeClasses(prefix+"case0/%s_templ.yaml");// save infos,// in this simple case infos are not usedshapes.save_infos(infos_have_templ, prefix + "case0/circle_info.yaml");std::cout << "train end" << std::endl << std::endl;}else if(mode=="test"){std::vector<std::string> ids;// read templatesids.push_back("circle");detector.readClasses(ids, prefix+"case0/%s_templ.yaml");Mat test_img = imread(prefix+"case0/1.jpg");assert(!test_img.empty() && "check your img path");// make the img having 32*n width & height// at least 16*n here for two pyrimads with strides 4 8int stride = 32;int n = test_img.rows/stride;int m = test_img.cols/stride;Rect roi(0, 0, stride*m , stride*n);Mat img = test_img(roi).clone();assert(img.isContinuous());Timer timer;// match, img, min socre, idsauto matches = detector.match(img, 90, ids);// one output match:// x: top left x// y: top left y// template_id: used to find templates// similarity: scores, 100 is besttimer.out();std::cout << "matches.size(): " << matches.size() << std::endl;size_t top5 = 5;if(top5>matches.size()) top5=matches.size();for(size_t i=0; i<top5; i++){auto match = matches[i];auto templ = detector.getTemplates("circle",match.template_id);// template:// nums: num_pyramids * num_modality (modality, depth or RGB, always 1 here)// template[0]: lowest pyrimad(more pixels)// template[0].width: actual width of the matched template// template[0].tl_x / tl_y: topleft corner when cropping templ during training// In this case, we can regard width/2 = radiusint x = templ[0].width/2 + match.x;int y = templ[0].height/2 + match.y;int r = templ[0].width/2;Scalar color(255, rand()%255, rand()%255);cv::putText(img, to_string(int(round(match.similarity))),Point(match.x+r-10, match.y-3), FONT_HERSHEY_PLAIN, 2, color);cv::circle(img, {x, y}, r, color, 2);}imshow("img", img);waitKey(0);std::cout << "test end" << std::endl << std::endl;}}void angle_test(string mode = "test", bool use_rot = true){line2Dup::Detector detector(128, {4, 8});if(mode != "test"){Mat img = imread(prefix+"case1/train.png");assert(!img.empty() && "check your img path");Rect roi(130, 110, 270, 270);img = img(roi).clone();Mat mask = Mat(img.size(), CV_8UC1, {255});// padding to avoid rotating outint padding = 100;cv::Mat padded_img = cv::Mat(img.rows + 2*padding, img.cols + 2*padding, img.type(), cv::Scalar::all(0));img.copyTo(padded_img(Rect(padding, padding, img.cols, img.rows)));cv::Mat padded_mask = cv::Mat(mask.rows + 2*padding, mask.cols + 2*padding, mask.type(), cv::Scalar::all(0));mask.copyTo(padded_mask(Rect(padding, padding, img.cols, img.rows)));shape_based_matching::shapeInfo_producer shapes(padded_img, padded_mask);shapes.angle_range = {0, 360};shapes.angle_step = 1;shapes.scale_range = {1}; // support just oneshapes.produce_infos();std::vector<shape_based_matching::shapeInfo_producer::Info> infos_have_templ;string class_id = "test";bool is_first = true;// for other scales you want to re-extract points:// set shapes.scale_range then produce_infos; set is_first = false;int first_id = 0;float first_angle = 0;for(auto& info: shapes.infos){Mat to_show = shapes.src_of(info);std::cout << "\ninfo.angle: " << info.angle << std::endl;int templ_id;if(is_first){templ_id = detector.addTemplate(shapes.src_of(info), class_id, shapes.mask_of(info));first_id = templ_id;first_angle = info.angle;if(use_rot) is_first = false;}else{templ_id = detector.addTemplate_rotate(class_id, first_id,info.angle-first_angle,{shapes.src.cols/2.0f, shapes.src.rows/2.0f});}auto templ = detector.getTemplates("test", templ_id);for(int i=0; i<templ[0].features.size(); i++){auto feat = templ[0].features[i];cv::circle(to_show, {feat.x+templ[0].tl_x, feat.y+templ[0].tl_y}, 3, {0, 0, 255}, -1);}// will be faster if not showing thisimshow("train", to_show);waitKey(1);std::cout << "templ_id: " << templ_id << std::endl;if(templ_id != -1){infos_have_templ.push_back(info);}}detector.writeClasses(prefix+"case1/%s_templ.yaml");shapes.save_infos(infos_have_templ, prefix + "case1/test_info.yaml");std::cout << "train end" << std::endl << std::endl;}else if(mode=="test"){std::vector<std::string> ids;ids.push_back("test");detector.readClasses(ids, prefix+"case1/%s_templ.yaml");// angle & scale are saved here, fetched by match idauto infos = shape_based_matching::shapeInfo_producer::load_infos(prefix + "case1/test_info.yaml");Mat test_img = imread(prefix+"case1/test.png");assert(!test_img.empty() && "check your img path");int padding = 250;cv::Mat padded_img = cv::Mat(test_img.rows + 2*padding,test_img.cols + 2*padding, test_img.type(), cv::Scalar::all(0));test_img.copyTo(padded_img(Rect(padding, padding, test_img.cols, test_img.rows)));int stride = 16;int n = padded_img.rows/stride;int m = padded_img.cols/stride;Rect roi(0, 0, stride*m , stride*n);Mat img = padded_img(roi).clone();assert(img.isContinuous());// cvtColor(img, img, CV_BGR2GRAY);std::cout << "test img size: " << img.rows * img.cols << std::endl << std::endl;Timer timer;auto matches = detector.match(img, 90, ids);timer.out();if(img.channels() == 1) cvtColor(img, img, CV_GRAY2BGR);std::cout << "matches.size(): " << matches.size() << std::endl;size_t top5 = 1;if(top5>matches.size()) top5=matches.size();for(size_t i=0; i<top5; i++){auto match = matches[i];auto templ = detector.getTemplates("test",match.template_id);// 270 is width of template image// 100 is padding when training// tl_x/y: template croping topleft corner when trainingfloat r_scaled = 270/2.0f*infos[match.template_id].scale;// scaling won't affect this, because it has been determined by warpAffine// cv::warpAffine(src, dst, rot_mat, src.size()); last paramfloat train_img_half_width = 270/2.0f + 100;float train_img_half_height = 270/2.0f + 100;// center x,y of train_img in test imgfloat x = match.x - templ[0].tl_x + train_img_half_width;float y = match.y - templ[0].tl_y + train_img_half_height;cv::Vec3b randColor;randColor[0] = rand()%155 + 100;randColor[1] = rand()%155 + 100;randColor[2] = rand()%155 + 100;for(int i=0; i<templ[0].features.size(); i++){auto feat = templ[0].features[i];cv::circle(img, {feat.x+match.x, feat.y+match.y}, 3, randColor, -1);}cv::putText(img, to_string(int(round(match.similarity))),Point(match.x+r_scaled-10, match.y-3), FONT_HERSHEY_PLAIN, 2, randColor);cv::RotatedRect rotatedRectangle({x, y}, {2*r_scaled, 2*r_scaled}, -infos[match.template_id].angle);cv::Point2f vertices[4];rotatedRectangle.points(vertices);for(int i=0; i<4; i++){int next = (i+1==4) ? 0 : (i+1);cv::line(img, vertices[i], vertices[next], randColor, 2);}std::cout << "\nmatch.template_id: " << match.template_id << std::endl;std::cout << "match.similarity: " << match.similarity << std::endl;}imshow("img", img);waitKey(0);std::cout << "test end" << std::endl << std::endl;}}void noise_test(string mode = "test"){line2Dup::Detector detector(30, {4, 8});if(mode == "train"){Mat img = imread(prefix+"case2/train.png");assert(!img.empty() && "check your img path");Mat mask = Mat(img.size(), CV_8UC1, {255});shape_based_matching::shapeInfo_producer shapes(img, mask);shapes.angle_range = {0, 360};shapes.angle_step = 1;shapes.produce_infos();std::vector<shape_based_matching::shapeInfo_producer::Info> infos_have_templ;string class_id = "test";for(auto& info: shapes.infos){imshow("train", shapes.src_of(info));waitKey(1);std::cout << "\ninfo.angle: " << info.angle << std::endl;int templ_id = detector.addTemplate(shapes.src_of(info), class_id, shapes.mask_of(info));std::cout << "templ_id: " << templ_id << std::endl;if(templ_id != -1){infos_have_templ.push_back(info);}}detector.writeClasses(prefix+"case2/%s_templ.yaml");shapes.save_infos(infos_have_templ, prefix + "case2/test_info.yaml");std::cout << "train end" << std::endl << std::endl;}else if(mode=="test"){std::vector<std::string> ids;ids.push_back("test");detector.readClasses(ids, prefix+"case2/%s_templ.yaml");Mat test_img = imread(prefix+"case2/test.png");assert(!test_img.empty() && "check your img path");// cvtColor(test_img, test_img, CV_BGR2GRAY);int stride = 16;int n = test_img.rows/stride;int m = test_img.cols/stride;Rect roi(0, 0, stride*m , stride*n);test_img = test_img(roi).clone();Timer timer;auto matches = detector.match(test_img, 90, ids);timer.out();std::cout << "matches.size(): " << matches.size() << std::endl;size_t top5 = 500;if(top5>matches.size()) top5=matches.size();vector<Rect> boxes;vector<float> scores;vector<int> idxs;for(auto match: matches){Rect box;box.x = match.x;box.y = match.y;auto templ = detector.getTemplates("test",match.template_id);box.width = templ[0].width;box.height = templ[0].height;boxes.push_back(box);scores.push_back(match.similarity);}cv_dnn::NMSBoxes(boxes, scores, 0, 0.5f, idxs);for(auto idx: idxs){auto match = matches[idx];auto templ = detector.getTemplates("test",match.template_id);int x = templ[0].width + match.x;int y = templ[0].height + match.y;int r = templ[0].width/2;cv::Vec3b randColor;randColor[0] = rand()%155 + 100;randColor[1] = rand()%155 + 100;randColor[2] = rand()%155 + 100;for(int i=0; i<templ[0].features.size(); i++){auto feat = templ[0].features[i];cv::circle(test_img, {feat.x+match.x, feat.y+match.y}, 2, randColor, -1);}cv::putText(test_img, to_string(int(round(match.similarity))),Point(match.x+r-10, match.y-3), FONT_HERSHEY_PLAIN, 2, randColor);cv::rectangle(test_img, {match.x, match.y}, {x, y}, randColor, 2);std::cout << "\nmatch.template_id: " << match.template_id << std::endl;std::cout << "match.similarity: " << match.similarity << std::endl;}imshow("img", test_img);waitKey(0);std::cout << "test end" << std::endl << std::endl;}}void MIPP_test(){std::cout << "MIPP tests" << std::endl;std::cout << "----------" << std::endl << std::endl;std::cout << "Instr. type: " << mipp::InstructionType << std::endl;std::cout << "Instr. full type: " << mipp::InstructionFullType << std::endl;std::cout << "Instr. version: " << mipp::InstructionVersion << std::endl;std::cout << "Instr. size: " << mipp::RegisterSizeBit << " bits" << std::endl;std::cout << "Instr. lanes: " << mipp::Lanes << std::endl;std::cout << "64-bit support: " << (mipp::Support64Bit ? "yes" : "no") << std::endl;std::cout << "Byte/word support: " << (mipp::SupportByteWord ? "yes" : "no") << std::endl;#ifndef has_max_int8_tstd::cout << "in this SIMD, int8 max is not inplemented by MIPP" << std::endl;#endif#ifndef has_shuff_int8_tstd::cout << "in this SIMD, int8 shuff is not inplemented by MIPP" << std::endl;#endifstd::cout << "----------" << std::endl << std::endl;}int main(){// scale_test("test");angle_test("test", true); // test or train// noise_test("test");return 0;}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。