├── google1a2bb3955e88a804.html ├── icon.ico ├── User Manual.pdf ├── Pre-Built Binaries.zip ├── Main.cpp ├── Dialog.cpp ├── Dialog.h ├── .gitignore ├── ManualRegistrationUI_resource.rc ├── README.md ├── Dialog.ui ├── ManualRegistrationUI2.pro ├── Mainui.h ├── Mainui.ui └── Mainui.cpp /google1a2bb3955e88a804.html: -------------------------------------------------------------------------------- 1 | google-site-verification: google1a2bb3955e88a804.html -------------------------------------------------------------------------------- /icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alirostami24/Manual-Image-Registration-Using-Control-Points/HEAD/icon.ico -------------------------------------------------------------------------------- /User Manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alirostami24/Manual-Image-Registration-Using-Control-Points/HEAD/User Manual.pdf -------------------------------------------------------------------------------- /Pre-Built Binaries.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alirostami24/Manual-Image-Registration-Using-Control-Points/HEAD/Pre-Built Binaries.zip -------------------------------------------------------------------------------- /Main.cpp: -------------------------------------------------------------------------------- 1 | #include "Mainui.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainUI w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /Dialog.cpp: -------------------------------------------------------------------------------- 1 | #include "Dialog.h" 2 | #include "ui_Dialog.h" 3 | 4 | CDialog::CDialog(QWidget *parent) : 5 | QDialog(parent), 6 | ui(new Ui::CDialog) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | CDialog::~CDialog() 12 | { 13 | delete ui; 14 | } 15 | -------------------------------------------------------------------------------- /Dialog.h: -------------------------------------------------------------------------------- 1 | #ifndef DIALOG_H 2 | #define DIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class CDialog; 8 | } 9 | 10 | class CDialog : public QDialog 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit CDialog(QWidget *parent = 0); 16 | ~CDialog(); 17 | 18 | private: 19 | Ui::CDialog *ui; 20 | }; 21 | 22 | #endif // DIALOG_H 23 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /ManualRegistrationUI_resource.rc: -------------------------------------------------------------------------------- 1 | # if defined(UNDER_CE) 2 | # include 3 | # else 4 | # include 5 | # endif 6 | 7 | IDI_ICON1 ICON DISCARDABLE "E:\\Other Projects\\Source Code\\ManualRegistrationUI2\\icon.ico" 8 | 9 | VS_VERSION_INFO VERSIONINFO 10 | FILEVERSION 1,3,2,1032 11 | PRODUCTVERSION 1,3,2,1032 12 | FILEFLAGSMASK 0x3fL 13 | #ifdef _DEBUG 14 | FILEFLAGS VS_FF_DEBUG 15 | #else 16 | FILEFLAGS 0x0L 17 | #endif 18 | FILEOS VOS__WINDOWS32 19 | FILETYPE VFT_DLL 20 | FILESUBTYPE 0x0L 21 | BEGIN 22 | BLOCK "StringFileInfo" 23 | BEGIN 24 | BLOCK "040904b0" 25 | BEGIN 26 | VALUE "CompanyName", "\0" 27 | VALUE "FileDescription", "\0" 28 | VALUE "FileVersion", "1.3.2.1032\0" 29 | VALUE "LegalCopyright", "\0" 30 | VALUE "OriginalFilename", "ManualRegistrationUI.exe\0" 31 | VALUE "ProductName", "ManualRegistrationUI\0" 32 | VALUE "ProductVersion", "1.3.2.1032\0" 33 | END 34 | END 35 | BLOCK "VarFileInfo" 36 | BEGIN 37 | VALUE "Translation", 0x0409, 1200 38 | END 39 | END 40 | /* End of Version info */ 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Manual Image Registration using Control Points 2 | A source code in C++ and Qt IDE for manual registration of two images, named reference and moving. This code contains two transformation types: Affine and Homography, all of which implemented using open source OpenCV library in C++. /this application is useful for those aiming to create a ground truth dataset for testing their automatic registration algorithms. Many helpful features are added to facilitate creating ground truth dataset, along with saving all the parameters generated by the transforamtion method. 3 | 4 | ## Requirements for Source Code Compilation 5 | - Opencv 3.1 (a complied version with extra modules. The OpenCV does not include some required funtions when it is downloaded for SourgeForge. A compile using Cmake is required to add other extra requirements provided in the extra modules. I you cannot complile the OpenCV with your own setting, please send me an E-mail (m.jalalat@gmail.com) to share a pre-built version with you. 6 | - Qt 5.X (e.g. 5.8 or higher) 7 | 8 | ## Pre-Built Binaries 9 | 10 | A pre-built binary of the code is available [here](https://github.com/mortezajalalat/Manual-Image-Registration-Using-Control-Points/blob/master/Pre-Built%20Binaries.zip) for those unwilling to compile the code from scratch. 11 | 12 | Before running the .exe file, you can see an screen capture of the UI provided in the "Pre-Built Binaries.zip" 13 | 14 | ## Requirements for executing Pre-built Binaries 15 | 16 | - Visual Studio 2013 redistributable for Windows 7 x86. 17 | - Visual Studio 2012 redistributable for Windows 7 x86. 18 | 19 | ## User Manual 20 | 21 | In order to get more details about the usage of the application please refer to the [User Manual](https://github.com/mortezajalalat/Manual-Image-Registration-Using-Control-Points/blob/master/User%20Manual.pdf) and the comments put inside the source code. 22 | 23 | ## Acknowledgement 24 | 25 | I thanks Mrs Zahra Khojasteh and Miss Fatemeh Moein for their help with testing and finalizing the code. 26 | 27 | ## An Easy Way for your Feedback 28 | I gratefully accept any bug report or suggestion for improving the performance and making the code more reusable. Please feel free to contact me via m.jalalat@gmail.com E-mail. 29 | -------------------------------------------------------------------------------- /Dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 197 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | 21 | 10 22 | 75 23 | true 24 | 25 | 26 | 27 | You are converting the transformation type from Homography to Affine. This means that only the first three control points will be preserved in this conversion. If you want to keep your three best control points, click on cancel and remove extra points manually. Then change the type of transforamtion matrix. Otherwise, after clicking Ok, extra control points will be lost. 28 | 29 | 30 | true 31 | 32 | 33 | 34 | 35 | 36 | 37 | Qt::Horizontal 38 | 39 | 40 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | buttonBox 50 | accepted() 51 | CDialog 52 | accept() 53 | 54 | 55 | 248 56 | 254 57 | 58 | 59 | 157 60 | 274 61 | 62 | 63 | 64 | 65 | buttonBox 66 | rejected() 67 | CDialog 68 | reject() 69 | 70 | 71 | 316 72 | 260 73 | 74 | 75 | 286 76 | 274 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /ManualRegistrationUI2.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2019-06-01T12:44:13 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | RC_ICONS += icon.ico 12 | 13 | TARGET = ManualRegistrationUI 14 | TEMPLATE = app 15 | 16 | 17 | SOURCES += \ 18 | Dialog.cpp \ 19 | Mainui.cpp \ 20 | Main.cpp 21 | 22 | HEADERS += \ 23 | Dialog.h \ 24 | Mainui.h 25 | 26 | FORMS += \ 27 | Dialog.ui \ 28 | Mainui.ui 29 | 30 | win32:VERSION = 1.3.2.1032 # major.minor.patch.build 31 | else:VERSION = 1.3.2 # major.minor.patch 32 | 33 | win32:CONFIG(release, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Release/' -lopencv_core310 34 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Debug/' -lopencv_core310d 35 | win32:CONFIG(release, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Release/' -lopencv_highgui310 36 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Debug/' -lopencv_highgui310d 37 | win32:CONFIG(release, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Release/' -lopencv_imgproc310 38 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Debug/' -lopencv_imgproc310d 39 | #win32:CONFIG(release, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Release/' -lopencv_photo310 40 | #else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Debug/' -lopencv_photo310d 41 | win32:CONFIG(release, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Release/' -lopencv_imgcodecs310 42 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Debug/' -lopencv_imgcodecs310d 43 | #win32:CONFIG(release, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Release/' -lopencv_videoio310 44 | #else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Debug/' -lopencv_videoio310d 45 | #win32:CONFIG(release, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Release/' -lopencv_video310 46 | #else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/'..HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Debug/' -lopencv_video310d 47 | win32:CONFIG(release, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Release/' -lopencv_calib3d310 48 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/lib/Debug/' -lopencv_calib3d310d 49 | 50 | INCLUDEPATH += $$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/include' 51 | DEPENDPATH += $$PWD/'../HyperGIS-widget/OpenCV 3.1 x86- complete/include' 52 | 53 | 54 | -------------------------------------------------------------------------------- /Mainui.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINUI_H 2 | #define MAINUI_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include "Dialog.h" 15 | 16 | #include "opencv2/core.hpp" 17 | #include "opencv2/highgui.hpp" 18 | #include "opencv2/imgproc.hpp" 19 | #include "opencv2/calib3d/calib3d.hpp" 20 | 21 | namespace Ui { 22 | class MainUI; 23 | } 24 | 25 | class MainUI : public QMainWindow 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | explicit MainUI(QWidget *parent = 0); 31 | ~MainUI(); 32 | 33 | private Q_SLOTS: 34 | void on_btnRegister_clicked(); 35 | 36 | void on_btnLoadReference_clicked(); 37 | 38 | void on_btnLoadMoving_clicked(); 39 | 40 | bool eventFilter( QObject *dist, QEvent *event ); 41 | 42 | void on_btnSavePoint_clicked(); 43 | 44 | void on_btnRemoveCurrentPoints_clicked(); 45 | 46 | void on_btnSaveRegistered_clicked(); 47 | 48 | void on_btnClear_clicked(); 49 | 50 | void on_dsbReferenceX_valueChanged(double arg1); 51 | 52 | void on_dsbReferenceY_valueChanged(double arg1); 53 | 54 | void on_dsbMovingX_valueChanged(double arg1); 55 | 56 | void on_dsbMovingY_valueChanged(double arg1); 57 | 58 | void on_btnSaveImshowPair_clicked(); 59 | 60 | void on_actionAffine_triggered(); 61 | 62 | void on_actionHomography_triggered(); 63 | 64 | void on_chbMovingContrastEnhancement_toggled(bool checked); 65 | 66 | void on_btnSaveControlPoints_clicked(); 67 | 68 | void on_btnLoadControlPoints_clicked(); 69 | 70 | void on_btnClearControlPoints_clicked(); 71 | 72 | void on_btnApplyToAll_clicked(); 73 | 74 | void on_chbReferenceContrastEnhancement_toggled(bool checked); 75 | 76 | void sltReceiveOkForControlPointRemoval(); 77 | 78 | void on_btnRemoveSelectedPoints_clicked(); 79 | 80 | private: 81 | Ui::MainUI *ui; 82 | 83 | /* converted version of the reference image from BGR to RGB */ 84 | cv::Mat convertedReferenceImage; 85 | 86 | /* converted version of the moving image from BGR to RGB */ 87 | cv::Mat convertedMovingImage; 88 | 89 | /* an image of size: zoomFactor*(imageSize) 90 | * This is defined to do rect zoom easierfor reference image 91 | */ 92 | cv::Mat enlargedReference; 93 | 94 | /* 95 | * an image of size: zoomFactor*(imageSize) 96 | * This is defined to do rect zoom easierfor moving image 97 | */ 98 | cv::Mat enlargedMoving; 99 | 100 | /* 101 | * images for keeping the converted version of the loaded image 102 | */ 103 | cv::Mat convertedMovingImage_CLAHE; 104 | cv::Mat convertedReferenceImage_CLAHE; 105 | 106 | /* 107 | * QPointF structure for keeping the clicked points in moving and reference images 108 | */ 109 | QPointF pReference; 110 | QPointF pMoving; 111 | 112 | /* 113 | * Some boolean variable for controlling user actions and preventing exceptions 114 | */ 115 | bool disableReferenceImageMouseMove; 116 | bool disableMovingImageMouseMove; 117 | bool referencePointIsSelected; 118 | bool movingPointIsSelected; 119 | bool isRegisterationDone; 120 | bool isActiveMovingImageCLAHE; 121 | bool isActiveReferenceImageCLAHE; 122 | 123 | /* A path in which there are images whose transformation matrix is the same as the one registered manuaaly */ 124 | QString seqPath; 125 | QString movingImagePath; 126 | QString referenceImagePath; 127 | 128 | /* 129 | * The suffix of the moving image is used for the writing of results. 130 | * The format of the moving image and the results are the same. 131 | */ 132 | QString movingImageSuffix; 133 | 134 | /* 135 | * this enum is needed in deciding on each method of transformation is selected by the user 136 | */ 137 | enum ETransformationType {Affine, Homography }; 138 | int method; 139 | 140 | /* 141 | * A mat which is used for the result of the warping operation. 142 | */ 143 | cv::Mat warpDst; 144 | 145 | /* 146 | * This mat is used for saving imShowPair image as it is defined by MATLAB. 147 | */ 148 | cv::Mat imShowPair; 149 | 150 | /* 151 | * The following variables are used for keeping the saved pair points. 152 | */ 153 | cv::Point2f movingPointsForAffine[3]; 154 | cv::Point2f referencePointsForAffine[3]; 155 | std::vector referencePointsForHomography; 156 | std::vector movingPointsForHomography; 157 | 158 | /* 159 | * indicates the total pair number of the saved points. 160 | */ 161 | int pairPointCounter; 162 | 163 | /* 164 | * The following variables are used for keeping the correlation between the UI and real coordinates. 165 | */ 166 | float referenceRatioX; 167 | float referenceRatioY; 168 | float movingRatioX; 169 | float movingRatioY; 170 | 171 | /* 172 | * The following variables are used for handling the removal of the pair points. 173 | */ 174 | bool haveSelectedPair; 175 | int selectedPairIndex; 176 | 177 | /* 178 | * The following variables are used for making sure that moving 179 | * and reference images are loaded properly or not.. 180 | */ 181 | bool isReferenceAvailable; 182 | bool isMovingAvailable; 183 | 184 | /* 185 | * This variable controls the amount of the zoom needed by the user to click on the 186 | * corresponding points. 187 | */ 188 | int zoomFactor; 189 | 190 | CDialog *controlPointDialog; 191 | 192 | /* 193 | * The following functions are implemented to update the images displayed on the UI 194 | * when the user is interacting with the UI. 195 | */ 196 | void plotReferenceZoomedImage(); 197 | void plotMovingZoomedImage(); 198 | void drawReferenceZoomed(); 199 | void drawMovingZoomed(); 200 | void updateReferenceImage(); 201 | void updateMovingImage(); 202 | }; 203 | 204 | 205 | 206 | 207 | #endif // MAINUI_H 208 | -------------------------------------------------------------------------------- /Mainui.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainUI 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1467 10 | 649 11 | 12 | 13 | 14 | MainUI 15 | 16 | 17 | 18 | 19 | 20 | 780 21 | 20 22 | 681 23 | 561 24 | 25 | 26 | 27 | color: rgb(255, 0, 0); 28 | 29 | 30 | Registration Result 31 | 32 | 33 | 34 | 35 | 36 | color: rgb(0, 0, 0); 37 | 38 | 39 | QFrame::Box 40 | 41 | 42 | 43 | 44 | 45 | true 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 50 55 | 11 56 | 681 57 | 401 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 315 66 | 330 67 | 68 | 69 | 70 | Reference 71 | 72 | 73 | 74 | true 75 | 76 | 77 | 78 | 10 79 | 379 80 | 16 81 | 16 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 11 92 | 24 93 | 315 94 | 230 95 | 96 | 97 | 98 | 99 | 315 100 | 230 101 | 102 | 103 | 104 | true 105 | 106 | 107 | QFrame::Box 108 | 109 | 110 | 111 | 112 | 113 | true 114 | 115 | 116 | 117 | 118 | 119 | 12 120 | 261 121 | 151 122 | 111 123 | 124 | 125 | 126 | 127 | 128 | 129 | Load 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | X: 139 | 140 | 141 | 142 | 143 | 144 | 145 | 1 146 | 147 | 148 | 2000.000000000000000 149 | 150 | 151 | 0.100000000000000 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | Y: 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 170 177 | 261 178 | 150 179 | 110 180 | 181 | 182 | 183 | 184 | 150 185 | 110 186 | 187 | 188 | 189 | QFrame::Box 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 10 199 | 380 200 | 133 201 | 17 202 | 203 | 204 | 205 | Contrast Enhancement 206 | 207 | 208 | false 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 315 218 | 330 219 | 220 | 221 | 222 | Moving 223 | 224 | 225 | 226 | 227 | 11 228 | 380 229 | 133 230 | 17 231 | 232 | 233 | 234 | Contrast Enhancement 235 | 236 | 237 | true 238 | 239 | 240 | 241 | 242 | 243 | 12 244 | 25 245 | 315 246 | 230 247 | 248 | 249 | 250 | 251 | 315 252 | 230 253 | 254 | 255 | 256 | true 257 | 258 | 259 | QFrame::Box 260 | 261 | 262 | 263 | 264 | 265 | true 266 | 267 | 268 | 269 | 270 | 271 | 13 272 | 262 273 | 151 274 | 111 275 | 276 | 277 | 278 | 279 | 280 | 281 | Load 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | X: 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | Y: 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 171 319 | 262 320 | 150 321 | 110 322 | 323 | 324 | 325 | 326 | 150 327 | 110 328 | 329 | 330 | 331 | QFrame::Box 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 11 345 | 421 346 | 271 347 | 171 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 16777215 356 | 25 357 | 358 | 359 | 360 | 361 | 10 362 | 75 363 | true 364 | 365 | 366 | 367 | color: rgb(0, 170, 0); 368 | 369 | 370 | Selected Pair-Point Counts: 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 10 381 | 75 382 | true 383 | 384 | 385 | 386 | background-color: rgb(196, 230, 255); 387 | 388 | 389 | Transformation Type: 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | ... 398 | 399 | 400 | QToolButton::MenuButtonPopup 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 9 409 | 410 | 411 | 412 | color: rgb(255, 0, 0); 413 | 414 | 415 | None 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 7 426 | 50 427 | false 428 | 429 | 430 | 431 | The Required Number of Points: 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 16777215 443 | 25 444 | 445 | 446 | 447 | 448 | 10 449 | 75 450 | true 451 | 452 | 453 | 454 | color: rgb(255, 0, 0); 455 | 456 | 457 | Version: 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 290 469 | 420 470 | 281 471 | 175 472 | 473 | 474 | 475 | 476 | 9 477 | 75 478 | true 479 | 480 | 481 | 482 | 483 | 484 | 485 | Control Points Selection 486 | 487 | 488 | 489 | 490 | 180 491 | 20 492 | 90 493 | 35 494 | 495 | 496 | 497 | 498 | 8 499 | 75 500 | true 501 | 502 | 503 | 504 | Save CPs 505 | 506 | 507 | 508 | 509 | 510 | 180 511 | 136 512 | 90 513 | 32 514 | 515 | 516 | 517 | 518 | 8 519 | 75 520 | true 521 | 522 | 523 | 524 | background-color: rgb(255, 0, 0); 525 | 526 | 527 | Reset All 528 | 529 | 530 | 531 | 532 | 533 | 10 534 | 20 535 | 160 536 | 32 537 | 538 | 539 | 540 | 541 | 8 542 | 75 543 | true 544 | 545 | 546 | 547 | Save Current Pair 548 | 549 | 550 | 551 | 552 | 553 | 180 554 | 99 555 | 90 556 | 33 557 | 558 | 559 | 560 | 561 | 8 562 | 75 563 | true 564 | 565 | 566 | 567 | background-color: rgb(255, 0, 0); 568 | 569 | 570 | Reset CPs 571 | 572 | 573 | 574 | 575 | 576 | 10 577 | 59 578 | 160 579 | 33 580 | 581 | 582 | 583 | 584 | 8 585 | 75 586 | true 587 | 588 | 589 | 590 | Remove Current Pair 591 | 592 | 593 | 594 | 595 | 596 | 180 597 | 60 598 | 90 599 | 34 600 | 601 | 602 | 603 | 604 | 8 605 | 75 606 | true 607 | 608 | 609 | 610 | Load CPs 611 | 612 | 613 | 614 | 615 | 616 | 11 617 | 99 618 | 160 619 | 33 620 | 621 | 622 | 623 | 624 | 8 625 | 75 626 | true 627 | 628 | 629 | 630 | Remove Selected Pair 631 | 632 | 633 | 634 | 635 | 636 | 637 | 580 638 | 420 639 | 191 640 | 175 641 | 642 | 643 | 644 | 645 | 9 646 | 75 647 | true 648 | 649 | 650 | 651 | 652 | 653 | 654 | Apply Registration 655 | 656 | 657 | 658 | 659 | 11 660 | 20 661 | 170 662 | 34 663 | 664 | 665 | 666 | 667 | 11 668 | 75 669 | true 670 | 671 | 672 | 673 | color: rgb(0, 170, 0); 674 | 675 | 676 | Register 677 | 678 | 679 | 680 | 681 | 682 | 11 683 | 58 684 | 170 685 | 34 686 | 687 | 688 | 689 | 690 | 8 691 | 75 692 | true 693 | 694 | 695 | 696 | Save Registered 697 | 698 | 699 | 700 | 701 | 702 | 10 703 | 97 704 | 170 705 | 35 706 | 707 | 708 | 709 | 710 | 8 711 | 75 712 | true 713 | 714 | 715 | 716 | Save ImshowPair 717 | 718 | 719 | 720 | 721 | 722 | 10 723 | 136 724 | 170 725 | 35 726 | 727 | 728 | 729 | 730 | 75 731 | true 732 | 733 | 734 | 735 | background-color: rgb(85, 212, 0); 736 | 737 | 738 | Apply to Sequence 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 0 747 | 0 748 | 1467 749 | 21 750 | 751 | 752 | 753 | 754 | 755 | TopToolBarArea 756 | 757 | 758 | false 759 | 760 | 761 | 762 | 763 | 764 | Affine 765 | 766 | 767 | 768 | 769 | Homography 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | -------------------------------------------------------------------------------- /Mainui.cpp: -------------------------------------------------------------------------------- 1 | #include "Mainui.h" 2 | #include "ui_mainui.h" 3 | 4 | MainUI::MainUI(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::MainUI) 7 | { 8 | ui->setupUi(this); 9 | 10 | ui->lblReferenceImage->installEventFilter(this); 11 | ui->lblMovingImage->installEventFilter(this); 12 | 13 | disableReferenceImageMouseMove = false; 14 | disableMovingImageMouseMove = false; 15 | 16 | referencePointIsSelected = false; 17 | movingPointIsSelected = false; 18 | 19 | isReferenceAvailable = false; 20 | isMovingAvailable = false; 21 | 22 | haveSelectedPair = false; 23 | 24 | selectedPairIndex = -1; 25 | 26 | isRegisterationDone = false; 27 | 28 | zoomFactor = 5; 29 | 30 | isActiveMovingImageCLAHE = true; 31 | isActiveReferenceImageCLAHE = false; 32 | 33 | pairPointCounter = 0; 34 | ui->lblPairPointCounter->setText(QString("Selected Pair-Point Counts: " + QString::number(pairPointCounter))); 35 | 36 | controlPointDialog = new CDialog(); 37 | connect(controlPointDialog, &CDialog::accepted, this, &MainUI::sltReceiveOkForControlPointRemoval); 38 | 39 | QImage QIm(ui->lblReferenceImage->width(), ui->lblReferenceImage->height(),QImage::Format_RGB888); 40 | QIm.fill(Qt::blue); 41 | ui->lblReferenceImage->setPixmap(QPixmap::fromImage(QIm)); 42 | ui->lblMovingImage->setPixmap(QPixmap::fromImage(QIm)); 43 | ui->lblZoomedReference->setPixmap(QPixmap::fromImage(QIm)); 44 | ui->lblZoomedMoving->setPixmap(QPixmap::fromImage(QIm)); 45 | 46 | QImage QImRegistered(ui->lblRegisteredImage->width(), ui->lblRegisteredImage->height(),QImage::Format_RGB888); 47 | QImRegistered.fill(Qt::blue); 48 | ui->lblRegisteredImage->setPixmap(QPixmap::fromImage(QImRegistered)); 49 | 50 | ui->toolButton->addAction(ui->actionAffine); 51 | ui->toolButton->addAction(ui->actionHomography); 52 | 53 | ui->lblVersion->setText("Version: 1.3.2.1032"); 54 | 55 | method = ETransformationType(Affine); 56 | ui->lblMethod->setText("Affine"); 57 | ui->lblNumPointRequired->setText("The Required Number of Points: 3"); 58 | } 59 | 60 | MainUI::~MainUI() 61 | { 62 | delete controlPointDialog; 63 | delete ui; 64 | } 65 | 66 | void MainUI::on_btnRegister_clicked() 67 | { 68 | if((method == ETransformationType::Affine && pairPointCounter > 2) || (method == ETransformationType::Homography && pairPointCounter > 3)) 69 | { 70 | QString fileName = QFileDialog::getSaveFileName(this, 71 | tr("Select Path for Transition Matrix"), "" 72 | , tr("*.txt")); 73 | 74 | if(fileName.isEmpty()) 75 | { 76 | qDebug() << "The specified file name is empty!"; 77 | fileName = "outputTransforamtionMatrix.txt"; 78 | } 79 | 80 | QFileInfo InputMap(fileName); 81 | QString fullName = fileName; 82 | if(InputMap.suffix() == "") 83 | fullName = QString(fullName + ".txt"); 84 | 85 | cv::Mat affineWarpMat(2, 3, CV_32FC1); 86 | cv::Mat homographyWarpMat(3, 3, CV_32FC1); 87 | 88 | std::vector channels; 89 | cv::Mat imgPair; 90 | 91 | std::ofstream outputTransforamtionMatrix; 92 | outputTransforamtionMatrix.open(fileName.toLatin1().data()); 93 | 94 | switch (method) 95 | { 96 | case ETransformationType::Affine: 97 | 98 | affineWarpMat = cv::getAffineTransform(movingPointsForAffine, referencePointsForAffine); 99 | 100 | cv::warpAffine(convertedMovingImage, warpDst, affineWarpMat, warpDst.size()); 101 | 102 | if (outputTransforamtionMatrix.is_open()) 103 | { 104 | outputTransforamtionMatrix << affineWarpMat.at(0, 0) << ", " << affineWarpMat.at(0, 1) << ", " << affineWarpMat.at(0, 2) << "\n"; 105 | outputTransforamtionMatrix << affineWarpMat.at(1, 0) << ", " << affineWarpMat.at(1, 1) << ", " << affineWarpMat.at(1, 2) << "\n"; 106 | } 107 | 108 | break; 109 | case ETransformationType::Homography: 110 | 111 | // Find homography 112 | homographyWarpMat = findHomography(movingPointsForHomography, referencePointsForHomography, cv::RANSAC );//LMEDS,RANSAC,RHO 113 | 114 | // Use homography to warp image 115 | cv::warpPerspective(convertedMovingImage, warpDst, homographyWarpMat, warpDst.size()); 116 | 117 | if (outputTransforamtionMatrix.is_open()) 118 | { 119 | outputTransforamtionMatrix << homographyWarpMat.at(0, 0) << ", " << homographyWarpMat.at(0, 1) << ", " << homographyWarpMat.at(0, 2) << "\n"; 120 | outputTransforamtionMatrix << homographyWarpMat.at(1, 0) << ", " << homographyWarpMat.at(1, 1) << ", " << homographyWarpMat.at(1, 2) << "\n"; 121 | outputTransforamtionMatrix << homographyWarpMat.at(2, 0) << ", " << homographyWarpMat.at(2, 1) << ", " << homographyWarpMat.at(2, 2) << "\n"; 122 | } 123 | 124 | break; 125 | } 126 | 127 | outputTransforamtionMatrix.close(); 128 | 129 | cv::Mat paddedImage; 130 | cv::Mat matOriginal_Gray; 131 | cv::Mat warpDst_Gray; 132 | cv::cvtColor(convertedReferenceImage, matOriginal_Gray, CV_RGB2GRAY); 133 | cv::cvtColor(warpDst, warpDst_Gray, CV_RGB2GRAY); 134 | 135 | if(matOriginal_Gray.cols >= warpDst.cols) 136 | { 137 | paddedImage.create(matOriginal_Gray.rows, matOriginal_Gray.cols, CV_8UC1); 138 | paddedImage.setTo(0); 139 | 140 | cv::Mat ROI(paddedImage, cv::Rect(0, 0, warpDst.cols, warpDst.rows)); 141 | warpDst_Gray.copyTo(ROI); 142 | 143 | channels.push_back(matOriginal_Gray); 144 | channels.push_back(paddedImage); 145 | channels.push_back(matOriginal_Gray); 146 | 147 | 148 | merge(channels, imgPair); 149 | } 150 | else 151 | { 152 | paddedImage.create(warpDst.rows, warpDst.cols, CV_8UC1); 153 | paddedImage.setTo(0); 154 | cv::Mat ROI(paddedImage, cv::Rect(0, 0, matOriginal_Gray.cols, matOriginal_Gray.rows)); 155 | matOriginal_Gray.copyTo(ROI); 156 | 157 | channels.push_back(warpDst_Gray); 158 | channels.push_back(paddedImage); 159 | channels.push_back(warpDst_Gray); 160 | 161 | merge(channels, imgPair); 162 | } 163 | 164 | if (!imShowPair.empty()) 165 | imShowPair.release(); 166 | 167 | imShowPair = imgPair.clone(); 168 | 169 | QImage qimgOriginal_Pre((uchar*)imgPair.data, imgPair.cols, imgPair.rows, imgPair.step, QImage::Format_RGB888); 170 | ui->lblRegisteredImage->setPixmap(QPixmap::fromImage(qimgOriginal_Pre)); 171 | 172 | isRegisterationDone = true; 173 | } 174 | else 175 | { 176 | QMessageBox msgBox; 177 | if(method == ETransformationType::Affine) 178 | msgBox.setText("Registration Failed! At least three pair points should be selected!"); 179 | else if(method == ETransformationType::Homography) 180 | msgBox.setText("Registration Failed! At least four pair points should be selected!"); 181 | msgBox.setIcon(QMessageBox::Warning); 182 | msgBox.exec(); 183 | } 184 | } 185 | 186 | void MainUI::on_btnLoadReference_clicked() 187 | { 188 | QString fileName = QFileDialog::getOpenFileName(this, 189 | tr("Open Image"), "E:/bistco/RGB-T DataSet/RGB-T234/baketballwaliking/reference/" 190 | , tr("Map Files (*.jpg *.tif *.bmp *.png)")); 191 | 192 | QFileInfo fi(fileName); 193 | referenceImagePath = fi.path(); 194 | 195 | if(fileName.isEmpty()) 196 | { 197 | qDebug() << "The specified file name is empty!"; 198 | return; 199 | } 200 | 201 | cv::Mat matOriginal = cv::imread(fileName.toStdString()); 202 | cv::cvtColor(matOriginal, convertedReferenceImage, CV_BGR2RGB); 203 | 204 | if (isActiveReferenceImageCLAHE) 205 | { 206 | cv::cvtColor(matOriginal, convertedReferenceImage_CLAHE, CV_RGB2GRAY); 207 | cv::Ptr clahe = cv::createCLAHE(); 208 | clahe->setClipLimit(4); 209 | clahe->apply(convertedReferenceImage_CLAHE, convertedReferenceImage_CLAHE); 210 | 211 | if(!enlargedReference.empty()) 212 | enlargedReference.release(); 213 | cv::resize(convertedReferenceImage_CLAHE, enlargedReference, cv::Size(zoomFactor*matOriginal.cols, zoomFactor*matOriginal.rows), 0,0,cv::INTER_LINEAR); 214 | 215 | QImage qimgOriginal_Pre((uchar*)convertedReferenceImage_CLAHE.data, convertedReferenceImage_CLAHE.cols, convertedReferenceImage_CLAHE.rows, convertedReferenceImage_CLAHE.step, QImage::Format_Grayscale8); 216 | ui->lblReferenceImage->setPixmap(QPixmap::fromImage(qimgOriginal_Pre)); 217 | } 218 | else 219 | { 220 | if(!enlargedReference.empty()) 221 | enlargedReference.release(); 222 | cv::resize(convertedReferenceImage, enlargedReference, cv::Size(zoomFactor*matOriginal.cols, zoomFactor*matOriginal.rows), 0,0,cv::INTER_LINEAR); 223 | 224 | QImage qimgOriginal_Pre((uchar*)convertedReferenceImage.data, convertedReferenceImage.cols, convertedReferenceImage.rows, convertedReferenceImage.step, QImage::Format_RGB888); 225 | ui->lblReferenceImage->setPixmap(QPixmap::fromImage(qimgOriginal_Pre)); 226 | } 227 | 228 | updateReferenceImage(); 229 | 230 | disableReferenceImageMouseMove = false; 231 | isReferenceAvailable = true; 232 | 233 | ui->dsbReferenceX->setMaximum(matOriginal.cols); 234 | ui->dsbReferenceX->setSingleStep(1.0/zoomFactor); 235 | ui->dsbReferenceY->setMaximum(matOriginal.rows); 236 | ui->dsbReferenceY->setSingleStep(1.0/zoomFactor); 237 | } 238 | 239 | void MainUI::on_btnLoadMoving_clicked() 240 | { 241 | QString fileName = QFileDialog::getOpenFileName(this, 242 | tr("Open Image"), "E:/bistco/RGB-T DataSet/RGB-T234/baketballwaliking/infrared" 243 | , tr("Map Files (*.jpg *.tif *.bmp)")); 244 | 245 | if(fileName.isEmpty()) 246 | { 247 | qDebug() << "The specified file name is empty!"; 248 | return; 249 | } 250 | 251 | QFileInfo fi(fileName); 252 | movingImageSuffix = fi.suffix(); 253 | movingImagePath = fi.path(); 254 | 255 | cv::Mat matOriginal = cv::imread(fileName.toStdString()); 256 | cv::cvtColor(matOriginal, convertedMovingImage, CV_BGR2RGB); 257 | 258 | if (isActiveMovingImageCLAHE) 259 | { 260 | cv::cvtColor(matOriginal, convertedMovingImage_CLAHE, CV_RGB2GRAY); 261 | cv::Ptr clahe = cv::createCLAHE(); 262 | clahe->setClipLimit(4); 263 | clahe->apply(convertedMovingImage_CLAHE, convertedMovingImage_CLAHE); 264 | 265 | if(!enlargedMoving.empty()) 266 | enlargedMoving.release(); 267 | cv::resize(convertedMovingImage_CLAHE, enlargedMoving, cv::Size(zoomFactor*matOriginal.cols, zoomFactor*matOriginal.rows), 0,0,cv::INTER_LINEAR); 268 | 269 | QImage qimgOriginal_Pre((uchar*)convertedMovingImage_CLAHE.data, convertedMovingImage_CLAHE.cols, convertedMovingImage_CLAHE.rows, convertedMovingImage_CLAHE.step, QImage::Format_Grayscale8); 270 | ui->lblMovingImage->setPixmap(QPixmap::fromImage(qimgOriginal_Pre)); 271 | } 272 | else 273 | { 274 | if(!enlargedMoving.empty()) 275 | enlargedMoving.release(); 276 | cv::resize(convertedMovingImage, enlargedMoving, cv::Size(zoomFactor*matOriginal.cols, zoomFactor*matOriginal.rows), 0,0,cv::INTER_LINEAR); 277 | 278 | QImage qimgOriginal_Pre((uchar*)convertedMovingImage.data, convertedMovingImage.cols, convertedMovingImage.rows, convertedMovingImage.step, QImage::Format_RGB888); 279 | ui->lblMovingImage->setPixmap(QPixmap::fromImage(qimgOriginal_Pre)); 280 | } 281 | 282 | updateMovingImage(); 283 | 284 | disableMovingImageMouseMove = false; 285 | isMovingAvailable = true; 286 | 287 | ui->dsbMovingX->setMaximum(matOriginal.cols); 288 | ui->dsbMovingX->setSingleStep(1.0/zoomFactor); 289 | ui->dsbMovingY->setMaximum(matOriginal.rows); 290 | ui->dsbMovingY->setSingleStep(1.0/zoomFactor); 291 | } 292 | 293 | bool MainUI::eventFilter(QObject *dist, QEvent *event) 294 | { 295 | QMouseEvent *me = static_cast(event); 296 | 297 | if (me->button() == Qt::MiddleButton && haveSelectedPair) 298 | { 299 | haveSelectedPair = false; 300 | 301 | updateReferenceImage(); 302 | updateMovingImage(); 303 | } 304 | 305 | if (dist == ui->lblReferenceImage && isReferenceAvailable) 306 | { 307 | referenceRatioX = (float) convertedReferenceImage.cols/ui->lblReferenceImage->width(); 308 | referenceRatioY = (float) convertedReferenceImage.rows/ui->lblReferenceImage->height(); 309 | 310 | if (event->type() == QEvent::MouseMove && !disableReferenceImageMouseMove) 311 | { 312 | QPoint coordinates = me->pos(); 313 | 314 | pReference.setX(referenceRatioX*coordinates.x()); 315 | pReference.setY(referenceRatioY*coordinates.y()); 316 | 317 | plotReferenceZoomedImage(); 318 | } 319 | else if (me->button() == Qt::RightButton 320 | && event->type() == QEvent::MouseButtonRelease 321 | && event->type() != QEvent::MouseMove) 322 | { 323 | selectedPairIndex = -1; 324 | float distance = 10000; 325 | float currentDistance; 326 | for (int i = 0; i < pairPointCounter; i++) 327 | { 328 | switch (method) 329 | { 330 | case ETransformationType::Affine: 331 | currentDistance = qSqrt(qPow(referencePointsForAffine[i].x - pReference.x(),2.0) 332 | + qPow(referencePointsForAffine[i].y - pReference.y(), 2.0)); 333 | 334 | break; 335 | case ETransformationType::Homography: 336 | currentDistance = qSqrt(qPow(referencePointsForHomography[i].x - pReference.x(),2.0) 337 | + qPow(referencePointsForHomography[i].y - pReference.y(), 2.0)); 338 | break; 339 | } 340 | 341 | if (currentDistance < distance) 342 | { 343 | haveSelectedPair = true; 344 | distance = currentDistance; 345 | selectedPairIndex = i; 346 | } 347 | } 348 | 349 | updateReferenceImage(); 350 | updateMovingImage(); 351 | } 352 | else if (event->type() == QEvent::MouseButtonRelease 353 | && me->button() != Qt::RightButton 354 | && me->button() != Qt::MiddleButton 355 | && !disableReferenceImageMouseMove) 356 | { 357 | disableReferenceImageMouseMove = true; 358 | 359 | cv::Mat fullWindow; 360 | cv::resize(convertedReferenceImage, fullWindow, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 361 | cv::circle(fullWindow, cv::Point((float)pReference.x()/referenceRatioX, (float)pReference.y()/referenceRatioY), 3, cv::Scalar(255,0,0), 4,-1); 362 | 363 | if(pairPointCounter>0) 364 | { 365 | for (int i=0; i clahe = cv::createCLAHE(); 374 | clahe->setClipLimit(4); 375 | cv::cvtColor(convertedReferenceImage, convertedReferenceImage_CLAHE, CV_RGB2GRAY); 376 | clahe->apply(convertedReferenceImage_CLAHE, convertedReferenceImage_CLAHE); 377 | 378 | cv::Mat CLAHERGB; 379 | cv::cvtColor(convertedReferenceImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 380 | cv::resize(CLAHERGB, fullWindow, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 381 | } 382 | 383 | QImage qimg((uchar*)fullWindow.data, fullWindow.cols, fullWindow.rows, fullWindow.step, QImage::Format_RGB888); 384 | ui->lblReferenceImage->setPixmap(QPixmap::fromImage(qimg)); 385 | 386 | ui->dsbReferenceX->setValue(pReference.x()); 387 | ui->dsbReferenceY->setValue(pReference.y()); 388 | 389 | referencePointIsSelected = true; 390 | } 391 | } 392 | 393 | if (dist == ui->lblMovingImage && isMovingAvailable) 394 | { 395 | movingRatioX = (float) convertedMovingImage.cols/ui->lblMovingImage->width(); 396 | movingRatioY = (float) convertedMovingImage.rows/ui->lblMovingImage->height(); 397 | 398 | if (event->type() == QEvent::MouseMove && !disableMovingImageMouseMove) 399 | { 400 | QPoint coordinates = me->pos(); 401 | 402 | pMoving.setX(movingRatioX*coordinates.x()); 403 | pMoving.setY(movingRatioY*coordinates.y()); 404 | 405 | plotMovingZoomedImage(); 406 | } 407 | else if (me->button() == Qt::RightButton 408 | && event->type() == QEvent::MouseButtonRelease 409 | && event->type() != QEvent::MouseMove) 410 | { 411 | selectedPairIndex = -1; 412 | float distance = 10000; 413 | float currentDistance; 414 | for (int i = 0; i < pairPointCounter; i++) 415 | { 416 | switch (method) 417 | { 418 | case ETransformationType::Affine: 419 | currentDistance = qSqrt(qPow(movingPointsForAffine[i].x - pMoving.x(),2.0) 420 | + qPow(movingPointsForAffine[i].y - pMoving.y(), 2.0)); 421 | 422 | break; 423 | case ETransformationType::Homography: 424 | currentDistance = qSqrt(qPow(movingPointsForHomography[i].x - pMoving.x(),2.0) 425 | + qPow(movingPointsForHomography[i].y - pMoving.y(), 2.0)); 426 | break; 427 | } 428 | 429 | if (currentDistance < distance) 430 | { 431 | haveSelectedPair = true; 432 | distance = currentDistance; 433 | selectedPairIndex = i; 434 | } 435 | } 436 | 437 | updateReferenceImage(); 438 | updateMovingImage(); 439 | } 440 | else if (event->type() == QEvent::MouseButtonRelease 441 | && me->button() != Qt::RightButton 442 | && me->button() != Qt::MiddleButton 443 | && !disableMovingImageMouseMove) 444 | { 445 | disableMovingImageMouseMove = true; 446 | 447 | cv::Mat fullWindow; 448 | cv::resize(convertedMovingImage, fullWindow, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 449 | cv::circle(fullWindow, cv::Point((float)pMoving.x()/movingRatioX, (float)pMoving.y()/movingRatioY), 3, cv::Scalar(255,0,0), 4,-1); 450 | 451 | if(pairPointCounter > 0) 452 | { 453 | for (int i=0; i clahe = cv::createCLAHE(); 462 | clahe->setClipLimit(4); 463 | cv::cvtColor(convertedMovingImage, convertedMovingImage_CLAHE, CV_RGB2GRAY); 464 | clahe->apply(convertedMovingImage_CLAHE, convertedMovingImage_CLAHE); 465 | 466 | cv::Mat CLAHERGB; 467 | cv::cvtColor(convertedMovingImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 468 | cv::resize(CLAHERGB, fullWindow, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 469 | } 470 | 471 | QImage qimg((uchar*)fullWindow.data, fullWindow.cols, fullWindow.rows, fullWindow.step, QImage::Format_RGB888); 472 | ui->lblMovingImage->setPixmap(QPixmap::fromImage(qimg)); 473 | 474 | ui->dsbMovingX->setValue(pMoving.x()); 475 | ui->dsbMovingY->setValue(pMoving.y()); 476 | 477 | movingPointIsSelected = true; 478 | } 479 | 480 | } 481 | return QObject::eventFilter(dist, event); 482 | } 483 | 484 | void MainUI::on_btnSavePoint_clicked() 485 | { 486 | if (!disableReferenceImageMouseMove || !disableMovingImageMouseMove) 487 | { 488 | QMessageBox msgBox; 489 | msgBox.setText("A single point cannot be saved, you should select a pair!"); 490 | msgBox.setIcon(QMessageBox::Warning); 491 | msgBox.exec(); 492 | } 493 | else 494 | { 495 | cv::Mat fullWindowReference; 496 | if (isActiveReferenceImageCLAHE) 497 | { 498 | qDebug() << isActiveReferenceImageCLAHE; 499 | cv::Mat CLAHERGB; 500 | cv::cvtColor(convertedReferenceImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 501 | cv::resize(CLAHERGB, fullWindowReference, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 502 | } 503 | else 504 | cv::resize(convertedReferenceImage, fullWindowReference, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 505 | 506 | cv::Mat fullWindowMoving; 507 | if (isActiveMovingImageCLAHE) 508 | { 509 | cv::Mat CLAHERGB; 510 | cv::cvtColor(convertedMovingImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 511 | cv::resize(CLAHERGB, fullWindowMoving, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 512 | } 513 | else 514 | cv::resize(convertedMovingImage, fullWindowMoving, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 515 | 516 | switch (method) 517 | { 518 | case ETransformationType::Affine: 519 | if (pairPointCounter < 3 && referencePointIsSelected && movingPointIsSelected) 520 | { 521 | movingPointsForAffine[pairPointCounter] = cv::Point2f(pMoving.x(), pMoving.y()); 522 | referencePointsForAffine[pairPointCounter] = cv::Point2f(pReference.x(), pReference.y()); 523 | 524 | disableReferenceImageMouseMove = false; 525 | disableMovingImageMouseMove = false; 526 | 527 | referencePointIsSelected = false; 528 | movingPointIsSelected = false; 529 | 530 | pairPointCounter++; 531 | ui->lblPairPointCounter->setText(QString("Selected Pair-Point Counts: " + QString::number(pairPointCounter))); 532 | 533 | 534 | if(pairPointCounter>0) 535 | { 536 | for (int i=0; ilblReferenceImage->setPixmap(QPixmap::fromImage(qimgOriginal_PreReference)); 545 | 546 | QImage qimgOriginal_PreMoving((uchar*)fullWindowMoving.data, fullWindowMoving.cols, fullWindowMoving.rows, fullWindowMoving.step, QImage::Format_RGB888); 547 | ui->lblMovingImage->setPixmap(QPixmap::fromImage(qimgOriginal_PreMoving)); 548 | } 549 | else 550 | { 551 | QMessageBox msgBox; 552 | msgBox.setText("You are allowed to choose at most three points for Affine transform!\nShould you require to renew any point, a previously saved point must be eliminated!"); 553 | msgBox.setIcon(QMessageBox::Warning); 554 | msgBox.exec(); 555 | } 556 | break; 557 | 558 | case ETransformationType::Homography: 559 | referencePointsForHomography.push_back(cv::Point2f(pReference.x(), pReference.y())); 560 | movingPointsForHomography.push_back(cv::Point2f(pMoving.x(), pMoving.y())); 561 | 562 | disableReferenceImageMouseMove = false; 563 | disableMovingImageMouseMove = false; 564 | 565 | referencePointIsSelected = false; 566 | movingPointIsSelected = false; 567 | 568 | pairPointCounter++; 569 | ui->lblPairPointCounter->setText(QString("Selected Pair-Point Counts: " + QString::number(pairPointCounter))); 570 | 571 | if(pairPointCounter>0) 572 | { 573 | for (int i=0; ilblReferenceImage->setPixmap(QPixmap::fromImage(qimgOriginal_PreReference)); 582 | 583 | QImage qimgOriginal_PreMoving((uchar*)fullWindowMoving.data, fullWindowMoving.cols, fullWindowMoving.rows, fullWindowMoving.step, QImage::Format_RGB888); 584 | ui->lblMovingImage->setPixmap(QPixmap::fromImage(qimgOriginal_PreMoving)); 585 | 586 | break; 587 | } 588 | } 589 | } 590 | 591 | void MainUI::on_btnRemoveCurrentPoints_clicked() 592 | { 593 | disableReferenceImageMouseMove = false; 594 | disableMovingImageMouseMove = false; 595 | 596 | referencePointIsSelected = false; 597 | movingPointIsSelected = false; 598 | 599 | updateReferenceImage(); 600 | updateMovingImage(); 601 | } 602 | 603 | void MainUI::updateReferenceImage() 604 | { 605 | if (isReferenceAvailable) 606 | { 607 | cv::Mat fullWindowReference; 608 | 609 | if(isActiveReferenceImageCLAHE) 610 | { 611 | cv::Mat CLAHERGB; 612 | cv::cvtColor(convertedReferenceImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 613 | cv::resize(CLAHERGB, fullWindowReference, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 614 | } 615 | else 616 | cv::resize(convertedReferenceImage, fullWindowReference, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 617 | 618 | if(pairPointCounter>0) 619 | { 620 | switch (method) 621 | { 622 | case ETransformationType::Affine: 623 | for (int i=0; i< qMin(3, pairPointCounter) ; i++) 624 | { 625 | if (selectedPairIndex == i && haveSelectedPair) 626 | cv::circle(fullWindowReference, cv::Point((float)referencePointsForAffine[i].x/referenceRatioX, (float)referencePointsForAffine[i].y/referenceRatioY), 3, cv::Scalar(0,0,255), 4,-1); 627 | else 628 | cv::circle(fullWindowReference, cv::Point((float)referencePointsForAffine[i].x/referenceRatioX, (float)referencePointsForAffine[i].y/referenceRatioY), 3, cv::Scalar(0,255,0), 4,-1); 629 | } 630 | 631 | break; 632 | 633 | case ETransformationType::Homography: 634 | 635 | for (int i=0; ilblReferenceImage->setPixmap(QPixmap::fromImage(qimgOriginal_PreReference)); 649 | } 650 | } 651 | 652 | void MainUI::updateMovingImage() 653 | { 654 | if (isMovingAvailable) 655 | { 656 | cv::Mat fullWindowMoving; 657 | 658 | if(isActiveMovingImageCLAHE) 659 | { 660 | cv::Mat CLAHERGB; 661 | cv::cvtColor(convertedMovingImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 662 | cv::resize(CLAHERGB, fullWindowMoving, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 663 | } 664 | else 665 | cv::resize(convertedMovingImage, fullWindowMoving, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 666 | 667 | if(pairPointCounter>0) 668 | { 669 | switch (method) 670 | { 671 | case ETransformationType::Affine: 672 | for (int i=0; i< qMin(3, pairPointCounter); i++) 673 | { 674 | if (selectedPairIndex == i && haveSelectedPair) 675 | cv::circle(fullWindowMoving, cv::Point((float)movingPointsForAffine[i].x/movingRatioX, (float)movingPointsForAffine[i].y/movingRatioY), 3, cv::Scalar(0,0,255), 4,-1); 676 | else 677 | cv::circle(fullWindowMoving, cv::Point((float)movingPointsForAffine[i].x/movingRatioX, (float)movingPointsForAffine[i].y/movingRatioY), 3, cv::Scalar(0,255,0), 4,-1); 678 | } 679 | 680 | break; 681 | 682 | case ETransformationType::Homography: 683 | 684 | for (int i=0; ilblMovingImage->setPixmap(QPixmap::fromImage(qimgOriginal_PreMoving)); 697 | } 698 | } 699 | 700 | 701 | void MainUI::plotReferenceZoomedImage() 702 | { 703 | cv::Rect rectOnZoomed = cv::Rect(qRound(pReference.x()*zoomFactor - ui->lblZoomedReference->width()/2.0) 704 | , qRound(pReference.y()*zoomFactor - ui->lblZoomedReference->height()/2.0) 705 | , qMin(ui->lblZoomedReference->width(), enlargedReference.cols - qRound(pReference.x()*zoomFactor - ui->lblZoomedReference->width()/2.0)) 706 | , qMin(ui->lblZoomedReference->height(), enlargedReference.rows - qRound(pReference.y()*zoomFactor - ui->lblZoomedReference->height()/2.0))); 707 | 708 | int offsetX = 0; 709 | int offsetY = 0; 710 | 711 | if (rectOnZoomed.x < 0) 712 | { 713 | offsetX = rectOnZoomed.x; 714 | rectOnZoomed.width += offsetX; 715 | rectOnZoomed.x = 0; 716 | } 717 | if (rectOnZoomed.y < 0) 718 | { 719 | offsetY = rectOnZoomed.y; 720 | rectOnZoomed.height += offsetY; 721 | rectOnZoomed.y = 0; 722 | } 723 | if (rectOnZoomed.width < 0) 724 | rectOnZoomed.width = 0; 725 | if (rectOnZoomed.height < 0) 726 | rectOnZoomed.height = 0; 727 | 728 | cv::Mat ROIOnZoomed(enlargedReference, rectOnZoomed); 729 | cv::Mat ROIClone; 730 | ROIClone = ROIOnZoomed.clone(); 731 | if(ROIClone.channels() == 1) 732 | cv::cvtColor(ROIClone, ROIClone, CV_GRAY2RGB); 733 | 734 | cv::Mat resizedIm(ui->lblZoomedReference->height(), ui->lblZoomedReference->width(), convertedReferenceImage.type()); 735 | resizedIm.setTo(0); 736 | 737 | int min_x; 738 | int min_y; 739 | if (pReference.x() < ui->lblZoomedReference->width()/zoomFactor) 740 | { 741 | min_x = resizedIm.cols - ROIClone.cols; 742 | } 743 | else 744 | min_x = 0; 745 | 746 | 747 | if (pReference.y() < ui->lblZoomedReference->height()/referenceRatioY*zoomFactor) 748 | min_y = resizedIm.rows - ROIClone.rows; 749 | else 750 | min_y = 0; 751 | 752 | if (ROIClone.cols > 0 && ROIClone.rows >0) 753 | { 754 | cv::Mat A_roi(resizedIm, cv::Rect(min_x, min_y, ROIClone.cols, ROIClone.rows)); 755 | ROIClone.copyTo(A_roi); 756 | } 757 | 758 | cv::Mat zoomedWindow; 759 | cv::resize(resizedIm, zoomedWindow, cv::Size(ui->lblZoomedReference->width(), ui->lblZoomedReference->height()), 0,0,cv::INTER_LINEAR); 760 | cv::line(zoomedWindow, cv::Point(ui->lblZoomedReference->width()/2.0, 0), cv::Point(ui->lblZoomedReference->width()/2.0, ui->lblZoomedReference->height()), cv::Scalar(0,255,0)); 761 | cv::line(zoomedWindow, cv::Point(0, ui->lblZoomedReference->height()/2.0), cv::Point(ui->lblZoomedReference->width(), ui->lblZoomedReference->height()/2.0), cv::Scalar(0,255,0)); 762 | 763 | QImage qimg((uchar*)zoomedWindow.data, zoomedWindow.cols, zoomedWindow.rows, zoomedWindow.step, QImage::Format_RGB888); 764 | ui->lblZoomedReference->setPixmap(QPixmap::fromImage(qimg)); 765 | } 766 | 767 | void MainUI::plotMovingZoomedImage() 768 | { 769 | cv::Rect rectOnZoomed = cv::Rect(qRound(pMoving.x()*zoomFactor - ui->lblZoomedMoving->width()/2.0) 770 | , qRound(pMoving.y()*zoomFactor - ui->lblZoomedMoving->height()/2.0) 771 | , qMin(ui->lblZoomedMoving->width(), enlargedMoving.cols - qRound(pMoving.x()*zoomFactor - ui->lblZoomedMoving->width()/2.0)) 772 | , qMin(ui->lblZoomedMoving->height(), enlargedMoving.rows - qRound(pMoving.y()*zoomFactor - ui->lblZoomedMoving->height()/2.0))); 773 | 774 | int offsetX = 0; 775 | int offsetY = 0; 776 | 777 | if (rectOnZoomed.x < 0) 778 | { 779 | offsetX = rectOnZoomed.x; 780 | rectOnZoomed.width += offsetX; 781 | rectOnZoomed.x = 0; 782 | } 783 | if (rectOnZoomed.y < 0) 784 | { 785 | offsetY = rectOnZoomed.y; 786 | rectOnZoomed.height += offsetY; 787 | rectOnZoomed.y = 0; 788 | } 789 | if (rectOnZoomed.width < 0) 790 | rectOnZoomed.width = 0; 791 | if (rectOnZoomed.height < 0) 792 | rectOnZoomed.height = 0; 793 | 794 | cv::Mat ROIOnZoomed(enlargedMoving, rectOnZoomed); 795 | cv::Mat ROIClone; 796 | ROIClone = ROIOnZoomed.clone(); 797 | if(ROIClone.channels() == 1) 798 | cv::cvtColor(ROIClone, ROIClone, CV_GRAY2RGB); 799 | 800 | cv::Mat resizedIm(ui->lblZoomedMoving->height(), ui->lblZoomedMoving->width(), convertedMovingImage.type()); 801 | resizedIm.setTo(0); 802 | 803 | int min_x; 804 | int min_y; 805 | if (pMoving.x() < ui->lblZoomedMoving->width()/zoomFactor) 806 | { 807 | min_x = resizedIm.cols - ROIClone.cols; 808 | } 809 | else 810 | min_x = 0; 811 | 812 | 813 | if (pMoving.y() < ui->lblZoomedMoving->height()/movingRatioY*zoomFactor) 814 | min_y = resizedIm.rows - ROIClone.rows; 815 | else 816 | min_y = 0; 817 | 818 | if (ROIClone.cols > 0 && ROIClone.rows >0) 819 | { 820 | cv::Mat A_roi(resizedIm, cv::Rect(min_x, min_y, ROIClone.cols, ROIClone.rows)); 821 | ROIClone.copyTo(A_roi); 822 | } 823 | 824 | cv::Mat zoomedWindow; 825 | cv::resize(resizedIm, zoomedWindow, cv::Size(ui->lblZoomedMoving->width(), ui->lblZoomedMoving->height()), 0,0,cv::INTER_LINEAR); 826 | cv::line(zoomedWindow, cv::Point(ui->lblZoomedMoving->width()/2.0, 0), cv::Point(ui->lblZoomedMoving->width()/2.0, ui->lblZoomedMoving->height()), cv::Scalar(0,255,0)); 827 | cv::line(zoomedWindow, cv::Point(0, ui->lblZoomedMoving->height()/2.0), cv::Point(ui->lblZoomedMoving->width(), ui->lblZoomedMoving->height()/2.0), cv::Scalar(0,255,0)); 828 | 829 | QImage qimg((uchar*)zoomedWindow.data, zoomedWindow.cols, zoomedWindow.rows, zoomedWindow.step, QImage::Format_RGB888); 830 | ui->lblZoomedMoving->setPixmap(QPixmap::fromImage(qimg)); 831 | } 832 | 833 | void MainUI::on_btnSaveRegistered_clicked() 834 | { 835 | if (isRegisterationDone) 836 | { 837 | QString fileName = QFileDialog::getSaveFileName(this, 838 | tr("Select Path for Registered Image"), "" 839 | , tr("")); 840 | 841 | if(fileName.isEmpty()) 842 | { 843 | fileName = QString("RegisteredImage." + movingImageSuffix); 844 | } 845 | 846 | 847 | QFileInfo InputMap(fileName); 848 | QString fullName = fileName; 849 | if(InputMap.suffix() == "") 850 | fullName = QString(fullName + "." + movingImageSuffix); 851 | 852 | 853 | cv::cvtColor(warpDst, warpDst,CV_BGR2RGB); 854 | cv::imwrite(fullName.toLatin1().data(), warpDst); 855 | } 856 | else 857 | { 858 | QMessageBox msgBox; 859 | msgBox.setText("No Registered Images Available!"); 860 | msgBox.setIcon(QMessageBox::Warning); 861 | msgBox.exec(); 862 | } 863 | } 864 | 865 | void MainUI::on_btnClear_clicked() 866 | { 867 | disableReferenceImageMouseMove = false; 868 | disableMovingImageMouseMove = false; 869 | 870 | isReferenceAvailable = false; 871 | isMovingAvailable = false; 872 | 873 | isRegisterationDone = false; 874 | 875 | pairPointCounter = 0; 876 | ui->lblPairPointCounter->setText(QString("Selected Pair-Point Counts: " + QString::number(pairPointCounter))); 877 | 878 | movingPointsForHomography.clear(); 879 | referencePointsForHomography.clear(); 880 | 881 | for (int i = 0; i<3; i++) 882 | { 883 | referencePointsForAffine[i] = cv::Point2f(0.0,0.0); 884 | movingPointsForAffine[i] = cv::Point2f(0.0,0.0); 885 | } 886 | 887 | QImage QIm(ui->lblReferenceImage->width(), ui->lblReferenceImage->height(),QImage::Format_RGB888); 888 | QIm.fill(Qt::blue); 889 | ui->lblReferenceImage->setPixmap(QPixmap::fromImage(QIm)); 890 | ui->lblMovingImage->setPixmap(QPixmap::fromImage(QIm)); 891 | ui->lblZoomedReference->setPixmap(QPixmap::fromImage(QIm)); 892 | ui->lblZoomedMoving->setPixmap(QPixmap::fromImage(QIm)); 893 | 894 | QImage QImRegistered(ui->lblRegisteredImage->width(), ui->lblRegisteredImage->height(),QImage::Format_RGB888); 895 | QImRegistered.fill(Qt::blue); 896 | ui->lblRegisteredImage->setPixmap(QPixmap::fromImage(QImRegistered)); 897 | } 898 | 899 | void MainUI::on_dsbReferenceX_valueChanged(double arg1) 900 | { 901 | pReference.setX(arg1); 902 | 903 | drawReferenceZoomed(); 904 | } 905 | 906 | void MainUI::on_dsbReferenceY_valueChanged(double arg1) 907 | { 908 | pReference.setY(arg1); 909 | 910 | drawReferenceZoomed(); 911 | } 912 | 913 | void MainUI::drawReferenceZoomed() 914 | { 915 | cv::Rect rectOnZoomed = cv::Rect(qRound(pReference.x()*zoomFactor - ui->lblZoomedReference->width()/2.0) 916 | , qRound(pReference.y()*zoomFactor - ui->lblZoomedReference->height()/2.0) 917 | , qMin(ui->lblZoomedReference->width(), enlargedReference.cols - qRound(pReference.x()*zoomFactor - ui->lblZoomedReference->width()/2.0)) 918 | , qMin(ui->lblZoomedReference->height(), enlargedReference.rows - qRound(pReference.y()*zoomFactor - ui->lblZoomedReference->height()/2.0))); 919 | 920 | int offsetX = 0; 921 | int offsetY = 0; 922 | 923 | if (rectOnZoomed.x < 0) 924 | { 925 | offsetX = rectOnZoomed.x; 926 | rectOnZoomed.width += offsetX; 927 | rectOnZoomed.x = 0; 928 | } 929 | if (rectOnZoomed.y < 0) 930 | { 931 | offsetY = rectOnZoomed.y; 932 | rectOnZoomed.height += offsetY; 933 | rectOnZoomed.y = 0; 934 | } 935 | if (rectOnZoomed.width < 0) 936 | rectOnZoomed.width = 0; 937 | if (rectOnZoomed.height < 0) 938 | rectOnZoomed.height = 0; 939 | 940 | cv::Mat ROIOnZoomed(enlargedReference, rectOnZoomed); 941 | cv::Mat ROIClone; 942 | ROIClone = ROIOnZoomed.clone(); 943 | if(ROIClone.channels() == 1) 944 | cv::cvtColor(ROIClone, ROIClone, CV_GRAY2RGB); 945 | 946 | cv::Mat resizedIm(ui->lblZoomedReference->height(), ui->lblZoomedReference->width(), convertedReferenceImage.type()); 947 | resizedIm.setTo(0); 948 | 949 | int min_x; 950 | int min_y; 951 | if (pReference.x() < ui->lblZoomedReference->width()/zoomFactor) 952 | { 953 | min_x = resizedIm.cols - ROIClone.cols; 954 | } 955 | else 956 | min_x = 0; 957 | 958 | 959 | if (pReference.y() < ui->lblZoomedReference->height()/referenceRatioY*zoomFactor) 960 | min_y = resizedIm.rows - ROIClone.rows; 961 | else 962 | min_y = 0; 963 | if (ROIClone.cols > 0 && ROIClone.rows >0) 964 | { 965 | cv::Mat A_roi(resizedIm, cv::Rect(min_x, min_y, ROIClone.cols, ROIClone.rows)); 966 | ROIClone.copyTo(A_roi); 967 | } 968 | 969 | cv::Mat zoomedWindow; 970 | cv::resize(resizedIm, zoomedWindow, cv::Size(ui->lblZoomedReference->width(), ui->lblZoomedReference->height()), 0,0,cv::INTER_LINEAR); 971 | cv::line(zoomedWindow, cv::Point(ui->lblZoomedReference->width()/2.0, 0), cv::Point(ui->lblZoomedReference->width()/2.0, ui->lblZoomedReference->height()), cv::Scalar(0,255,0)); 972 | cv::line(zoomedWindow, cv::Point(0, ui->lblZoomedReference->height()/2.0), cv::Point(ui->lblZoomedReference->width(), ui->lblZoomedReference->height()/2.0), cv::Scalar(0,255,0)); 973 | 974 | QImage qimg((uchar*)zoomedWindow.data, zoomedWindow.cols, zoomedWindow.rows, zoomedWindow.step, QImage::Format_RGB888); 975 | ui->lblZoomedReference->setPixmap(QPixmap::fromImage(qimg)); 976 | 977 | cv::Mat fullWindow; 978 | if (isActiveReferenceImageCLAHE) 979 | { 980 | cv::Mat CLAHERGB; 981 | cv::cvtColor(convertedReferenceImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 982 | cv::resize(CLAHERGB, fullWindow, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 983 | } 984 | else 985 | cv::resize(convertedReferenceImage, fullWindow, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 986 | 987 | cv::circle(fullWindow, cv::Point((float)pReference.x()/referenceRatioX, (float)pReference.y()/referenceRatioY), 3, cv::Scalar(255,0,0), 4,-1); 988 | QImage qimgOriginal_Pre((uchar*)fullWindow.data, fullWindow.cols, fullWindow.rows, fullWindow.step, QImage::Format_RGB888); 989 | ui->lblReferenceImage->setPixmap(QPixmap::fromImage(qimgOriginal_Pre)); 990 | } 991 | 992 | void MainUI::on_dsbMovingX_valueChanged(double arg1) 993 | { 994 | pMoving.setX(arg1); 995 | 996 | drawMovingZoomed(); 997 | } 998 | 999 | void MainUI::on_dsbMovingY_valueChanged(double arg1) 1000 | { 1001 | pMoving.setY(arg1); 1002 | 1003 | drawMovingZoomed(); 1004 | } 1005 | 1006 | void MainUI::drawMovingZoomed() 1007 | { 1008 | cv::Rect rectOnZoomed = cv::Rect(qRound(pMoving.x()*zoomFactor - ui->lblZoomedMoving->width()/2.0) 1009 | , qRound(pMoving.y()*zoomFactor - ui->lblZoomedMoving->height()/2.0) 1010 | , qMin(ui->lblZoomedMoving->width(), enlargedMoving.cols - qRound(pMoving.x()*zoomFactor - ui->lblZoomedMoving->width()/2.0)) 1011 | , qMin(ui->lblZoomedMoving->height(), enlargedMoving.rows - qRound(pMoving.y()*zoomFactor - ui->lblZoomedMoving->height()/2.0))); 1012 | 1013 | int offsetX = 0; 1014 | int offsetY = 0; 1015 | 1016 | if (rectOnZoomed.x < 0) 1017 | { 1018 | offsetX = rectOnZoomed.x; 1019 | rectOnZoomed.width += offsetX; 1020 | rectOnZoomed.x = 0; 1021 | } 1022 | if (rectOnZoomed.y < 0) 1023 | { 1024 | offsetY = rectOnZoomed.y; 1025 | rectOnZoomed.height += offsetY; 1026 | rectOnZoomed.y = 0; 1027 | } 1028 | if (rectOnZoomed.width < 0) 1029 | rectOnZoomed.width = 0; 1030 | if (rectOnZoomed.height < 0) 1031 | rectOnZoomed.height = 0; 1032 | 1033 | cv::Mat ROIOnZoomed(enlargedMoving, rectOnZoomed); 1034 | cv::Mat ROIClone; 1035 | ROIClone = ROIOnZoomed.clone(); 1036 | if(ROIClone.channels() == 1) 1037 | cv::cvtColor(ROIClone, ROIClone, CV_GRAY2RGB); 1038 | 1039 | cv::Mat resizedIm(ui->lblZoomedMoving->height(), ui->lblZoomedMoving->width(), convertedMovingImage.type()); 1040 | resizedIm.setTo(0); 1041 | 1042 | int min_x; 1043 | int min_y; 1044 | if (pMoving.x() < ui->lblZoomedMoving->width()/zoomFactor) 1045 | { 1046 | min_x = resizedIm.cols - ROIClone.cols; 1047 | } 1048 | else 1049 | min_x = 0; 1050 | 1051 | 1052 | if (pMoving.y() < ui->lblZoomedMoving->height()/referenceRatioY*zoomFactor) 1053 | min_y = resizedIm.rows - ROIClone.rows; 1054 | else 1055 | min_y = 0; 1056 | if (ROIClone.cols > 0 && ROIClone.rows >0) 1057 | { 1058 | cv::Mat A_roi(resizedIm, cv::Rect(min_x, min_y, ROIClone.cols, ROIClone.rows)); 1059 | ROIClone.copyTo(A_roi); 1060 | } 1061 | 1062 | cv::Mat zoomedWindow; 1063 | cv::resize(resizedIm, zoomedWindow, cv::Size(ui->lblZoomedMoving->width(), ui->lblZoomedMoving->height()), 0,0,cv::INTER_LINEAR); 1064 | cv::line(zoomedWindow, cv::Point(ui->lblZoomedMoving->width()/2.0, 0), cv::Point(ui->lblZoomedMoving->width()/2.0, ui->lblZoomedMoving->height()), cv::Scalar(0,255,0)); 1065 | cv::line(zoomedWindow, cv::Point(0, ui->lblZoomedMoving->height()/2.0), cv::Point(ui->lblZoomedMoving->width(), ui->lblZoomedMoving->height()/2.0), cv::Scalar(0,255,0)); 1066 | 1067 | QImage qimg((uchar*)zoomedWindow.data, zoomedWindow.cols, zoomedWindow.rows, zoomedWindow.step, QImage::Format_RGB888); 1068 | ui->lblZoomedMoving->setPixmap(QPixmap::fromImage(qimg)); 1069 | 1070 | cv::Mat fullWindow; 1071 | if (isActiveMovingImageCLAHE) 1072 | { 1073 | cv::Mat CLAHERGB; 1074 | cv::cvtColor(convertedMovingImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 1075 | cv::resize(CLAHERGB, fullWindow, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 1076 | } 1077 | else 1078 | cv::resize(convertedMovingImage, fullWindow, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 1079 | 1080 | cv::circle(fullWindow, cv::Point((float)pMoving.x()/movingRatioX, (float)pMoving.y()/movingRatioY), 3, cv::Scalar(255,0,0), 4,-1); 1081 | QImage qimgOriginal_Pre((uchar*)fullWindow.data, fullWindow.cols, fullWindow.rows, fullWindow.step, QImage::Format_RGB888); 1082 | ui->lblMovingImage->setPixmap(QPixmap::fromImage(qimgOriginal_Pre)); 1083 | } 1084 | 1085 | void MainUI::on_btnSaveImshowPair_clicked() 1086 | { 1087 | if (isRegisterationDone) 1088 | { 1089 | QString fileName = QFileDialog::getSaveFileName(this, 1090 | tr("Select Path for ImshowPair Image"), "" 1091 | , tr("")); 1092 | 1093 | if(fileName.isEmpty()) 1094 | { 1095 | fileName = QString("ImShowPair." + movingImageSuffix); 1096 | } 1097 | 1098 | 1099 | QFileInfo InputMap(fileName); 1100 | QString fullName = fileName; 1101 | if(InputMap.suffix() == "") 1102 | fullName = QString(fullName + "." + movingImageSuffix); 1103 | 1104 | 1105 | cv::cvtColor(imShowPair, imShowPair,CV_BGR2RGB); 1106 | cv::imwrite(fullName.toLatin1().data(), imShowPair); 1107 | } 1108 | else 1109 | { 1110 | QMessageBox msgBox; 1111 | msgBox.setText("No Registered Images Available!"); 1112 | msgBox.setIcon(QMessageBox::Warning); 1113 | msgBox.exec(); 1114 | } 1115 | } 1116 | 1117 | void MainUI::on_actionAffine_triggered() 1118 | { 1119 | controlPointDialog->show(); 1120 | } 1121 | 1122 | void MainUI::on_actionHomography_triggered() 1123 | { 1124 | method = ETransformationType(Homography); 1125 | ui->lblMethod->setText("Homography"); 1126 | ui->lblNumPointRequired->setText("The Required Number of Points: >4,\n(7 to 10 works fine!)"); 1127 | 1128 | referencePointsForHomography.clear(); 1129 | movingPointsForHomography.clear(); 1130 | 1131 | for (int i=0; i < qMin(3, pairPointCounter); i++) 1132 | { 1133 | referencePointsForHomography.push_back(cv::Point2f(referencePointsForAffine[i].x, referencePointsForAffine[i].y)); 1134 | movingPointsForHomography.push_back(cv::Point2f(movingPointsForAffine[i].x, movingPointsForAffine[i].y)); 1135 | } 1136 | 1137 | pairPointCounter = 3; 1138 | } 1139 | 1140 | void MainUI::sltReceiveOkForControlPointRemoval() 1141 | { 1142 | method = ETransformationType(Affine); 1143 | ui->lblMethod->setText("Affine"); 1144 | ui->lblNumPointRequired->setText("The Required Number of Points: 3"); 1145 | 1146 | if (isReferenceAvailable && isMovingAvailable) 1147 | { 1148 | pairPointCounter = qMin(3, pairPointCounter); 1149 | 1150 | for (int i=0; i < qMin(3, pairPointCounter) ; i++) 1151 | { 1152 | referencePointsForAffine[i] = cv::Point2f(referencePointsForHomography[i].x, referencePointsForHomography[i].y); 1153 | movingPointsForAffine[i] = cv::Point2f(movingPointsForHomography[i].x, movingPointsForHomography[i].y); 1154 | } 1155 | 1156 | referencePointsForHomography.clear(); 1157 | movingPointsForHomography.clear(); 1158 | 1159 | updateReferenceImage(); 1160 | updateMovingImage(); 1161 | } 1162 | } 1163 | 1164 | void MainUI::on_chbMovingContrastEnhancement_toggled(bool checked) 1165 | { 1166 | isActiveMovingImageCLAHE = checked; 1167 | 1168 | if (isMovingAvailable) 1169 | { 1170 | if(checked) 1171 | { 1172 | cv::Ptr clahe = cv::createCLAHE(); 1173 | clahe->setClipLimit(4); 1174 | cv::cvtColor(convertedMovingImage, convertedMovingImage_CLAHE, CV_RGB2GRAY); 1175 | clahe->apply(convertedMovingImage_CLAHE, convertedMovingImage_CLAHE); 1176 | 1177 | if(!enlargedMoving.empty()) 1178 | enlargedMoving.release(); 1179 | cv::resize(convertedMovingImage_CLAHE, enlargedMoving, 1180 | cv::Size(zoomFactor*convertedMovingImage_CLAHE.cols, zoomFactor*convertedMovingImage_CLAHE.rows), 0,0,cv::INTER_LINEAR); 1181 | 1182 | cv::Mat CLAHERGB; 1183 | cv::Mat fullWindowMoving; 1184 | cv::cvtColor(convertedMovingImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 1185 | cv::resize(CLAHERGB, fullWindowMoving, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 1186 | 1187 | if(disableMovingImageMouseMove) 1188 | cv::circle(fullWindowMoving, cv::Point((float)pMoving.x()/movingRatioX, (float)pMoving.y()/movingRatioY), 3, cv::Scalar(255,0,0), 4,-1); 1189 | else 1190 | { 1191 | if(pairPointCounter>0) 1192 | { 1193 | switch (method) 1194 | { 1195 | case ETransformationType::Affine: 1196 | for (int i=0; i< qMin(3, pairPointCounter) ; i++) 1197 | { 1198 | cv::circle(fullWindowMoving, cv::Point((float)movingPointsForAffine[i].x/movingRatioX, (float)movingPointsForAffine[i].y/movingRatioY), 3, cv::Scalar(0,255,0), 4,-1); 1199 | } 1200 | 1201 | break; 1202 | 1203 | case ETransformationType::Homography: 1204 | 1205 | for (int i=0; ilblMovingImage->setPixmap(QPixmap::fromImage(qimgOriginal_Pre)); 1216 | } 1217 | else 1218 | { 1219 | if(!enlargedMoving.empty()) 1220 | enlargedMoving.release(); 1221 | cv::resize(convertedMovingImage, enlargedMoving, cv::Size(zoomFactor*convertedMovingImage.cols, zoomFactor*convertedMovingImage.rows), 0,0,cv::INTER_LINEAR); 1222 | 1223 | cv::Mat fullWindowMoving; 1224 | cv::resize(convertedMovingImage, fullWindowMoving, 1225 | cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 1226 | 1227 | if(disableMovingImageMouseMove) 1228 | { 1229 | cv::circle(fullWindowMoving, cv::Point((float)pMoving.x()/movingRatioX, (float)pMoving.y()/movingRatioY), 3, cv::Scalar(255,0,0), 4,-1); 1230 | drawMovingZoomed(); 1231 | } 1232 | else 1233 | { 1234 | if(pairPointCounter>0) 1235 | { 1236 | switch (method) 1237 | { 1238 | case ETransformationType::Affine: 1239 | for (int i=0; i< qMin(3, pairPointCounter) ; i++) 1240 | { 1241 | cv::circle(fullWindowMoving, cv::Point((float)movingPointsForAffine[i].x/movingRatioX, (float)movingPointsForAffine[i].y/movingRatioY), 3, cv::Scalar(0,255,0), 4,-1); 1242 | } 1243 | 1244 | break; 1245 | 1246 | case ETransformationType::Homography: 1247 | 1248 | for (int i=0; ilblMovingImage->setPixmap(QPixmap::fromImage(qimgOriginal_Pre)); 1259 | } 1260 | } 1261 | } 1262 | 1263 | void MainUI::on_chbReferenceContrastEnhancement_toggled(bool checked) 1264 | { 1265 | isActiveReferenceImageCLAHE = checked; 1266 | 1267 | if (isReferenceAvailable) 1268 | { 1269 | if(checked) 1270 | { 1271 | cv::Ptr clahe = cv::createCLAHE(); 1272 | clahe->setClipLimit(4); 1273 | cv::cvtColor(convertedReferenceImage, convertedReferenceImage_CLAHE, CV_RGB2GRAY); 1274 | clahe->apply(convertedReferenceImage_CLAHE, convertedReferenceImage_CLAHE); 1275 | 1276 | if(!enlargedReference.empty()) 1277 | enlargedReference.release(); 1278 | cv::resize(convertedReferenceImage_CLAHE, enlargedReference, 1279 | cv::Size(zoomFactor*convertedReferenceImage_CLAHE.cols, zoomFactor*convertedReferenceImage_CLAHE.rows), 0,0,cv::INTER_LINEAR); 1280 | 1281 | cv::Mat CLAHERGB; 1282 | cv::Mat fullWindowReference; 1283 | cv::cvtColor(convertedReferenceImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 1284 | cv::resize(CLAHERGB, fullWindowReference, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 1285 | 1286 | if(disableReferenceImageMouseMove) 1287 | cv::circle(fullWindowReference, cv::Point((float)pReference.x()/referenceRatioX, (float)pReference.y()/referenceRatioY), 3, cv::Scalar(255,0,0), 4,-1); 1288 | else 1289 | { 1290 | if(pairPointCounter>0) 1291 | { 1292 | switch (method) 1293 | { 1294 | case ETransformationType::Affine: 1295 | for (int i=0; i< qMin(3, pairPointCounter) ; i++) 1296 | { 1297 | cv::circle(fullWindowReference, cv::Point((float)referencePointsForAffine[i].x/referenceRatioX, (float)referencePointsForAffine[i].y/referenceRatioY), 3, cv::Scalar(0,255,0), 4,-1); 1298 | } 1299 | 1300 | break; 1301 | 1302 | case ETransformationType::Homography: 1303 | 1304 | for (int i=0; ilblReferenceImage->setPixmap(QPixmap::fromImage(qImg)); 1315 | } 1316 | else 1317 | { 1318 | if(!enlargedReference.empty()) 1319 | enlargedReference.release(); 1320 | cv::resize(convertedReferenceImage, enlargedReference, cv::Size(zoomFactor*convertedReferenceImage.cols, zoomFactor*convertedReferenceImage.rows), 0,0,cv::INTER_LINEAR); 1321 | 1322 | cv::Mat fullWindowReference; 1323 | cv::resize(convertedReferenceImage, fullWindowReference, 1324 | cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 1325 | 1326 | if(disableReferenceImageMouseMove) 1327 | { 1328 | cv::circle(fullWindowReference, cv::Point((float)pReference.x()/referenceRatioX, (float)pReference.y()/referenceRatioY), 3, cv::Scalar(255,0,0), 4,-1); 1329 | drawReferenceZoomed(); 1330 | } 1331 | else 1332 | { 1333 | if(pairPointCounter>0) 1334 | { 1335 | switch (method) 1336 | { 1337 | case ETransformationType::Affine: 1338 | for (int i=0; i< qMin(3, pairPointCounter) ; i++) 1339 | { 1340 | cv::circle(fullWindowReference, cv::Point((float)referencePointsForAffine[i].x/referenceRatioX, (float)referencePointsForAffine[i].y/referenceRatioY), 3, cv::Scalar(0,255,0), 4,-1); 1341 | } 1342 | 1343 | break; 1344 | 1345 | case ETransformationType::Homography: 1346 | 1347 | for (int i=0; ilblReferenceImage->setPixmap(QPixmap::fromImage(qImg)); 1358 | } 1359 | } 1360 | } 1361 | 1362 | void MainUI::on_btnSaveControlPoints_clicked() 1363 | { 1364 | QString fileName = QFileDialog::getSaveFileName(this, 1365 | tr("Select Path for Control Points"), "" 1366 | , tr("*.txt")); 1367 | 1368 | if(fileName.isEmpty()) 1369 | { 1370 | qDebug() << "The specified file name is empty!"; 1371 | fileName = "controlPoints.txt"; 1372 | } 1373 | 1374 | QFileInfo InputMap(fileName); 1375 | QString fullName = fileName; 1376 | if(InputMap.suffix() == "") 1377 | fullName = QString(fullName + ".txt"); 1378 | 1379 | std::ofstream controlPoints; 1380 | controlPoints.open(fileName.toLatin1().data()); 1381 | 1382 | if (controlPoints.is_open()) 1383 | { 1384 | switch (method) 1385 | { 1386 | case ETransformationType::Affine: 1387 | controlPoints << "Affine\n"; 1388 | for (int i=0; i< qMin(3, pairPointCounter); i++) 1389 | { 1390 | controlPoints << (float)referencePointsForAffine[i].x << "," << (float)referencePointsForAffine[i].y 1391 | << "," << (float)movingPointsForAffine[i].x << "," <<(float)movingPointsForAffine[i].y << "\n"; 1392 | } 1393 | 1394 | break; 1395 | case ETransformationType::Homography: 1396 | controlPoints << "Homography\n"; 1397 | for (int i=0; ilblMethod->setText("Affine"); 1437 | ui->lblNumPointRequired->setText("The Required Number of Points: 3"); 1438 | 1439 | for (int i = 0; i<3; i++) 1440 | { 1441 | referencePointsForAffine[i] = cv::Point2f(0.0,0.0); 1442 | movingPointsForAffine[i] = cv::Point2f(0.0,0.0); 1443 | } 1444 | } 1445 | else if(line == "Homography") 1446 | { 1447 | method = ETransformationType(Homography); 1448 | 1449 | ui->lblMethod->setText("Homography"); 1450 | ui->lblNumPointRequired->setText("The Required Number of Points: >4,\n(7 to 10 works fine!)"); 1451 | 1452 | referencePointsForHomography.clear(); 1453 | movingPointsForHomography.clear(); 1454 | } 1455 | else if (line != "") 1456 | { 1457 | QStringList list = line.split(","); 1458 | if(method == ETransformationType(Affine)) 1459 | { 1460 | referencePointsForAffine[pairPointCounter] = cv::Point2f(list[0].toFloat(), list[1].toFloat()); 1461 | movingPointsForAffine[pairPointCounter] = cv::Point2f(list[2].toFloat(), list[3].toFloat()); 1462 | } 1463 | else if(ETransformationType(Homography)) 1464 | { 1465 | referencePointsForHomography.push_back(cv::Point2f(list[0].toFloat(), list[1].toFloat())); 1466 | movingPointsForHomography.push_back(cv::Point2f(list[2].toFloat(), list[3].toFloat())); 1467 | } 1468 | pairPointCounter++; 1469 | ui->lblPairPointCounter->setText(QString("Selected Pair-Point Counts: " + QString::number(pairPointCounter))); 1470 | } 1471 | } 1472 | 1473 | cv::Mat fullWindowReference; 1474 | if (isActiveReferenceImageCLAHE) 1475 | { 1476 | cv::Mat CLAHERGB; 1477 | cv::cvtColor(convertedReferenceImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 1478 | cv::resize(CLAHERGB, fullWindowReference, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 1479 | } 1480 | else 1481 | cv::resize(convertedReferenceImage, fullWindowReference, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 1482 | 1483 | cv::Mat fullWindowMoving; 1484 | if (isActiveMovingImageCLAHE) 1485 | { 1486 | cv::Mat CLAHERGB; 1487 | cv::cvtColor(convertedMovingImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 1488 | cv::resize(CLAHERGB, fullWindowMoving, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 1489 | } 1490 | else 1491 | cv::resize(convertedMovingImage, fullWindowMoving, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 1492 | 1493 | if (isReferenceAvailable && isMovingAvailable) 1494 | { 1495 | disableReferenceImageMouseMove = false; 1496 | disableMovingImageMouseMove = false; 1497 | 1498 | referencePointIsSelected = false; 1499 | movingPointIsSelected = false; 1500 | 1501 | if(pairPointCounter>0) 1502 | { 1503 | switch (method) 1504 | { 1505 | case ETransformationType::Affine: 1506 | 1507 | for (int i=0; ilblReferenceImage->setPixmap(QPixmap::fromImage(qimgOriginal_PreReference)); 1529 | QImage qimgOriginal_PreMoving((uchar*)fullWindowMoving.data, fullWindowMoving.cols, fullWindowMoving.rows, fullWindowMoving.step, QImage::Format_RGB888); 1530 | ui->lblMovingImage->setPixmap(QPixmap::fromImage(qimgOriginal_PreMoving)); 1531 | } 1532 | file.close(); 1533 | } 1534 | else 1535 | { 1536 | QMessageBox msgBox; 1537 | msgBox.setText("The text file containing control points cannot be opened!"); 1538 | msgBox.setIcon(QMessageBox::Warning); 1539 | msgBox.exec(); 1540 | } 1541 | } 1542 | else 1543 | { 1544 | QMessageBox msgBox; 1545 | msgBox.setText("Either Reference or Moving image is not loaded properly!"); 1546 | msgBox.setIcon(QMessageBox::Warning); 1547 | msgBox.exec(); 1548 | } 1549 | } 1550 | 1551 | void MainUI::on_btnClearControlPoints_clicked() 1552 | { 1553 | disableReferenceImageMouseMove = false; 1554 | disableMovingImageMouseMove = false; 1555 | 1556 | referencePointIsSelected = false; 1557 | movingPointIsSelected = false; 1558 | 1559 | isRegisterationDone = false; 1560 | 1561 | pairPointCounter = 0; 1562 | ui->lblPairPointCounter->setText(QString("Selected Pair-Point Counts: " + QString::number(pairPointCounter))); 1563 | 1564 | movingPointsForHomography.clear(); 1565 | referencePointsForHomography.clear(); 1566 | 1567 | for (int i = 0; i<3; i++) 1568 | { 1569 | referencePointsForAffine[i] = cv::Point2f(0.0,0.0); 1570 | movingPointsForAffine[i] = cv::Point2f(0.0,0.0); 1571 | } 1572 | 1573 | if (isReferenceAvailable) 1574 | { 1575 | cv::Mat fullWindowReference; 1576 | if(isActiveReferenceImageCLAHE) 1577 | { 1578 | cv::Mat CLAHERGB; 1579 | cv::cvtColor(convertedReferenceImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 1580 | cv::resize(CLAHERGB, fullWindowReference, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 1581 | } 1582 | else 1583 | cv::resize(convertedReferenceImage, fullWindowReference, cv::Size(ui->lblReferenceImage->width(), ui->lblReferenceImage->height()), 0,0,cv::INTER_LINEAR); 1584 | 1585 | QImage qimg((uchar*)fullWindowReference.data, fullWindowReference.cols, 1586 | fullWindowReference.rows, fullWindowReference.step, QImage::Format_RGB888); 1587 | ui->lblReferenceImage->setPixmap(QPixmap::fromImage(qimg)); 1588 | } 1589 | 1590 | if (isMovingAvailable) 1591 | { 1592 | cv::Mat fullWindowMoving; 1593 | if(isActiveMovingImageCLAHE) 1594 | { 1595 | cv::Mat CLAHERGB; 1596 | cv::cvtColor(convertedMovingImage_CLAHE, CLAHERGB, CV_GRAY2RGB); 1597 | cv::resize(CLAHERGB, fullWindowMoving, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 1598 | } 1599 | else 1600 | cv::resize(convertedMovingImage, fullWindowMoving, cv::Size(ui->lblMovingImage->width(), ui->lblMovingImage->height()), 0,0,cv::INTER_LINEAR); 1601 | 1602 | QImage qimg((uchar*)fullWindowMoving.data, fullWindowMoving.cols, 1603 | fullWindowMoving.rows, fullWindowMoving.step, QImage::Format_RGB888); 1604 | ui->lblMovingImage->setPixmap(QPixmap::fromImage(qimg)); 1605 | } 1606 | } 1607 | 1608 | void MainUI::on_btnApplyToAll_clicked() 1609 | { 1610 | if (isRegisterationDone) 1611 | { 1612 | seqPath = QFileDialog::getExistingDirectory(this, tr("Select the Directory Containing the Moving and Reference Folders"), 1613 | "", 1614 | QFileDialog::ShowDirsOnly 1615 | | QFileDialog::DontResolveSymlinks); 1616 | if (seqPath == "") 1617 | return; 1618 | 1619 | QString referenceFolder = QString(referenceImagePath + "/"); 1620 | QDir referenceDirectory(referenceFolder); 1621 | QStringList referenceImages = referenceDirectory.entryList(QStringList() << QString("*." + movingImageSuffix),QDir::Files); 1622 | 1623 | QString movingFolder = QString(movingImagePath + "/");; 1624 | QDir movingDirectory(movingFolder); 1625 | QStringList movingImages = movingDirectory.entryList(QStringList() << QString("*." + movingImageSuffix) ,QDir::Files); 1626 | 1627 | cv::Mat affineWarpMat(2, 3, CV_32FC1); 1628 | cv::Mat homographyWarpMat(3, 3, CV_32FC1); 1629 | std::vector channels; 1630 | cv::Mat imgPair; 1631 | cv::Mat paddedImage; 1632 | cv::Mat matOriginal_Gray; 1633 | cv::Mat warpDst_Gray; 1634 | cv::Mat movingWarpDst; 1635 | 1636 | int index = 0; 1637 | 1638 | QString referenceFileName; 1639 | QString movingFileName; 1640 | cv::Mat referenceInput; 1641 | cv::Mat movingInput; 1642 | 1643 | QDir().mkdir(QString(seqPath + "/Results")); 1644 | QDir().mkdir(QString(seqPath + "/Results/Registered Moving Images")); 1645 | QDir().mkdir(QString(seqPath + "/Results/ImShowPairs")); 1646 | 1647 | switch (method) 1648 | { 1649 | case ETransformationType::Affine: 1650 | 1651 | affineWarpMat = cv::getAffineTransform(movingPointsForAffine, referencePointsForAffine); 1652 | 1653 | while (index < referenceImages.length() && index < movingImages.length()) 1654 | { 1655 | referenceFileName = referenceFolder + referenceImages.at(index); 1656 | movingFileName = movingFolder + movingImages.at(index); 1657 | 1658 | referenceInput = cv::imread(referenceFileName.toLatin1().data()); 1659 | movingInput = cv::imread(movingFileName.toLatin1().data()); 1660 | 1661 | qDebug() << movingFileName.toLatin1().data() << movingInput.cols << movingInput.rows; 1662 | 1663 | cv::warpAffine(movingInput, movingWarpDst, affineWarpMat, movingWarpDst.size()); 1664 | 1665 | cv::imwrite(QString(seqPath + "/Results/Registered Moving Images/" 1666 | + QString(movingImages.at(index)).split(".",QString::SkipEmptyParts).at(0) 1667 | + "." + movingImageSuffix).toLatin1().data(), movingWarpDst); 1668 | 1669 | cv::cvtColor(referenceInput, matOriginal_Gray, CV_RGB2GRAY); 1670 | cv::cvtColor(movingWarpDst, warpDst_Gray, CV_RGB2GRAY); 1671 | 1672 | if(matOriginal_Gray.cols >= movingWarpDst.cols) 1673 | { 1674 | paddedImage.create(matOriginal_Gray.rows, matOriginal_Gray.cols, CV_8UC1); 1675 | paddedImage.setTo(0); 1676 | 1677 | cv::Mat ROI(paddedImage, cv::Rect(0, 0, movingWarpDst.cols, movingWarpDst.rows)); 1678 | warpDst_Gray.copyTo(ROI); 1679 | 1680 | channels.push_back(matOriginal_Gray); 1681 | channels.push_back(paddedImage); 1682 | channels.push_back(matOriginal_Gray); 1683 | 1684 | merge(channels, imgPair); 1685 | } 1686 | else 1687 | { 1688 | paddedImage.create(movingWarpDst.rows, movingWarpDst.cols, CV_8UC1); 1689 | paddedImage.setTo(0); 1690 | cv::Mat ROI(paddedImage, cv::Rect(0, 0, matOriginal_Gray.cols, matOriginal_Gray.rows)); 1691 | matOriginal_Gray.copyTo(ROI); 1692 | 1693 | channels.push_back(warpDst_Gray); 1694 | channels.push_back(paddedImage); 1695 | channels.push_back(warpDst_Gray); 1696 | 1697 | merge(channels, imgPair); 1698 | } 1699 | 1700 | cv::imwrite(QString(seqPath + "/Results/ImShowPairs/" 1701 | + "ImShowPair_" + QString(movingImages.at(index++)).split(".",QString::SkipEmptyParts).at(0) 1702 | + "." + movingImageSuffix).toLatin1().data(), imgPair); 1703 | 1704 | channels.clear(); 1705 | } 1706 | break; 1707 | case ETransformationType::Homography: 1708 | 1709 | // Find homography 1710 | homographyWarpMat = findHomography(movingPointsForHomography, referencePointsForHomography, cv::RANSAC );//LMEDS,RANSAC,RHO 1711 | 1712 | while (index < referenceImages.length() && index < movingImages.length()) 1713 | { 1714 | referenceFileName = referenceFolder + referenceImages.at(index); 1715 | movingFileName = movingFolder + movingImages.at(index); 1716 | 1717 | referenceInput = cv::imread(referenceFileName.toLatin1().data()); 1718 | movingInput = cv::imread(movingFileName.toLatin1().data()); 1719 | 1720 | // Use homography to warp image 1721 | cv::warpPerspective(movingInput, movingWarpDst, homographyWarpMat, movingWarpDst.size()); 1722 | 1723 | cv::imwrite(QString(seqPath + "/Results/Registered Moving Images/" 1724 | + QString(movingImages.at(index)).split(".",QString::SkipEmptyParts).at(0) 1725 | + "." + movingImageSuffix).toLatin1().data(), movingWarpDst); 1726 | 1727 | cv::cvtColor(referenceInput, matOriginal_Gray, CV_RGB2GRAY); 1728 | cv::cvtColor(movingWarpDst, warpDst_Gray, CV_RGB2GRAY); 1729 | 1730 | if(matOriginal_Gray.cols >= movingWarpDst.cols) 1731 | { 1732 | paddedImage.create(matOriginal_Gray.rows, matOriginal_Gray.cols, CV_8UC1); 1733 | paddedImage.setTo(0); 1734 | 1735 | cv::Mat ROI(paddedImage, cv::Rect(0, 0, movingWarpDst.cols, movingWarpDst.rows)); 1736 | warpDst_Gray.copyTo(ROI); 1737 | 1738 | channels.push_back(matOriginal_Gray); 1739 | channels.push_back(paddedImage); 1740 | channels.push_back(matOriginal_Gray); 1741 | 1742 | merge(channels, imgPair); 1743 | } 1744 | else 1745 | { 1746 | paddedImage.create(movingWarpDst.rows, movingWarpDst.cols, CV_8UC1); 1747 | paddedImage.setTo(0); 1748 | cv::Mat ROI(paddedImage, cv::Rect(0, 0, matOriginal_Gray.cols, matOriginal_Gray.rows)); 1749 | matOriginal_Gray.copyTo(ROI); 1750 | 1751 | channels.push_back(warpDst_Gray); 1752 | channels.push_back(paddedImage); 1753 | channels.push_back(warpDst_Gray); 1754 | 1755 | merge(channels, imgPair); 1756 | } 1757 | 1758 | cv::imwrite(QString(seqPath + "/Results/ImShowPairs/" 1759 | + "ImShowPair_" + QString(movingImages.at(index++)).split(".",QString::SkipEmptyParts).at(0) 1760 | + "." + movingImageSuffix).toLatin1().data(), imgPair); 1761 | 1762 | channels.clear(); 1763 | } 1764 | break; 1765 | } 1766 | } 1767 | else 1768 | { 1769 | QMessageBox msgBox; 1770 | msgBox.setText("Registration is not completed yet!\nPlease register a pair of moving-reference images first."); 1771 | msgBox.setIcon(QMessageBox::Warning); 1772 | msgBox.exec(); 1773 | } 1774 | } 1775 | 1776 | 1777 | void MainUI::on_btnRemoveSelectedPoints_clicked() 1778 | { 1779 | if (!haveSelectedPair) 1780 | { 1781 | QMessageBox msgBox; 1782 | msgBox.setText("No pair is selected for removal yet.\nFor selecting a pair, double click on a point on either reference or moving images."); 1783 | msgBox.setIcon(QMessageBox::Warning); 1784 | msgBox.exec(); 1785 | } 1786 | else 1787 | { 1788 | if (pairPointCounter > 0) 1789 | { 1790 | switch (method) 1791 | { 1792 | case ETransformationType::Affine: 1793 | if (selectedPairIndex == 0) 1794 | { 1795 | referencePointsForAffine[0] = referencePointsForAffine[1]; 1796 | referencePointsForAffine[1] = referencePointsForAffine[2]; 1797 | referencePointsForAffine[2] = cv::Point2f(0.0,0.0); 1798 | 1799 | movingPointsForAffine[0] = movingPointsForAffine[1]; 1800 | movingPointsForAffine[1] = movingPointsForAffine[2]; 1801 | movingPointsForAffine[2] = cv::Point2f(0.0,0.0); 1802 | } 1803 | else if (selectedPairIndex == 1) 1804 | { 1805 | referencePointsForAffine[1] = referencePointsForAffine[2]; 1806 | referencePointsForAffine[2] = cv::Point2f(0.0,0.0); 1807 | 1808 | movingPointsForAffine[1] = movingPointsForAffine[2]; 1809 | movingPointsForAffine[2] = cv::Point2f(0.0,0.0); 1810 | } 1811 | else if (selectedPairIndex == 2) 1812 | { 1813 | referencePointsForAffine[2] = cv::Point2f(0.0,0.0); 1814 | 1815 | movingPointsForAffine[2] = cv::Point2f(0.0,0.0); 1816 | } 1817 | 1818 | break; 1819 | case ETransformationType::Homography: 1820 | referencePointsForHomography.erase(referencePointsForHomography.begin() + selectedPairIndex); 1821 | movingPointsForHomography.erase(movingPointsForHomography.begin() + selectedPairIndex); 1822 | 1823 | break; 1824 | } 1825 | 1826 | pairPointCounter--; 1827 | 1828 | selectedPairIndex = -1; 1829 | haveSelectedPair = false; 1830 | 1831 | updateReferenceImage(); 1832 | updateMovingImage(); 1833 | } 1834 | } 1835 | } 1836 | --------------------------------------------------------------------------------