├── .gitattributes ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── a0.bmp ├── main.cpp ├── paper.pdf ├── sampleCircle.bmp ├── sampleSquare.bmp ├── subPixelCal.cpp ├── subPixelCal.h ├── windowParam.cpp ├── windowParam.h └── zernikeMask.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 SuWeiQiang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | 4 | CFLAG=-I/usr/local/include -std=c++11 5 | LFLAG=-L/usr/local/lib 6 | 7 | LIB_OPENCV=-lopencv_calib3d -lopencv_core -lopencv_features2d\ 8 | -lopencv_photo -lopencv_imgproc -lopencv_legacy -lopencv_video\ 9 | -lopencv_videostab -lopencv_stitching -lopencv_superres\ 10 | -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_ocl\ 11 | -lopencv_ml -lopencv_nonfree -lopencv_objdetect -lopencv_contrib 12 | 13 | LFLAG+=$(LIB_OPENCV) 14 | LFLAG+=-lpthread 15 | 16 | GTK_FLAG=`pkg-config --cflags --libs gtk+-2.0 gthread-2.0` 17 | CFLAG+=$(GTK_FLAG) 18 | 19 | aim=demo 20 | test=image 21 | 22 | $(aim):main.o subPixelCal.o windowParam.o 23 | $(CXX) main.o subPixelCal.o windowParam.o -o $(aim) $(CFLAG) $(LFLAG) 24 | 25 | main.o:main.cpp 26 | $(CXX) -c main.cpp $(CFLAG) 27 | 28 | subPixelCal.o:subPixelCal.cpp subPixelCal.h zernikeMask.h 29 | $(CXX) -c subPixelCal.cpp $(CFLAG) 30 | 31 | windowParam.o:windowParam.cpp windowParam.h 32 | $(CXX) -c windowParam.cpp $(CFLAG) 33 | 34 | $(test):image.cpp 35 | $(CXX) image.cpp -o $(test) $(CFLAG) $(LFLAG) `pkg-config --cflags --libs gtk+-2.0 gthread-2.0` 36 | 37 | all: 38 | make $(aim) 39 | # make $(test) 40 | 41 | run: 42 | make $(aim) 43 | ./$(aim) 44 | clean: 45 | rm -rf *.exe *.o 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZernikeMoment_SubPixel_Detection 2 | ## feature 3 | - High precision: 0.005mm 4 | - A large amount of subpixel edge points 5 | - Complex edge area subpixel detection 6 | - interactive GUI by GTK Linux 7 | ## Installation 8 | ### For Linux 9 | If you are on Linux platform, please make sure that your device has the follow lib: 10 | > - Opencv 2.4.10 or higher 11 | > - GTK 2.0 12 | 13 | Because we also tested our code on Linux device, it is no doubt that you can achieve all the function of this demo on (or saay only on) Linux device.So if you want to use this code on Linux, it is really fortunate.But if you are a windows user, don't worry,please look down. 14 | ### For Windows 15 | You could still use the main algorithm rather than interactive GUI.You only need to download this repository and add the algorithm main code :`subPixelCal.cpp`, `subPixelCal.h`, `zernikeMask.h` to your own C++ project.The following function can be call in your own project to detect the size of square or circle: 16 | 17 | ```c++ 18 | ZerResult CalDistanceSquare(Mat& matRoi, double rto = MMPERPIXEL, 19 | int drawColor = WHITE, bool ifmedianBlur=YESMEDIANBLUR, 20 | int cannyL = 150, int cannyH = 200, int cannyCore = 3, 21 | int nbsize = N, Point2i VHtime = Point2i(4, 4), 22 | int ZerBgrL = 10, int ZerBgrH = 50 23 | 24 | ); 25 | ZerResultCir CalDistanceCircle(Mat& matRoi, double rto = MMPERPIXEL, 26 | int drawColor = WHITE, bool ifmedianBlur = YESMEDIANBLUR, 27 | int cannyL = 150, int cannyH = 200, int cannyCore = 3, 28 | int nbsize = N, Point2i VHtime = Point2i(4, 4), 29 | int ZerBgrL = 10, int ZerBgrH = 50 30 | 31 | ); 32 | ``` 33 | 34 | ## Usage 35 | 36 | ### Main interface 37 | ![image](https://github.com/swq123459/swq123456-readmePicture/blob/master/subpixel_pic/main-origin.png?raw=true) 38 | ### Child interface 39 | ![image](https://github.com/swq123459/swq123456-readmePicture/blob/master/subpixel_pic/main-params.png?raw=true) 40 | 41 | ### Operation guide 42 | 43 | - As show in the figure, the main interface of the program consists of two parts: the upper part consists of various types of control buttons and measurement information display area, etc., and the lower part is the display area of measurement result. 44 | To click the ***"Open Camera"*** button,we could turn on the camera, you can take a picture as a measure target by clicking the ***"Capture"*** .You could see the picture you tacke shows on the window. If you click the ***"Close Camera"*** , the camera will be closed. 45 | Or you could click ***"Local Image"*** to select an image in your computer to test the program. Here we provide several standard image for you to test. 46 | - Click the ***"Parameter Setting"*** button to pop up the parameter setting interface as shown in figure. In this interface, you can modify the parameters that the core algorithm depend on. 47 | - Checking "Use Example" box to enter the ***"demo mode"*** which allow you to roughly experience this algorithm. In this mode, by click "Squre detect" or "Circle detect" button, program will detect the size of target squre or circle and output the result in the white text area above the main interface. 48 | - When the input image is not a pure gray background, click the ***"Square-dectect"*** button to enter the parallel line spacing detection process, and pop up the parallel line selection form. At this time, use the mouse to select two parallel lines in the picture in the form. Pressing the ***Esc*** button will start measuring the parallel line spacing and the measurement will be displayed in the white text area. When the image area to be measured is not a pure gray background, click the Circle-dectect button to enter the circle size measurement process, and pop up the circle selection form. At this time, select a circle with the mouse frame to select the circle in the form image, and then Pressing the ***Esc*** button will start the circle size measurement, and the measurement results (radius, center position) will be displayed in the white text area. 49 | 50 | 51 | ## Some results 52 | 53 | ![image](https://github.com/swq123459/swq123456-readmePicture/blob/master/subpixel_pic/sample.png?raw=true) 54 | ![image](https://github.com/swq123459/swq123456-readmePicture/blob/master/subpixel_pic/main-origin.png?raw=true) 55 | ## How it Works 56 | - my paper: SUBPIXEL EDGE DETECTION BASED ON EDGE GRADIENT DIRECTIONAL INTERPOLATION AND ZERNIKE MOMENT 57 | https://scholar.archive.org/work/lbr7c3kj2vcnbl6y56px5zn2cu/access/wayback/http://dpi-proceedings.com/index.php/dtcse/article/download/24488/24120 58 | or dowlownd from my rep which names paper 59 | 60 | 61 | -------------------------------------------------------------------------------- /a0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq123459/ZernikeMoment_SubPixel_Detection/82ea167db6985a1fa2fc1bf11cf9d6ca91edbcb3/a0.bmp -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "zernikeMask.h" 7 | #include "subPixelCal.h" 8 | 9 | #include "windowParam.h" 10 | 11 | 12 | using namespace cv; 13 | 14 | const char* WndName_CAM = "Video"; 15 | const char* WndName_CAP = "Captured"; 16 | 17 | GThread* Cam_Thread; 18 | VideoCapture cap; 19 | 20 | Mat cam_frame; 21 | Mat captured_frame; 22 | GtkWidget *image_captured; 23 | GtkWidget *global_textView; 24 | GtkTextBuffer *global_textBuff; 25 | 26 | 27 | GtkWidget *ImageSelect; 28 | GtkWidget *entry_pix_mm; 29 | double pixel_mm_ratio = MMPERPIXEL; 30 | #define MMPERPIXEL_STR "0.0145503" 31 | 32 | ParamSet params; 33 | 34 | bool use_example = false; 35 | volatile static bool keep_Camera_Open=false; 36 | 37 | void* CamCtl(void*); 38 | 39 | void on_btn_openCam_clicked(GtkWidget *button, gpointer userdata); 40 | void on_btn_closeCam_clicked(GtkWidget *button, gpointer userdata); 41 | void on_btn_capture_clicked(GtkWidget *button, gpointer userdata); 42 | 43 | void on_btn_Square_clicked(GtkWidget *button, gpointer userdata); 44 | void on_btn_Circle_clicked(GtkWidget *button, gpointer userdata); 45 | 46 | void on_btn_chooseImage_clicked(GtkWidget *button, gpointer userdata); 47 | void on_btn_default_pix_mm_clicked(GtkWidget *button, gpointer userdata); 48 | 49 | void on_btn_openParamPanel_clicked(GtkWidget *button, gpointer userData); 50 | 51 | void on_checkbox_useExample_toggle(GtkWidget *check_button, gpointer data); 52 | 53 | void on_menuitem_params_actived(GtkWidget *widget, GdkEvent *event); 54 | 55 | 56 | void ShowMessage(const char* message); 57 | void ShowMat(Mat& src); 58 | 59 | 60 | int main(int argc,char *argv[]) 61 | { 62 | 63 | GtkWidget *window; 64 | 65 | GtkWidget *Vlayout_main; 66 | GtkWidget *Hlayout_up; 67 | GtkWidget *Vlayout_cameraCtl; 68 | GtkWidget *Vlayout_processCtl; 69 | GtkWidget *Hlayout_processCtl_part1; 70 | 71 | GtkWidget *btn_openCam; 72 | GtkWidget *btn_closeCam; 73 | GtkWidget *btn_capture; 74 | 75 | GtkWidget *btn_chooseImage; 76 | 77 | GtkWidget *btn_Square; 78 | GtkWidget *btn_Circle; 79 | 80 | GtkWidget *textView; 81 | 82 | GtkWidget *label_pix_mm; 83 | GtkWidget *btn_default_pix_mm; 84 | GtkWidget *btn_openParamPanel; 85 | 86 | GtkWidget *checkbox_useExample; 87 | checkbox_useExample = gtk_check_button_new_with_label("Use Example"); 88 | g_signal_connect(GTK_OBJECT(checkbox_useExample),"toggled",G_CALLBACK(on_checkbox_useExample_toggle),NULL); 89 | 90 | 91 | //menu initial 92 | GtkWidget *menubar,*menu,*menuitem_setting; 93 | menubar=gtk_menu_bar_new(); 94 | 95 | menuitem_setting = gtk_menu_item_new_with_label("设置"); 96 | 97 | gtk_menu_bar_append(GTK_MENU_BAR(menubar),menuitem_setting); 98 | gtk_widget_show(menuitem_setting); 99 | 100 | menu=gtk_menu_new(); 101 | gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem_setting),menu); 102 | 103 | GtkWidget *menuitem_params; 104 | menuitem_params=gtk_menu_item_new_with_label("参数设置"); 105 | 106 | gtk_menu_append(GTK_MENU(menu),menuitem_params); 107 | g_signal_connect(GTK_MENU_ITEM(menuitem_params),"activate",G_CALLBACK(on_menuitem_params_actived),NULL); 108 | 109 | 110 | image_captured = gtk_image_new_from_file("./gray.png"); 111 | 112 | 113 | gtk_init(&argc,&argv); 114 | 115 | 116 | //window initial 117 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 118 | 119 | gtk_window_set_title(GTK_WINDOW(window),"Demo"); 120 | gtk_window_set_default_size(GTK_WINDOW(window),640,540); 121 | gtk_container_set_border_width(GTK_CONTAINER(window),10); 122 | 123 | g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit),NULL); 124 | 125 | //parameters window initial 126 | Initial_WindowParam(¶ms); 127 | 128 | 129 | //layout initial 130 | Vlayout_main = gtk_vbox_new(FALSE,0); 131 | gtk_container_add(GTK_CONTAINER(window),Vlayout_main); 132 | 133 | Hlayout_up = gtk_hbox_new(FALSE,0); 134 | Vlayout_cameraCtl = gtk_vbox_new(FALSE,0); 135 | Vlayout_processCtl = gtk_vbox_new(FALSE,0); 136 | Hlayout_processCtl_part1 = gtk_hbox_new(FALSE,0); 137 | 138 | 139 | //widgets initial 140 | 141 | textView = gtk_text_view_new(); 142 | global_textView = textView; 143 | ShowMessage("Camera Closed"); 144 | 145 | entry_pix_mm = gtk_entry_new(); 146 | gtk_entry_set_text(GTK_ENTRY(entry_pix_mm),MMPERPIXEL_STR); 147 | label_pix_mm = gtk_label_new("单位像素对应毫米值"); 148 | 149 | btn_openCam = gtk_button_new_with_label("Open Camera"); 150 | g_signal_connect(G_OBJECT(btn_openCam),"clicked",G_CALLBACK(on_btn_openCam_clicked),(gpointer)NULL); 151 | 152 | btn_closeCam = gtk_button_new_with_label("Close Camera"); 153 | g_signal_connect(G_OBJECT(btn_closeCam),"clicked",G_CALLBACK(on_btn_closeCam_clicked),(gpointer)NULL); 154 | 155 | btn_capture = gtk_button_new_with_label("Capture"); 156 | g_signal_connect(G_OBJECT(btn_capture),"clicked",G_CALLBACK(on_btn_capture_clicked),(gpointer)NULL); 157 | 158 | btn_Square = gtk_button_new_with_label("Square-detect"); 159 | g_signal_connect(G_OBJECT(btn_Square),"clicked",G_CALLBACK(on_btn_Square_clicked),(gpointer)NULL); 160 | 161 | btn_Circle = gtk_button_new_with_label("Circle-detect"); 162 | g_signal_connect(G_OBJECT(btn_Circle),"clicked",G_CALLBACK(on_btn_Circle_clicked),(gpointer)NULL); 163 | 164 | btn_chooseImage = gtk_button_new_with_label("本地图片"); 165 | g_signal_connect(G_OBJECT(btn_chooseImage),"clicked",G_CALLBACK(on_btn_chooseImage_clicked),(gpointer)NULL); 166 | 167 | btn_default_pix_mm = gtk_button_new_with_label("default"); 168 | g_signal_connect(G_OBJECT(btn_default_pix_mm),"clicked",G_CALLBACK(on_btn_default_pix_mm_clicked),(gpointer)NULL); 169 | 170 | btn_openParamPanel = gtk_button_new_with_label("参数设置"); 171 | g_signal_connect(G_OBJECT(btn_openParamPanel),"clicked",G_CALLBACK(on_btn_openParamPanel_clicked),(gpointer)NULL); 172 | 173 | 174 | //add widgets to layout 175 | gtk_box_pack_start(GTK_BOX(Vlayout_main),menubar,FALSE,FALSE,3); 176 | gtk_box_pack_start(GTK_BOX(Vlayout_main),Hlayout_up,FALSE,TRUE,3); 177 | gtk_box_pack_start(GTK_BOX(Vlayout_main),image_captured,FALSE,TRUE,3); 178 | 179 | gtk_box_pack_start(GTK_BOX(Hlayout_up),Vlayout_cameraCtl,FALSE,FALSE,3); 180 | gtk_box_pack_start(GTK_BOX(Hlayout_up),Vlayout_processCtl,TRUE,TRUE,3); 181 | 182 | gtk_box_pack_start(GTK_BOX(Vlayout_cameraCtl),btn_openCam,FALSE,TRUE,3); 183 | gtk_box_pack_start(GTK_BOX(Vlayout_cameraCtl),btn_closeCam,FALSE,TRUE,3); 184 | gtk_box_pack_start(GTK_BOX(Vlayout_cameraCtl),btn_capture,FALSE,TRUE,3); 185 | 186 | gtk_box_pack_start(GTK_BOX(Vlayout_cameraCtl),btn_Square,FALSE,TRUE,3); 187 | gtk_box_pack_start(GTK_BOX(Vlayout_cameraCtl),btn_Circle,FALSE,TRUE,3); 188 | 189 | gtk_box_pack_start(GTK_BOX(Vlayout_cameraCtl),checkbox_useExample,FALSE,TRUE,3); 190 | 191 | 192 | gtk_box_pack_start(GTK_BOX(Vlayout_processCtl),textView,TRUE,TRUE,3); 193 | gtk_box_pack_start(GTK_BOX(Vlayout_processCtl),Hlayout_processCtl_part1,FALSE,FALSE,3); 194 | gtk_box_pack_start(GTK_BOX(Hlayout_processCtl_part1),btn_chooseImage,FALSE,FALSE,3); 195 | gtk_box_pack_start(GTK_BOX(Hlayout_processCtl_part1),btn_openParamPanel,FALSE,FALSE,3); 196 | 197 | 198 | gtk_box_pack_end(GTK_BOX(Hlayout_processCtl_part1),btn_default_pix_mm,FALSE,FALSE,3); 199 | gtk_box_pack_end(GTK_BOX(Hlayout_processCtl_part1),entry_pix_mm,FALSE,FALSE,3); 200 | gtk_box_pack_end(GTK_BOX(Hlayout_processCtl_part1),label_pix_mm,FALSE,FALSE,3); 201 | 202 | 203 | 204 | //show window and launch thread 205 | gtk_widget_show_all(window); 206 | 207 | gdk_threads_init(); 208 | 209 | //Cam_Thread = g_thread_create(CamCtl,NULL,FALSE,NULL); 210 | Cam_Thread = g_thread_new("Cam_Thread",CamCtl,NULL); 211 | 212 | gdk_threads_enter(); 213 | gtk_main(); 214 | gdk_threads_leave(); 215 | 216 | return 0; 217 | } 218 | 219 | void ShowMessage(const char* message){ 220 | // GtkTextIter end; 221 | GtkTextBuffer* buff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(global_textView)); 222 | //gtk_text_buffer_get_end_iter(buff,&end); 223 | gtk_text_buffer_set_text(buff,message,-1); 224 | // gtk_text_buffer_insert(buff,&end,"Camera Opened",-1); 225 | } 226 | 227 | void ShowMat(Mat& src){ 228 | if(!src.data) 229 | return; 230 | Mat scaled_src = src.clone(); 231 | double ratio = 480.0 / (double)src.rows; 232 | 233 | if(ratio > (640.0 / (double)src.cols)) 234 | ratio = 640.0 / (double)src.cols; 235 | 236 | int new_cols = (int) ((double)src.cols * ratio); 237 | int new_rows = (int) ((double)src.rows * ratio); 238 | 239 | std::cout<<"ratio = "<ok_button),"clicked",GTK_SIGNAL_FUNC(OpenImage),NULL); 322 | gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(ImageSelect)->cancel_button),"clicked",GTK_SIGNAL_FUNC(OpenImage_Cancel),NULL); 323 | gtk_widget_show(ImageSelect); 324 | } 325 | 326 | void on_btn_default_pix_mm_clicked(GtkWidget *button, gpointer userdata){ 327 | gtk_entry_set_text(GTK_ENTRY(entry_pix_mm),MMPERPIXEL_STR); 328 | pixel_mm_ratio = MMPERPIXEL; 329 | } 330 | 331 | void on_btn_openParamPanel_clicked(GtkWidget *button, gpointer userData){ 332 | Show_WindowParam(); 333 | } 334 | 335 | void on_btn_Square_clicked(GtkWidget *button, gpointer userdata){ 336 | 337 | ShowMessage("矩形对边距离测量开始\n请先用鼠标框选图中两条矩形的平行边,再按下Esc按键"); 338 | Mat matRoi; 339 | ZerResult result; 340 | char disp_buf[1024]={'\0'}; 341 | 342 | string ratio = gtk_entry_get_text(GTK_ENTRY(entry_pix_mm)); 343 | double tmp = atof(ratio.c_str()); 344 | if(tmp!=0 && tmp!=HUGE_VAL && tmp!=HUGE_VALF) 345 | pixel_mm_ratio = tmp; 346 | 347 | if(use_example){ 348 | matRoi = imread("sampleSquare.bmp", 0); 349 | if(!matRoi.data) 350 | { 351 | ShowMessage("Failed to open \"sampleSquare.bmp\""); 352 | return; 353 | } 354 | } 355 | else{ 356 | matRoi = captured_frame.clone(); 357 | if(!matRoi.data) 358 | { 359 | ShowMessage("Please capture a new picture"); 360 | return; 361 | } 362 | 363 | } 364 | 365 | Point2i p = Point2i(params.VScale,params.HScale); 366 | result = CalDistanceSquare(matRoi,pixel_mm_ratio,params.DrawColor,params.useMedium,params.cannyL,params.cannyH,params.cannyCore,\ 367 | params.neighborSize,p,params.ZerBgrL,params.ZerBgrH); 368 | 369 | sprintf(disp_buf,"测量结果:\n对边距离-像素: %lf pix\n对边距离-毫米: %lf mm",\ 370 | result.distance_pixel,result.distance_mm 371 | ); 372 | 373 | ShowMessage(disp_buf); 374 | ShowMat(result.matedge); 375 | 376 | destroyAllWindows(); 377 | } 378 | 379 | void on_btn_Circle_clicked(GtkWidget *button, gpointer userdata) 380 | { 381 | ShowMessage("圆尺寸测量开始\n请先用鼠标框选图中待测量的圆,再按下Esc按键"); 382 | Mat matRoi; 383 | ZerResultCir resultCir; 384 | char disp_buf[1024] = {'\0'}; 385 | 386 | string ratio = gtk_entry_get_text(GTK_ENTRY(entry_pix_mm)); 387 | double tmp = atof(ratio.c_str()); 388 | if(tmp!=0 && tmp!=HUGE_VAL && tmp!=HUGE_VALF) 389 | pixel_mm_ratio = tmp; 390 | 391 | if(use_example){ 392 | matRoi = imread("sampleCircle.bmp", 0); 393 | if(!matRoi.data) 394 | { 395 | ShowMessage("Failed to open \"sampleCircle.bmp\""); 396 | return; 397 | } 398 | } 399 | else{ 400 | matRoi = captured_frame.clone(); 401 | if(!matRoi.data) 402 | { 403 | ShowMessage("Please capture a new picture"); 404 | return; 405 | } 406 | 407 | } 408 | Point2i p = Point2i(params.VScale,params.HScale); 409 | resultCir = CalDistanceCircle(matRoi,pixel_mm_ratio,params.DrawColor,params.useMedium,params.cannyL,params.cannyH,params.cannyCore,\ 410 | params.neighborSize,p,params.ZerBgrL,params.ZerBgrH); 411 | 412 | sprintf(disp_buf,"测量结果:\n半径: %lf [pixel]\n半径: %lf [mm]\n\n圆心: (%lf , %lf) [pixel]\n圆心: (%lf , %lf)[mm]",\ 413 | resultCir.radius_pixel,resultCir.radius_mm,\ 414 | resultCir.centerPoint_pixel.x,resultCir.centerPoint_pixel.y,\ 415 | resultCir.centerPoint_mm.x,resultCir.centerPoint_mm.y 416 | ); 417 | 418 | ShowMessage(disp_buf); 419 | ShowMat(resultCir.matedge); 420 | 421 | destroyAllWindows(); 422 | } 423 | 424 | void on_menuitem_params_actived(GtkWidget *widget, GdkEvent *event) 425 | { 426 | Show_WindowParam(); 427 | } 428 | 429 | void* CamCtl(void*){ 430 | 431 | while(true){ 432 | if(!keep_Camera_Open) 433 | usleep(10000); 434 | 435 | while(keep_Camera_Open) 436 | { 437 | gdk_threads_enter(); 438 | cap >> cam_frame; 439 | if(cam_frame.data) 440 | imshow(WndName_CAM,cam_frame); 441 | gdk_threads_leave(); 442 | usleep(30000); 443 | } 444 | } 445 | 446 | 447 | cap.release(); 448 | } 449 | -------------------------------------------------------------------------------- /paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq123459/ZernikeMoment_SubPixel_Detection/82ea167db6985a1fa2fc1bf11cf9d6ca91edbcb3/paper.pdf -------------------------------------------------------------------------------- /sampleCircle.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq123459/ZernikeMoment_SubPixel_Detection/82ea167db6985a1fa2fc1bf11cf9d6ca91edbcb3/sampleCircle.bmp -------------------------------------------------------------------------------- /sampleSquare.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq123459/ZernikeMoment_SubPixel_Detection/82ea167db6985a1fa2fc1bf11cf9d6ca91edbcb3/sampleSquare.bmp -------------------------------------------------------------------------------- /subPixelCal.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq123459/ZernikeMoment_SubPixel_Detection/82ea167db6985a1fa2fc1bf11cf9d6ca91edbcb3/subPixelCal.cpp -------------------------------------------------------------------------------- /subPixelCal.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq123459/ZernikeMoment_SubPixel_Detection/82ea167db6985a1fa2fc1bf11cf9d6ca91edbcb3/subPixelCal.h -------------------------------------------------------------------------------- /windowParam.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "windowParam.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | const char* default_cannyl_str = "150"; 11 | const char* default_cannyh_str = "200"; 12 | 13 | const char* default_ZerBgrL_str = "10"; 14 | const char* default_ZerGrrH_str = "50"; 15 | 16 | const char* default_cannyCore_str = "3"; 17 | const char* default_drawColor_str = "255"; 18 | const char* default_neighborSize_str = "7"; 19 | 20 | const char* default_HScale_str = "4"; 21 | const char* default_VScale_str = "4"; 22 | 23 | const bool default_useMedium = true; 24 | 25 | ParamSet *_params; 26 | GtkWidget* windowParam; 27 | 28 | GtkWidget *Vlayout_main; 29 | GtkWidget *Hlayout_l1; 30 | GtkWidget *Hlayout_l2; 31 | GtkWidget *Hlayout_l3; 32 | GtkWidget *Hlayout_l4; 33 | GtkWidget *Hlayout_l5; 34 | 35 | GtkWidget *tableLayout_main; 36 | 37 | GtkWidget *btn_apply; 38 | GtkWidget *btn_cancel; 39 | GtkWidget *btn_default; 40 | 41 | GtkWidget *labe_cannyL; 42 | GtkWidget *labe_cannyH; 43 | GtkWidget *labe_cannyCore; 44 | GtkWidget *labe_ZerBgrL; 45 | GtkWidget *labe_ZerBgrH; 46 | GtkWidget *label_drawColor; 47 | GtkWidget *label_neighborSize; 48 | GtkWidget *label_VScale; 49 | GtkWidget *label_HScale; 50 | 51 | GtkWidget *entry_cannyL; 52 | GtkWidget *entry_cannyH; 53 | GtkWidget *entry_cannyCore; 54 | GtkWidget *entry_ZerBgrL; 55 | GtkWidget *entry_ZerBgrH; 56 | GtkWidget *entry_drawColor; 57 | GtkWidget *entry_neighborSize; 58 | GtkWidget *entry_VScale; 59 | GtkWidget *entry_HScale; 60 | 61 | 62 | GtkWidget *checkBox_meida; 63 | 64 | void Initial_WindowParam(ParamSet *ext_params){ 65 | 66 | windowParam = gtk_window_new(GTK_WINDOW_TOPLEVEL); 67 | 68 | gtk_window_set_title(GTK_WINDOW(windowParam),"参数设置"); 69 | gtk_window_set_default_size(GTK_WINDOW(windowParam),200,200); 70 | gtk_container_set_border_width(GTK_CONTAINER(windowParam),10); 71 | 72 | //layout initial 73 | tableLayout_main = gtk_table_new(9,6,TRUE); 74 | gtk_container_add(GTK_CONTAINER(windowParam),tableLayout_main); 75 | 76 | //widgets initial 77 | btn_apply = gtk_button_new_with_label("应用修改"); 78 | btn_cancel = gtk_button_new_with_label("取消修改"); 79 | btn_default = gtk_button_new_with_label("恢复默认"); 80 | 81 | checkBox_meida = gtk_check_button_new_with_label("是否中值滤波"); 82 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkBox_meida),TRUE); 83 | g_signal_connect(GTK_OBJECT(checkBox_meida),"toggled",G_CALLBACK(on_checkBox_meida_toggle),NULL); 84 | 85 | entry_cannyL = gtk_entry_new(); 86 | entry_cannyH = gtk_entry_new(); 87 | entry_cannyCore = gtk_entry_new(); 88 | entry_ZerBgrL = gtk_entry_new(); 89 | entry_ZerBgrH = gtk_entry_new(); 90 | entry_drawColor = gtk_entry_new(); 91 | entry_neighborSize = gtk_entry_new(); 92 | entry_VScale = gtk_entry_new(); 93 | entry_HScale = gtk_entry_new(); 94 | //高低 95 | labe_cannyL = gtk_label_new("Canny低阈值"); 96 | labe_cannyH = gtk_label_new("Canny高阈值"); 97 | labe_cannyCore = gtk_label_new("Canny核尺寸(odd)"); 98 | labe_ZerBgrL = gtk_label_new("边缘背景低阈值"); 99 | labe_ZerBgrH = gtk_label_new("边缘背景高阈值"); 100 | label_drawColor = gtk_label_new("画笔颜色 [0-255]"); 101 | label_neighborSize = gtk_label_new("边缘邻域尺寸(odd)"); 102 | label_VScale = gtk_label_new("垂直缩放尺度"); 103 | label_HScale = gtk_label_new("水平缩放尺度"); 104 | 105 | 106 | //connect signals and handler 107 | g_signal_connect(G_OBJECT(btn_apply),"clicked",G_CALLBACK(on_btn_apply_clicked),(gpointer)NULL); 108 | g_signal_connect(G_OBJECT(btn_cancel),"clicked",G_CALLBACK(on_btn_cancel_clicked),(gpointer)NULL); 109 | g_signal_connect(G_OBJECT(btn_default),"clicked",G_CALLBACK(on_btn_default_clicked),(gpointer)NULL); 110 | 111 | //add widgets to layouts 112 | 113 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),labe_cannyL, 0,3,0,1); 114 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),entry_cannyL, 3,6,0,1); 115 | 116 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),labe_cannyH, 0,3,1,2); 117 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),entry_cannyH, 3,6,1,2); 118 | 119 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),labe_cannyCore, 0,3,2,3); 120 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),entry_cannyCore, 3,6,2,3); 121 | 122 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),labe_ZerBgrL, 0,3,3,4); 123 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),entry_ZerBgrL, 3,6,3,4); 124 | 125 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),labe_ZerBgrH, 0,3,4,5); 126 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),entry_ZerBgrH, 3,6,4,5); 127 | 128 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),label_neighborSize, 0,3,5,6); 129 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),entry_neighborSize, 3,6,5,6); 130 | 131 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),label_drawColor, 0,3,6,7); 132 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),entry_drawColor, 3,6,6,7); 133 | 134 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),label_VScale, 0,3,7,8); 135 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),entry_VScale, 3,6,7,8); 136 | 137 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),label_HScale, 0,3,8,9); 138 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),entry_HScale, 3,6,8,9); 139 | 140 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),checkBox_meida, 3,6,9,10); 141 | 142 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),btn_apply, 0,2,10,11); 143 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),btn_cancel, 2,4,10,11); 144 | gtk_table_attach_defaults(GTK_TABLE(tableLayout_main),btn_default, 4,6,10,11); 145 | 146 | //params setting 147 | _params = ext_params; 148 | Use_DefaultParams(_params); 149 | Fill_DefaultParams(); 150 | 151 | } 152 | 153 | void Show_WindowParam() 154 | { 155 | FillParamsToView(_params); 156 | gtk_widget_show_all(windowParam); 157 | } 158 | 159 | void Hide_WindowParam(){ 160 | ; 161 | } 162 | 163 | 164 | /* 165 | ZerResult CalDistanceSquare(Mat& matRoi, double rto = MMPERPIXEL, 166 | int drawColor = WHITE, bool ifmedianBlur=YESMEDIANBLUR, 167 | int cannyL = 150, int cannyH = 200, int cannyCore = 3, 168 | int nbsize = N, Point2i VHtime = Point2i(4, 4), 169 | int ZerBgrL = 10, int ZerBgrH = 50 170 | 171 | ); 172 | ZerResultCir CalDistanceCircle(Mat& matRoi, double rto = MMPERPIXEL, 173 | int drawColor = WHITE, bool ifmedianBlur = YESMEDIANBLUR, 174 | int cannyL = 150, int cannyH = 200, int cannyCore = 3, 175 | int nbsize = N, Point2i VHtime = Point2i(4, 4), 176 | int ZerBgrL = 10, int ZerBgrH = 50 177 | 178 | ); 179 | */ 180 | 181 | 182 | void Fill_DefaultParams(){ 183 | gtk_entry_set_text(GTK_ENTRY(entry_cannyL), default_cannyl_str); 184 | gtk_entry_set_text(GTK_ENTRY(entry_cannyH), default_cannyh_str); 185 | gtk_entry_set_text(GTK_ENTRY(entry_ZerBgrL), default_ZerBgrL_str); 186 | gtk_entry_set_text(GTK_ENTRY(entry_ZerBgrH), default_ZerGrrH_str); 187 | gtk_entry_set_text(GTK_ENTRY(entry_cannyCore), default_cannyCore_str); 188 | gtk_entry_set_text(GTK_ENTRY(entry_drawColor), default_drawColor_str); 189 | gtk_entry_set_text(GTK_ENTRY(entry_neighborSize), default_neighborSize_str); 190 | gtk_entry_set_text(GTK_ENTRY(entry_VScale), default_VScale_str); 191 | gtk_entry_set_text(GTK_ENTRY(entry_HScale), default_HScale_str); 192 | } 193 | 194 | void Use_DefaultParams(ParamSet* params){ 195 | params->cannyL = 150; 196 | params->cannyH = 200; 197 | params->ZerBgrL = 10; 198 | params->ZerBgrH = 50; 199 | params->cannyCore = 3; 200 | params->DrawColor = 255; 201 | params->neighborSize = 7; 202 | params->VScale = 4; 203 | params->HScale = 4; 204 | params->useMedium = true; 205 | } 206 | 207 | void FillParamsToView(ParamSet *params){ 208 | 209 | char buffer[24]; 210 | 211 | memset(buffer,'\0',24); 212 | sprintf(buffer,"%d",params->cannyL); 213 | gtk_entry_set_text(GTK_ENTRY(entry_cannyL), buffer); 214 | 215 | memset(buffer,'\0',24); 216 | sprintf(buffer,"%d",params->cannyH); 217 | gtk_entry_set_text(GTK_ENTRY(entry_cannyH), buffer); 218 | 219 | memset(buffer,'\0',24); 220 | sprintf(buffer,"%d",params->ZerBgrL); 221 | gtk_entry_set_text(GTK_ENTRY(entry_ZerBgrL), buffer); 222 | 223 | memset(buffer,'\0',24); 224 | sprintf(buffer,"%d",params->ZerBgrH); 225 | gtk_entry_set_text(GTK_ENTRY(entry_ZerBgrH), buffer); 226 | 227 | memset(buffer,'\0',24); 228 | sprintf(buffer,"%d",params->cannyCore); 229 | gtk_entry_set_text(GTK_ENTRY(entry_cannyCore), buffer); 230 | 231 | memset(buffer,'\0',24); 232 | sprintf(buffer,"%d",params->neighborSize); 233 | gtk_entry_set_text(GTK_ENTRY(entry_neighborSize), buffer); 234 | 235 | memset(buffer,'\0',24); 236 | sprintf(buffer,"%d",params->DrawColor); 237 | gtk_entry_set_text(GTK_ENTRY(entry_drawColor), buffer); 238 | 239 | memset(buffer,'\0',24); 240 | sprintf(buffer,"%d",params->VScale); 241 | gtk_entry_set_text(GTK_ENTRY(entry_VScale), buffer); 242 | 243 | memset(buffer,'\0',24); 244 | sprintf(buffer,"%d",params->HScale); 245 | gtk_entry_set_text(GTK_ENTRY(entry_HScale), buffer); 246 | } 247 | 248 | void SetParamsFromView(ParamSet* params){ 249 | 250 | string cannyL_str = gtk_entry_get_text(GTK_ENTRY(entry_cannyL)); 251 | string cannyH_str = gtk_entry_get_text(GTK_ENTRY(entry_cannyH)); 252 | string ZerBgrL_str = gtk_entry_get_text(GTK_ENTRY(entry_ZerBgrL)); 253 | string ZerBgrH_str = gtk_entry_get_text(GTK_ENTRY(entry_ZerBgrH)); 254 | string cannyCore_str = gtk_entry_get_text(GTK_ENTRY(entry_cannyCore)); 255 | string neighborSize_str = gtk_entry_get_text(GTK_ENTRY(entry_neighborSize)); 256 | string drawColor_str = gtk_entry_get_text(GTK_ENTRY(entry_drawColor)); 257 | string vscale_str = gtk_entry_get_text(GTK_ENTRY(entry_VScale)); 258 | string hscale_str = gtk_entry_get_text(GTK_ENTRY(entry_HScale)); 259 | 260 | params->cannyL = atoi(cannyL_str.c_str()); 261 | params->cannyH = atoi(cannyH_str.c_str()); 262 | params->ZerBgrL = atoi(ZerBgrL_str.c_str()); 263 | params->ZerBgrH = atoi(ZerBgrH_str.c_str()); 264 | params->cannyCore = atoi(cannyCore_str.c_str()); 265 | params->neighborSize = atoi(neighborSize_str.c_str()); 266 | params->VScale = atoi(vscale_str.c_str()); 267 | params->HScale = atoi(hscale_str.c_str()); 268 | 269 | int drawColor = atoi(drawColor_str.c_str()); 270 | if(drawColor>255) 271 | drawColor = 255; 272 | if(drawColor<0) 273 | drawColor = 0; 274 | 275 | params->DrawColor = drawColor; 276 | 277 | //setting of using medium filter is in on_checkBox_media_toggle 278 | } 279 | 280 | 281 | void on_btn_apply_clicked(GtkWidget* button,gpointer userdata){ 282 | SetParamsFromView(_params); 283 | //gtk_widget_hide(windowParam); 284 | } 285 | 286 | void on_btn_cancel_clicked(GtkWidget* button,gpointer userdata){ 287 | gtk_widget_hide(windowParam); 288 | return; 289 | } 290 | 291 | void on_btn_default_clicked(GtkWidget* button,gpointer userdata){ 292 | 293 | Use_DefaultParams(_params); 294 | Fill_DefaultParams(); 295 | } 296 | 297 | void on_checkBox_meida_toggle(GtkWidget *check_button, gpointer data) 298 | { 299 | _params->useMedium = !_params->useMedium; 300 | } 301 | -------------------------------------------------------------------------------- /windowParam.h: -------------------------------------------------------------------------------- 1 | #ifndef WINDOWPARAM_H 2 | #define WINDOWPARAM_H 3 | 4 | #include 5 | 6 | 7 | /* 8 | ZerResult CalDistanceSquare(Mat& matRoi, double rto = MMPERPIXEL, 9 | int drawColor = WHITE, bool ifmedianBlur=YESMEDIANBLUR, 10 | int cannyL = 150, int cannyH = 200, int cannyCore = 3, 11 | int nbsize = N, Point2i VHtime = Point2i(4, 4), 12 | int ZerBgrL = 10, int ZerBgrH = 50 13 | 14 | ); 15 | ZerResultCir CalDistanceCircle(Mat& matRoi, double rto = MMPERPIXEL, 16 | int drawColor = WHITE, bool ifmedianBlur = YESMEDIANBLUR, 17 | int cannyL = 150, int cannyH = 200, int cannyCore = 3, 18 | int nbsize = N, Point2i VHtime = Point2i(4, 4), 19 | int ZerBgrL = 10, int ZerBgrH = 50 20 | 21 | ); 22 | */ 23 | 24 | typedef struct tag_paramSet{ 25 | int cannyL; 26 | int cannyH; 27 | int cannyCore; 28 | int ZerBgrL; 29 | int ZerBgrH; 30 | int DrawColor; 31 | int neighborSize; 32 | bool useMedium; 33 | int VScale; 34 | int HScale; 35 | }ParamSet; 36 | 37 | void Initial_WindowParam(ParamSet *ext_params); 38 | void Show_WindowParam(); 39 | void Hide_WindowParam(); 40 | 41 | void Fill_DefaultParams(); 42 | void Use_DefaultParams(ParamSet* params); 43 | 44 | void SetParamsFromView(ParamSet* params); 45 | void FillParamsToView(ParamSet *params); 46 | 47 | 48 | void on_btn_apply_clicked(GtkWidget* button,gpointer userdata); 49 | void on_btn_cancel_clicked(GtkWidget* button,gpointer userdata); 50 | void on_btn_default_clicked(GtkWidget* button,gpointer userdata); 51 | 52 | void on_checkBox_meida_toggle(GtkWidget *check_button, gpointer data); 53 | 54 | #endif // WINDOWPARAM_H 55 | -------------------------------------------------------------------------------- /zernikeMask.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq123459/ZernikeMoment_SubPixel_Detection/82ea167db6985a1fa2fc1bf11cf9d6ca91edbcb3/zernikeMask.h --------------------------------------------------------------------------------