├── README.txt ├── headers.h ├── main.cpp ├── model1.bmp ├── model1_dst1.bmp ├── model1_dst2.bmp ├── model1_src1.bmp ├── model1_src2.bmp ├── model2.bmp ├── model2_dst1.bmp ├── model2_dst2.bmp ├── model2_src1.bmp ├── model2_src2.bmp ├── model3.bmp ├── model3_dst1.bmp ├── model3_dst2.bmp ├── model3_dst3.bmp ├── model3_dst4.bmp ├── model3_dst5.bmp ├── model3_dst6.bmp ├── model3_src1.bmp ├── model3_src2.bmp ├── model3_src3.bmp ├── model3_src4.bmp ├── model3_src5.bmp ├── model3_src6.bmp ├── shapeMatcher.cpp └── shapeMatcher.h /README.txt: -------------------------------------------------------------------------------- 1 | # 2D-Shape-Match 2 | # shape matching for translation and rotation cases (Zoom cases is not included by now) 3 | # Zhang Yifei (yiphyzhang@126.com) 4 | 5 | 1. Introduction 6 | This program implements the 2d shapes matching algothrim for translation 7 | and rotation cases, based on OpenCV. Please sent questions, comments or 8 | bugs to Zhang Yifei(yiphyzhang@126.com) 9 | 10 | This software was developed/tested on Windows7 & visualStudio 2013. 11 | 12 | 2. License & Disclaimer 13 | Copyright @ 2018 Zhang Yifei(yiphyzhang@126.com) 14 | This software may be used for research purposes only. 15 | 16 | 3. Build and Run 17 | (1) Install OpenCV2.4.XX 18 | (2) Compile this project with visual Studio 2013. 19 | -------------------------------------------------------------------------------- /headers.h: -------------------------------------------------------------------------------- 1 | #ifndef HEADERS_H_ 2 | #define HEADERS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace std; 22 | using namespace cv; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include"shapeMatcher.h" 2 | 3 | void testMatchMultiModel1() 4 | { 5 | Mat model = imread("model1.bmp", CV_LOAD_IMAGE_GRAYSCALE); 6 | Mat src1 = imread("model1_src1.bmp", CV_LOAD_IMAGE_GRAYSCALE); 7 | Mat src2 = imread("model1_src2.bmp", CV_LOAD_IMAGE_GRAYSCALE); 8 | 9 | Mat dst1, dst2, dst3, dst4; 10 | string dstPath1 = "model1_dst1.bmp"; 11 | string dstPath2 = "model1_dst2.bmp"; 12 | 13 | int param0 = 15, param1 = 30, param2 = 50, param3 = 5; 14 | ShapeMatcher2d targetFinder; 15 | targetFinder.setEdgeParam(param0, param1, param2, param3); 16 | 17 | cout << endl << "Model2" << endl; 18 | 19 | clock_t ts, te; 20 | cout << "Image 1..."; ts = clock(); 21 | targetFinder.creatModel(model, 3, 0, 359); 22 | targetFinder.matchOverlap(src1, 0.7); 23 | targetFinder.drawRes(dst1); 24 | imwrite(dstPath1.c_str(), dst1); 25 | te = clock(); cout << " in " << te - ts << " ms" << endl; 26 | 27 | cout << "Image 2..."; ts = clock(); 28 | targetFinder.creatModel(model, 1, -10, 10); 29 | targetFinder.match(src2, 0.7); 30 | targetFinder.drawRes(dst2); 31 | imwrite(dstPath2.c_str(), dst2); 32 | te = clock(); cout << " in " << te - ts << " ms" << endl; 33 | 34 | return; 35 | } 36 | 37 | void testMatchMultiModel2() 38 | { 39 | Mat model = imread("model2.bmp", CV_LOAD_IMAGE_GRAYSCALE); 40 | Mat src1 = imread("model2_src1.bmp", CV_LOAD_IMAGE_GRAYSCALE); 41 | Mat src2 = imread("model2_src2.bmp", CV_LOAD_IMAGE_GRAYSCALE); 42 | 43 | Mat dst1, dst2, dst3, dst4; 44 | string dstPath1 = "model2_dst1.bmp"; 45 | string dstPath2 = "model2_dst2.bmp"; 46 | 47 | int param0 = 15, param1 = 30, param2 = 50, param3 = 5; 48 | ShapeMatcher2d targetFinder; 49 | targetFinder.setEdgeParam(param0, param1, param2, param3); 50 | 51 | cout << endl << "Model2" << endl; 52 | 53 | clock_t ts, te; 54 | cout << "Image 1..."; ts = clock(); 55 | targetFinder.creatModel(model, 1, 345, 359); 56 | targetFinder.matchOverlap(src1, 0.7); 57 | targetFinder.drawRes(dst1); 58 | imwrite(dstPath1.c_str(), dst1); 59 | te = clock(); cout << " in " << te - ts << " ms" << endl; 60 | 61 | cout << "Image 2..."; ts = clock(); 62 | targetFinder.creatModel(model, 1, 345, 359); 63 | targetFinder.matchOverlap(src2, 0.7); 64 | targetFinder.drawRes(dst2); 65 | imwrite(dstPath2.c_str(), dst2); 66 | te = clock(); cout << " in " << te - ts << " ms" << endl; 67 | 68 | return; 69 | } 70 | 71 | void testMatchMultiModel3() 72 | { 73 | Mat model = imread("model3.bmp", CV_LOAD_IMAGE_GRAYSCALE); 74 | Mat src1 = imread("model3_src1.bmp", CV_LOAD_IMAGE_GRAYSCALE); 75 | Mat src2 = imread("model3_src2.bmp", CV_LOAD_IMAGE_GRAYSCALE); 76 | Mat src3 = imread("model3_src3.bmp", CV_LOAD_IMAGE_GRAYSCALE); 77 | Mat src4 = imread("model3_src4.bmp", CV_LOAD_IMAGE_GRAYSCALE); 78 | Mat src5 = imread("model3_src5.bmp", CV_LOAD_IMAGE_GRAYSCALE); 79 | Mat src6 = imread("model3_src6.bmp", CV_LOAD_IMAGE_GRAYSCALE); 80 | 81 | Mat dst1, dst2, dst3, dst4, dst5, dst6; 82 | string dstPath1 = "model3_dst1.bmp"; 83 | string dstPath2 = "model3_dst2.bmp"; 84 | string dstPath3 = "model3_dst3.bmp"; 85 | string dstPath4 = "model3_dst4.bmp"; 86 | string dstPath5 = "model3_dst5.bmp"; 87 | string dstPath6 = "model3_dst6.bmp"; 88 | 89 | int param0 = 15, param1 = 30, param2 = 50, param3 = 3; 90 | ShapeMatcher2d targetFinder; 91 | targetFinder.setEdgeParam(param0, param1, param2, param3); 92 | 93 | cout << endl << "Model3" << endl; 94 | 95 | clock_t ts, te; 96 | cout << "Image 1..."; ts = clock(); 97 | targetFinder.creatModel(model, 1, 0, 10); 98 | targetFinder.match(src1, 0.7); 99 | targetFinder.drawRes(dst1); 100 | imwrite(dstPath1.c_str(), dst1); 101 | te = clock(); cout << " in " << te - ts << " ms" << endl; 102 | 103 | cout << "Image 2..."; ts = clock(); 104 | targetFinder.creatModel(model, 1, 0, 30); 105 | targetFinder.match(src2, 0.7); 106 | targetFinder.drawRes(dst2); 107 | imwrite(dstPath2.c_str(), dst2); 108 | te = clock(); cout << " in " << te - ts << " ms" << endl; 109 | 110 | cout << "Image 3..."; ts = clock(); 111 | targetFinder.creatModel(model, 1, 350, 360); 112 | targetFinder.match(src3, 0.7); 113 | targetFinder.drawRes(dst3); 114 | imwrite(dstPath3.c_str(), dst3); 115 | te = clock(); cout << " in " << te - ts << " ms" << endl; 116 | 117 | cout << "Image 4..."; ts = clock(); 118 | targetFinder.creatModel(model, 1, 270, 280); 119 | targetFinder.match(src4, 0.7); 120 | targetFinder.drawRes(dst4); 121 | imwrite(dstPath4.c_str(), dst4); 122 | te = clock(); cout << " in " << te - ts << " ms" << endl; 123 | 124 | cout << "Image 5..."; ts = clock(); 125 | targetFinder.creatModel(model, 1, 90, 120); 126 | targetFinder.match(src5, 0.7); 127 | targetFinder.drawRes(dst5); 128 | imwrite(dstPath5.c_str(), dst5); 129 | te = clock(); cout << " in " << te - ts << " ms" << endl; 130 | 131 | cout << "Image 6..."; ts = clock(); 132 | targetFinder.creatModel(model, 1, 180, 210); 133 | targetFinder.match(src6, 0.7); 134 | targetFinder.drawRes(dst6); 135 | imwrite(dstPath6.c_str(), dst6); 136 | te = clock(); cout << " in " << te - ts << " ms" << endl; 137 | 138 | return; 139 | } 140 | 141 | void main() 142 | { 143 | testMatchMultiModel1(); 144 | 145 | testMatchMultiModel2(); 146 | 147 | testMatchMultiModel3(); 148 | 149 | return; 150 | } 151 | -------------------------------------------------------------------------------- /model1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model1.bmp -------------------------------------------------------------------------------- /model1_dst1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model1_dst1.bmp -------------------------------------------------------------------------------- /model1_dst2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model1_dst2.bmp -------------------------------------------------------------------------------- /model1_src1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model1_src1.bmp -------------------------------------------------------------------------------- /model1_src2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model1_src2.bmp -------------------------------------------------------------------------------- /model2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model2.bmp -------------------------------------------------------------------------------- /model2_dst1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model2_dst1.bmp -------------------------------------------------------------------------------- /model2_dst2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model2_dst2.bmp -------------------------------------------------------------------------------- /model2_src1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model2_src1.bmp -------------------------------------------------------------------------------- /model2_src2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model2_src2.bmp -------------------------------------------------------------------------------- /model3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3.bmp -------------------------------------------------------------------------------- /model3_dst1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_dst1.bmp -------------------------------------------------------------------------------- /model3_dst2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_dst2.bmp -------------------------------------------------------------------------------- /model3_dst3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_dst3.bmp -------------------------------------------------------------------------------- /model3_dst4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_dst4.bmp -------------------------------------------------------------------------------- /model3_dst5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_dst5.bmp -------------------------------------------------------------------------------- /model3_dst6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_dst6.bmp -------------------------------------------------------------------------------- /model3_src1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_src1.bmp -------------------------------------------------------------------------------- /model3_src2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_src2.bmp -------------------------------------------------------------------------------- /model3_src3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_src3.bmp -------------------------------------------------------------------------------- /model3_src4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_src4.bmp -------------------------------------------------------------------------------- /model3_src5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_src5.bmp -------------------------------------------------------------------------------- /model3_src6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/model3_src6.bmp -------------------------------------------------------------------------------- /shapeMatcher.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yiphy/2D-Shape-Match/3fd5b3da4ec5909913760da947f69f3d9b455d39/shapeMatcher.cpp -------------------------------------------------------------------------------- /shapeMatcher.h: -------------------------------------------------------------------------------- 1 | 2 | /******************************************************************************************** 3 | # 2D - Shape - Match 4 | # shape matching for translation and rotation cases(Zoom cases is not included by now) 5 | # Zhang Yifei(yiphyzhang@126.com) 6 | 7 | 1. Introduction 8 | This program implements the 2d shapes matching algothrim for translation 9 | and rotation cases, based on OpenCV.Please sent questions, comments or 10 | bugs to Zhang Yifei(yiphyzhang@126.com) 11 | 12 | This software was developed / tested on Windows7 & visualStudio 2013. 13 | 14 | 2. License & Disclaimer 15 | Copyright @ 2018 Zhang Yifei(yiphyzhang@126.com) 16 | This software may be used for research purposes only. 17 | 18 | 3. Build and Run 19 | (1) Install OpenCV2.4.XX 20 | (2) Compile this project with visual Studio 2013. 21 | ********************************************************************************************/ 22 | 23 | #ifndef SHAPE_MATCHER_2D_H_ 24 | #define SHAPE_MATCHER_2D_H_ 25 | 26 | #include"headers.h" 27 | 28 | #define MAX_DETECT_NUM 100 29 | 30 | /** 31 | * Brief: target information 32 | * @param[0/1]: x,y: coordinate of target in 2d image 33 | * @param[2]: angle: rotation angle of the target in counterclockwise. 34 | * @param[3]: similarity: similarity of current coordinate and rotation angle. 35 | * Details: 36 | */ 37 | typedef struct _Target_Info 38 | { 39 | double x; 40 | double y; 41 | double angle; 42 | double similarity; 43 | }TargetInfo; 44 | 45 | /** 46 | * Brief: target information 47 | * @param[0]: nTargetsNumber: number of current targets. 48 | * @param[1]: tarInfo[MAX_DETECT_NUM]: detailed information of each target. MAX_DETECT_NUM is default set to be 100. 49 | * Details: 50 | */ 51 | typedef struct _Shape_Targets 52 | { 53 | int nTargetsNumber; 54 | TargetInfo tarInfo[MAX_DETECT_NUM]; 55 | }ShapeTargets; 56 | 57 | 58 | /** 59 | * Brief: target location and rotation detection for 2d images. 60 | 61 | This class may be used as below: 62 | 63 | 0. setEdgeParam(); 64 | 1. creatModel(); 65 | 2. match(); or matchOverlap(); 66 | 3. getTargets(); or drawRes(); 67 | 68 | * Details: 69 | */ 70 | class ShapeMatcher2d 71 | { 72 | public: 73 | ShapeMatcher2d(); 74 | 75 | /** 76 | * Brief: default parameters to extract edges. 77 | * @param[in] edgeParam0: bilateralFilter blur parameter, default set to be 15 78 | * @param[in] edgeParam1: canny edge parameter, default set to be 30 79 | * @param[in] edgeParam2: canny edge parameter, default set to be 50 80 | * @param[in] edgeParam3: dilate parameter in matching module, default set to be 5 81 | * Details: default parameters to extract edges of model and target image. 82 | */ 83 | ShapeMatcher2d(int edgeParam0, int edgeParam1, int edgeParam2, int edgeParam3) 84 | { 85 | m_iEdgeParam0 = edgeParam0; 86 | m_iEdgeParam1 = edgeParam1; 87 | m_iEdgeParam2 = edgeParam2; 88 | m_iEdgeParam3 = edgeParam3; 89 | } 90 | 91 | ~ShapeMatcher2d(); 92 | 93 | /** 94 | * Brief: default parameters to extract edges. 95 | * @param[in] edgeParam0: bilateralFilter blur parameter, default set to be 15 96 | * @param[in] edgeParam1: canny edge parameter, default set to be 30 97 | * @param[in] edgeParam2: canny edge parameter, default set to be 50 98 | * @param[in] edgeParam3: dilate parameter in matching module, default set to be 5 99 | * Details: default parameters to extract edges of model and target image. 100 | */ 101 | inline void setEdgeParam(int edgeParam0, int edgeParam1, int edgeParam2, int edgeParam3) 102 | { 103 | m_iEdgeParam0 = edgeParam0; 104 | m_iEdgeParam1 = edgeParam1; 105 | m_iEdgeParam2 = edgeParam2; 106 | m_iEdgeParam3 = edgeParam3; 107 | } 108 | 109 | /** 110 | * Brief: default parameters to creat models. 111 | * @param[in] src: original image to creat models. 112 | * @param[in] angleStep: step of angle, from start angle to end angle 113 | * @param[in] angleStart: start angle 114 | * @param[in] angleEnd: end angle 115 | * Details: angleStart must be smaller than angleEnd. But both paramters can be smaller than 0 or bigger than 360. 116 | * For example, (angleStart = -10 , angleEnd = 10) is OK. It's same as (angleStart = 350 , angleEnd = 370) 117 | */ 118 | bool creatModel(Mat src, double angleStep, double angleStart = 0, double angleEnd = 360); 119 | 120 | /** 121 | * Brief: match models within the dst image. Overlap cases are applicable. 122 | * @param[in] src: source images. CV_8UC1 123 | * @param[in] similarityThres: similarity biggers than this threshold will be recognized as target. 124 | * Details: This is recommended in overlap cases. But this may be sensitive to noises. 125 | */ 126 | bool matchOverlap(Mat src, double similarityThres = 0.5); 127 | 128 | /** 129 | * Brief: match models within the dst image. Overlap cases may not be applicable. 130 | * @param[in] src: source images. CV_8UC1 131 | * @param[in] similarityThres: similarity biggers than this threshold will be recognized as target. 132 | * Details: This is recommended in most cases. 133 | */ 134 | bool match(Mat src, double similarityThres = 0.5); 135 | 136 | /** 137 | * Brief: get targets number. 138 | * @param[out] return value. 139 | * Details: 140 | */ 141 | inline int getTargetsNumber(){ return m_stTargets.nTargetsNumber; } 142 | 143 | /** 144 | * Brief: get detection targets. 145 | * @param[out] return value. 146 | * Details: 147 | */ 148 | inline ShapeTargets getTargets(){ return m_stTargets; } 149 | 150 | /** 151 | * Brief: draw detection results on destination image. 152 | * @param[in&out] dst: destination images. will be translated into color SOURCE image. CV_8UC3 153 | * Details: 154 | */ 155 | void drawRes(Mat& dst); 156 | 157 | private: 158 | /** 159 | * Brief: rotate image in counterclockwise 160 | * Details: if src.rows==src.cols, isOriginalSize = true; else isOriginalSize = false. 161 | */ 162 | Mat rotateImg(Mat src, double angle, bool isOriginalSize = true); 163 | 164 | /** 165 | * Brief: only reserve non-zero pixel of src. 166 | * Details: cut pixels of zero intensity. only keep non-zero pixels of src and saved in dst. all CV_8UC1 167 | */ 168 | void cutMinImg(Mat src, Mat& dst); 169 | 170 | /** 171 | * Brief: get edge image of src. 172 | * Details: bilateralFilter -> canny -> threshold -> Exaggerate to diagonal size 173 | */ 174 | Mat getEdgeImg(Mat src); 175 | 176 | /** 177 | * Brief: cluster candidate targets to get peaks point. 178 | * Details: 179 | */ 180 | bool clusterAnalyze(vector>points, vector>& peaks, int disThres = 5, int numberThres = 1); 181 | 182 | void drawRes(Mat& dst, int xIdx, int yIdx, double angle, double value); 183 | 184 | void drawArrow(cv::Mat& img, cv::Point pStart, cv::Point pEnd, int len, int alpha, cv::Scalar& color, int thickness, int lineType); 185 | 186 | /** 187 | * Brief: set nTatgetNumber to be 0. 188 | * Details: 189 | */ 190 | void initialMatchedTargets(); 191 | 192 | /** 193 | * Brief shrink the angle to [0,360) 194 | * @param[in ]: angle 195 | * @param[out]: return angle 196 | * Details: if input 1.2 , return 1.2; if input -1.2 , return 358.8; if input 365.2, return 5.2; if input 723.4, return 3.4. 197 | */ 198 | double shrinkAngle(double angle); 199 | 200 | private: 201 | 202 | int m_iEdgeParam0; 203 | int m_iEdgeParam1; 204 | int m_iEdgeParam2; 205 | int m_iEdgeParam3; 206 | 207 | double m_dAngleStart; 208 | double m_dAngleEnd; 209 | double m_dAngleStep; 210 | 211 | int m_iModelWidth; 212 | int m_iModelHeight; 213 | 214 | int m_iModelActualWidth; 215 | int m_iModelActualHeight; 216 | Mat m_mSrc; 217 | 218 | vector> m_mMutiAngleModel; // 219 | 220 | ShapeTargets m_stTargets; 221 | }; 222 | 223 | #endif 224 | --------------------------------------------------------------------------------