├── .gitignore ├── README.md ├── cvmatandqimage.cpp ├── cvmatandqimage.h ├── examples ├── capture │ ├── cameradevice.cpp │ ├── cameradevice.h │ ├── capture.pro │ ├── dialog.cpp │ ├── dialog.h │ ├── dialog.ui │ └── main.cpp ├── colorchannel │ ├── colorchannel.pro │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ └── mainwindow.ui ├── examples.pro ├── imagefft │ ├── dialog.cpp │ ├── dialog.h │ ├── dialog.ui │ ├── imagefft.pro │ └── main.cpp ├── imageprocess │ ├── convert.cpp │ ├── convert.h │ ├── imageprocess.pro │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── mainwindow.ui │ ├── recentfiles.cpp │ └── recentfiles.h ├── shared │ ├── cvimagewidget.cpp │ ├── cvimagewidget.h │ └── shared.pri └── simple │ ├── main.cpp │ └── simple.pro ├── opencv.pri ├── opencv_prf_generator.py └── tests ├── testcvmatandimage ├── testcvmatandimage.pro └── tst_cvmatandimagetest.cpp └── tests.pro /.gitignore: -------------------------------------------------------------------------------- 1 | # common 2 | *~ 3 | *.a 4 | *.core 5 | *.moc 6 | *.o 7 | *.obj 8 | *.orig 9 | *.rej 10 | *.so 11 | *_pch.h.cpp 12 | *_resource.rc 13 | *.qm 14 | .#* 15 | *.*# 16 | tags 17 | .DS_Store 18 | *.debug 19 | Makefile* 20 | *.prl 21 | *.app 22 | moc_*.cpp 23 | ui_*.h 24 | qrc_*.cpp 25 | Thumbs.db 26 | # KDE 27 | .directory 28 | 29 | # python temporary files 30 | *.pyc 31 | 32 | # nsis files... 33 | nsis/dlls/* 34 | nsis/*.exe 35 | 36 | # qtcreator generated files 37 | *.pro.user* 38 | *.qmlproject.user* 39 | *.pluginspec 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *.vcxproj* 56 | *vcproj.*.*.user 57 | *vcxproj.*.*.user 58 | *.ncb 59 | *.opensdf 60 | *.sdf 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Directories to ignore 67 | # --------------------- 68 | 69 | temp 70 | debug 71 | lib/* 72 | lib64/* 73 | release 74 | doc/html/* 75 | ipch/* 76 | 77 | .rcc 78 | .pch 79 | 80 | opencv.prf 81 | 82 | # Binaries 83 | # -------- 84 | bin/** 85 | 86 | # Tests 87 | #------ 88 | tests/auto 89 | tests/valgrind 90 | tests/*/*/tst_* 91 | !tests/*/*/tst_*.cpp 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## About QtOpenCV 2 | 3 | * QtOpenCV provides some helper functions to converting cv::Mat from/to QImage. 4 | 5 | * QtOpenCV provides a opencv.pri file which can be used to integrate OpenCV2 or newer to qmake-based project. 6 | 7 | ## cv::Mat <==> QImage 8 | 9 | * Download and copy the `cvmatandqimage.cpp` `cvmatandqimage.h` and `opencv.pri` to your project's source tree. 10 | 11 | * Then take advantage of the following API to converting data between Cv::Mat and QImage. 12 | 13 | ```cpp 14 | namespace QtOcv { 15 | /* Convert QImage to/from cv::Mat 16 | * 17 | * - cv::Mat 18 | * - Supported channels 19 | * - 1 channel 20 | * - 3 channels (B G R), (R G B) 21 | * - 4 channels (B G R A), (R G B A), (A R G B) 22 | * - Supported depth 23 | * - CV_8U [0, 255] 24 | * - CV_16U [0, 65535] 25 | * - CV_32F [0, 1.0] 26 | * 27 | * - QImage 28 | * - All of the formats of QImage are supported. 29 | */ 30 | cv::Mat image2Mat(const QImage &img, int matType = CV_8UC(0), MatColorOrder order=MCO_BGR); 31 | QImage mat2Image(const cv::Mat &mat, MatColorOrder order=MCO_BGR, QImage::Format formatHint = QImage::Format_Invalid); 32 | } 33 | ``` 34 | 35 | * In addition, two other functions are provided which works more efficient when operating on `CV_8UC1`, `CV_8UC3(R G B)` 36 | `CV_8UC4(R G B A)`, `CV_8UC4(B G R A)` or `CV_8UC4(A R G B)`. 37 | 38 | ```cpp 39 | namespace QtOcv { 40 | /* Convert QImage to/from cv::Mat without data copy 41 | * 42 | * - Supported QImage formats and cv::Mat types are: 43 | * - QImage::Format_Indexed8 <==> CV_8UC1 44 | * - QImage::Format_Alpha8 <==> CV_8UC1 45 | * - QImage::Format_Grayscale8 <==> CV_8UC1 46 | * - QImage::Format_RGB888 <==> CV_8UC3 (R G B) 47 | * - QImage::Format_RGB32 <==> CV_8UC4 (A R G B or B G R A) 48 | * - QImage::Format_ARGB32 <==> CV_8UC4 (A R G B or B G R A) 49 | * - QImage::Format_ARGB32_Premultiplied <==> CV_8UC4 (A R G B or B G R A) 50 | * - QImage::Format_RGBX8888 <==> CV_8UC4 (R G B A) 51 | * - QImage::Format_RGBA8888 <==> CV_8UC4 (R G B A) 52 | * - QImage::Format_RGBA8888_Premultiplied <==> CV_8UC4 (R G B A) 53 | * 54 | * - For QImage::Format_RGB32 and QImage::Format_ARGB32, the 55 | * color channel order of cv::Mat will be (B G R A) in little 56 | * endian system or (A R G B) in big endian system. 57 | * 58 | * - User must make sure that the color channels order is the same as 59 | * the color channels order required by QImage. 60 | */ 61 | cv::Mat image2Mat_shared(const QImage &img, MatColorOrder *order=0); 62 | QImage mat2Image_shared(const cv::Mat &mat, QImage::Format formatHint = QImage::Format_Invalid); 63 | } //namespace QtOcv 64 | ``` 65 | 66 | ## OpenCV2 Integration 67 | 68 | If your want to use OpenCV in your qmake based project, you can download and put the source files to any directory you wanted, 69 | then add following code to your .pro file. 70 | 71 | include (yourpath/yourpath/yourpath/opencv.pri) 72 | 73 | or you can simply add following line to your .pro file: 74 | 75 | unix{ 76 | CONFIG += link_pkgconfig 77 | PKGCONFIG += opencv 78 | } 79 | win32{ 80 | # load(opencv) instead of CONFIG+=opencv used here 81 | !load(opencv):message("You must create an opencv.prf, and move it to $$[QT_INSTALL_PREFIX]/mkspecs/features/") 82 | } 83 | 84 | As you can see, nothing else needed to do for non-windows users. 85 | 86 | ### Notes for Windows User 87 | 88 | To make opencv.pri works for your, you need to create an `opencv.prf` file, then move the .prf file to `%QTDIR%/mkspecs/features/`. 89 | 90 | #### Method 1: Create and copy the opencv.prf by hand 91 | 92 | You can use a textedit to create the .prf file. The contents of .prf file more or less looks like this: 93 | 94 | INCLUDEPATH += D:/opencv/opencv_build/include 95 | LIBS += -LD:/opencv/opencv_build/x64/vc14/lib 96 | CONFIG(debug, debug|release) { 97 | LIBS += -lopencv_aruco310d 98 | LIBS += -lopencv_bgsegm310d 99 | LIBS += -lopencv_bioinspired310d 100 | LIBS += -lopencv_xxxxxx 101 | } else { 102 | LIBS += -lopencv_aruco310 103 | LIBS += -lopencv_bgsegm310 104 | LIBS += -lopencv_bioinspired310 105 | LIBS += -lopencv_xxxxxx 106 | } 107 | 108 | Then you can copy it to `%QTDIR%/mkspecs/features/`. 109 | 110 | #### Method 2: Take use of the helper script 111 | 112 | If you have installed python, the helper script `opencv_prf_generator.py` can be used to generate and install the opencv.prf file. 113 | 114 | python opencv_prf_generator.py -q D:\Qt\QtOnline\5.6\msvc2015_x64\bin\qmake.exe D:\opencv\opencv_build\x64\vc14\lib 115 | 116 | ## Some thing you need to know 117 | 118 | #### Channels order of OpenCV's image which used by highgui module is `B G R` and `B G R A` 119 | 120 | The manual of OpenCV says that, 121 | 122 | * cv::imwrite() 123 | 124 | Only 8-bit (or 16-bit unsigned(`CV_16U`) in case of PNG,JPEG 125 | 2000,and TIFF) single-channel or **3-channel(with 'BGR' channel order)** images can be saved using this function. 126 | 127 | It is possible to store PNG images with an alpha channel using this function. To do this, create 8-bit (or 16-bit) **4-chanel image BGRA**, where the alpha channel goes last. 128 | 129 | * cv::imread() 130 | 131 | In the case of color images, the decoded images will have the **channels stored in B G R order** . 132 | 133 | **Note:** If you don't care `opencv_highgui` module, you can always use the same channels order as QImage, which will be slightly fast. 134 | 135 | #### Data bytes order of QImage 136 | 137 | * In Little Endian System 138 | 139 | ``` 140 | QImage::Format_RGB32 ==> B G R 255 141 | QImage::Format_ARGB32 ==> B G R A 142 | 143 | QImage::Format_RGB888 ==> R G B 144 | QImage::Format_RGBX8888 ==> R G B 255 145 | QImage::Format_RGBA8888 ==> R G B A 146 | ``` 147 | 148 | * Ins Big Endian System 149 | 150 | ``` 151 | QImage::Format_RGB32 ==> 255 R G B 152 | QImage::Format_ARGB32 ==> A R G B 153 | 154 | QImage::Format_RGB888 ==> R G B 155 | QImage::Format_RGBX8888 ==> R G B 255 156 | QImage::Format_RGBA8888 ==> R G B A 157 | ``` 158 | 159 | #### How to swap channels? 160 | 161 | * In OpenCV 162 | 163 | ``` 164 | cv::cvtColor(mat, mat, CV_BGR2RGB) 165 | cv::cvtColor(mat, mat, CV_BGRA2RGBA) 166 | ... 167 | ``` 168 | 169 | * In Qt 170 | 171 | Swap r and b channel of QImage 172 | 173 | ``` 174 | QImage QImage::rgbSwapped(); 175 | ``` 176 | 177 | If the depth of the image is 32, the following function can be used too. 178 | 179 | ``` 180 | void QImage::invertPixels(InvertMode mode = InvertRgb) 181 | ``` 182 | 183 | #### Common Image Data Range of OpenCV 184 | 185 | ``` 186 | CV_8U [0, 255] 187 | CV_16U [0, 255*256] 188 | CV_32F [0.0, 1.0] 189 | ``` 190 | 191 | -------------------------------------------------------------------------------- /cvmatandqimage.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Copyright (c) 2012-2015 Debao Zhang 3 | ** All right reserved. 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining 6 | ** a copy of this software and associated documentation files (the 7 | ** "Software"), to deal in the Software without restriction, including 8 | ** without limitation the rights to use, copy, modify, merge, publish, 9 | ** distribute, sublicense, and/or sell copies of the Software, and to 10 | ** permit persons to whom the Software is furnished to do so, subject to 11 | ** the following conditions: 12 | ** 13 | ** The above copyright notice and this permission notice shall be 14 | ** included in all copies or substantial portions of the Software. 15 | ** 16 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #include "cvmatandqimage.h" 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "opencv2/core/core.hpp" 32 | #include "opencv2/imgproc/imgproc.hpp" 33 | 34 | namespace QtOcv { 35 | namespace { 36 | 37 | /*ARGB <==> BGRA 38 | */ 39 | cv::Mat argb2bgra(const cv::Mat &mat) 40 | { 41 | Q_ASSERT(mat.channels()==4); 42 | 43 | cv::Mat newMat(mat.rows, mat.cols, mat.type()); 44 | int from_to[] = {0,3, 1,2, 2,1, 3,0}; 45 | cv::mixChannels(&mat, 1, &newMat, 1, from_to, 4); 46 | return newMat; 47 | } 48 | 49 | cv::Mat adjustChannelsOrder(const cv::Mat &srcMat, MatColorOrder srcOrder, MatColorOrder targetOrder) 50 | { 51 | Q_ASSERT(srcMat.channels()==4); 52 | 53 | if (srcOrder == targetOrder) 54 | return srcMat.clone(); 55 | 56 | cv::Mat desMat; 57 | 58 | if ((srcOrder == MCO_ARGB && targetOrder == MCO_BGRA) 59 | ||(srcOrder == MCO_BGRA && targetOrder == MCO_ARGB)) { 60 | //ARGB <==> BGRA 61 | desMat = argb2bgra(srcMat); 62 | } else if (srcOrder == MCO_ARGB && targetOrder == MCO_RGBA) { 63 | //ARGB ==> RGBA 64 | desMat = cv::Mat(srcMat.rows, srcMat.cols, srcMat.type()); 65 | int from_to[] = {0,3, 1,0, 2,1, 3,2}; 66 | cv::mixChannels(&srcMat, 1, &desMat, 1, from_to, 4); 67 | } else if (srcOrder == MCO_RGBA && targetOrder == MCO_ARGB) { 68 | //RGBA ==> ARGB 69 | desMat = cv::Mat(srcMat.rows, srcMat.cols, srcMat.type()); 70 | int from_to[] = {0,1, 1,2, 2,3, 3,0}; 71 | cv::mixChannels(&srcMat, 1, &desMat, 1, from_to, 4); 72 | } else { 73 | //BGRA <==> RBGA 74 | cv::cvtColor(srcMat, desMat, CV_BGRA2RGBA); 75 | } 76 | return desMat; 77 | } 78 | 79 | QImage::Format findClosestFormat(QImage::Format formatHint) 80 | { 81 | QImage::Format format; 82 | switch (formatHint) { 83 | case QImage::Format_Indexed8: 84 | case QImage::Format_RGB32: 85 | case QImage::Format_ARGB32: 86 | case QImage::Format_ARGB32_Premultiplied: 87 | #if QT_VERSION >= 0x040400 88 | case QImage::Format_RGB888: 89 | #endif 90 | #if QT_VERSION >= 0x050200 91 | case QImage::Format_RGBX8888: 92 | case QImage::Format_RGBA8888: 93 | case QImage::Format_RGBA8888_Premultiplied: 94 | #endif 95 | #if QT_VERSION >= 0x050500 96 | case QImage::Format_Alpha8: 97 | case QImage::Format_Grayscale8: 98 | #endif 99 | format = formatHint; 100 | break; 101 | case QImage::Format_Mono: 102 | case QImage::Format_MonoLSB: 103 | format = QImage::Format_Indexed8; 104 | break; 105 | case QImage::Format_RGB16: 106 | format = QImage::Format_RGB32; 107 | break; 108 | #if QT_VERSION > 0x040400 109 | case QImage::Format_RGB444: 110 | case QImage::Format_RGB555: 111 | case QImage::Format_RGB666: 112 | format = QImage::Format_RGB888; 113 | break; 114 | case QImage::Format_ARGB4444_Premultiplied: 115 | case QImage::Format_ARGB6666_Premultiplied: 116 | case QImage::Format_ARGB8555_Premultiplied: 117 | case QImage::Format_ARGB8565_Premultiplied: 118 | format = QImage::Format_ARGB32_Premultiplied; 119 | break; 120 | #endif 121 | default: 122 | format = QImage::Format_ARGB32; 123 | break; 124 | } 125 | return format; 126 | } 127 | 128 | MatColorOrder getColorOrderOfRGB32Format() 129 | { 130 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 131 | return MCO_BGRA; 132 | #else 133 | return MCO_ARGB; 134 | #endif 135 | } 136 | } //namespace 137 | 138 | 139 | /* Convert QImage to cv::Mat 140 | */ 141 | cv::Mat image2Mat(const QImage &img, int requiredMatType, MatColorOrder requriedOrder) 142 | { 143 | int targetDepth = CV_MAT_DEPTH(requiredMatType); 144 | int targetChannels = CV_MAT_CN(requiredMatType); 145 | Q_ASSERT(targetChannels==CV_CN_MAX || targetChannels==1 || targetChannels==3 || targetChannels==4); 146 | Q_ASSERT(targetDepth==CV_8U || targetDepth==CV_16U || targetDepth==CV_32F); 147 | 148 | if (img.isNull()) 149 | return cv::Mat(); 150 | 151 | //Find the closest image format that can be used in image2Mat_shared() 152 | QImage::Format format = findClosestFormat(img.format()); 153 | QImage image = (format==img.format()) ? img : img.convertToFormat(format); 154 | 155 | MatColorOrder srcOrder; 156 | cv::Mat mat0 = image2Mat_shared(image, &srcOrder); 157 | 158 | //Adjust mat channells if needed. 159 | cv::Mat mat_adjustCn; 160 | const float maxAlpha = targetDepth==CV_8U ? 255 : (targetDepth==CV_16U ? 65535 : 1.0); 161 | if (targetChannels == CV_CN_MAX) 162 | targetChannels = mat0.channels(); 163 | switch(targetChannels) { 164 | case 1: 165 | if (mat0.channels() == 3) { 166 | cv::cvtColor(mat0, mat_adjustCn, CV_RGB2GRAY); 167 | } else if (mat0.channels() == 4) { 168 | if (srcOrder == MCO_BGRA) 169 | cv::cvtColor(mat0, mat_adjustCn, CV_BGRA2GRAY); 170 | else if (srcOrder == MCO_RGBA) 171 | cv::cvtColor(mat0, mat_adjustCn, CV_RGBA2GRAY); 172 | else//MCO_ARGB 173 | cv::cvtColor(argb2bgra(mat0), mat_adjustCn, CV_BGRA2GRAY); 174 | } 175 | break; 176 | case 3: 177 | if (mat0.channels() == 1) { 178 | cv::cvtColor(mat0, mat_adjustCn, requriedOrder == MCO_BGR ? CV_GRAY2BGR : CV_GRAY2RGB); 179 | } else if (mat0.channels() == 3) { 180 | if (requriedOrder != srcOrder) 181 | cv::cvtColor(mat0, mat_adjustCn, CV_RGB2BGR); 182 | } else if (mat0.channels() == 4) { 183 | if (srcOrder == MCO_ARGB) { 184 | mat_adjustCn = cv::Mat(mat0.rows, mat0.cols, CV_MAKE_TYPE(mat0.type(), 3)); 185 | int ARGB2RGB[] = {1,0, 2,1, 3,2}; 186 | int ARGB2BGR[] = {1,2, 2,1, 3,0}; 187 | cv::mixChannels(&mat0, 1, &mat_adjustCn, 1, requriedOrder == MCO_BGR ? ARGB2BGR : ARGB2RGB, 3); 188 | } else if (srcOrder == MCO_BGRA) { 189 | cv::cvtColor(mat0, mat_adjustCn, requriedOrder == MCO_BGR ? CV_BGRA2BGR : CV_BGRA2RGB); 190 | } else {//RGBA 191 | cv::cvtColor(mat0, mat_adjustCn, requriedOrder == MCO_BGR ? CV_RGBA2BGR : CV_RGBA2RGB); 192 | } 193 | } 194 | break; 195 | case 4: 196 | if (mat0.channels() == 1) { 197 | if (requriedOrder == MCO_ARGB) { 198 | cv::Mat alphaMat(mat0.rows, mat0.cols, CV_MAKE_TYPE(mat0.type(), 1), cv::Scalar(maxAlpha)); 199 | mat_adjustCn = cv::Mat(mat0.rows, mat0.cols, CV_MAKE_TYPE(mat0.type(), 4)); 200 | cv::Mat in[] = {alphaMat, mat0}; 201 | int from_to[] = {0,0, 1,1, 1,2, 1,3}; 202 | cv::mixChannels(in, 2, &mat_adjustCn, 1, from_to, 4); 203 | } else if (requriedOrder == MCO_RGBA) { 204 | cv::cvtColor(mat0, mat_adjustCn, CV_GRAY2RGBA); 205 | } else {//MCO_BGRA 206 | cv::cvtColor(mat0, mat_adjustCn, CV_GRAY2BGRA); 207 | } 208 | } else if (mat0.channels() == 3) { 209 | if (requriedOrder == MCO_ARGB) { 210 | cv::Mat alphaMat(mat0.rows, mat0.cols, CV_MAKE_TYPE(mat0.type(), 1), cv::Scalar(maxAlpha)); 211 | mat_adjustCn = cv::Mat(mat0.rows, mat0.cols, CV_MAKE_TYPE(mat0.type(), 4)); 212 | cv::Mat in[] = {alphaMat, mat0}; 213 | int from_to[] = {0,0, 1,1, 2,2, 3,3}; 214 | cv::mixChannels(in, 2, &mat_adjustCn, 1, from_to, 4); 215 | } else if (requriedOrder == MCO_RGBA) { 216 | cv::cvtColor(mat0, mat_adjustCn, CV_RGB2RGBA); 217 | } else {//MCO_BGRA 218 | cv::cvtColor(mat0, mat_adjustCn, CV_RGB2BGRA); 219 | } 220 | } else if (mat0.channels() == 4) { 221 | if (srcOrder != requriedOrder) 222 | mat_adjustCn = adjustChannelsOrder(mat0, srcOrder, requriedOrder); 223 | } 224 | break; 225 | default: 226 | break; 227 | } 228 | 229 | //Adjust depth if needed. 230 | if (targetDepth == CV_8U) 231 | return mat_adjustCn.empty() ? mat0.clone() : mat_adjustCn; 232 | 233 | if (mat_adjustCn.empty()) 234 | mat_adjustCn = mat0; 235 | cv::Mat mat_adjustDepth; 236 | mat_adjustCn.convertTo(mat_adjustDepth, CV_MAKE_TYPE(targetDepth, mat_adjustCn.channels()), targetDepth == CV_16U ? 255.0 : 1/255.0); 237 | return mat_adjustDepth; 238 | } 239 | 240 | /* Convert cv::Mat to QImage 241 | */ 242 | QImage mat2Image(const cv::Mat &mat, MatColorOrder order, QImage::Format formatHint) 243 | { 244 | Q_ASSERT(mat.channels()==1 || mat.channels()==3 || mat.channels()==4); 245 | Q_ASSERT(mat.depth()==CV_8U || mat.depth()==CV_16U || mat.depth()==CV_32F); 246 | 247 | if (mat.empty()) 248 | return QImage(); 249 | 250 | //Adjust mat channels if needed, and find proper QImage format. 251 | QImage::Format format; 252 | cv::Mat mat_adjustCn; 253 | if (mat.channels() == 1) { 254 | format = formatHint; 255 | if (formatHint != QImage::Format_Indexed8 256 | #if QT_VERSION >= 0x050500 257 | && formatHint != QImage::Format_Alpha8 258 | && formatHint != QImage::Format_Grayscale8 259 | #endif 260 | ) { 261 | format = QImage::Format_Indexed8; 262 | } 263 | } else if (mat.channels() == 3) { 264 | #if QT_VERSION >= 0x040400 265 | format = QImage::Format_RGB888; 266 | if (order == MCO_BGR) 267 | cv::cvtColor(mat, mat_adjustCn, CV_BGR2RGB); 268 | #else 269 | format = QImage::Format_RGB32; 270 | cv::Mat mat_tmp; 271 | cv::cvtColor(mat, mat_tmp, order == MCO_BGR ? CV_BGR2BGRA : CV_RGB2BGRA); 272 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 273 | mat_adjustCn = mat_tmp; 274 | #else 275 | mat_adjustCn = argb2bgra(mat_tmp); 276 | #endif 277 | 278 | #endif 279 | } else if (mat.channels() == 4) { 280 | //Find best format if the formatHint can not be applied. 281 | format = findClosestFormat(formatHint); 282 | if (format != QImage::Format_RGB32 283 | && format != QImage::Format_ARGB32 284 | && format != QImage::Format_ARGB32_Premultiplied 285 | #if QT_VERSION >= 0x050200 286 | && format != QImage::Format_RGBX8888 287 | && format != QImage::Format_RGBA8888 288 | && format != QImage::Format_RGBA8888_Premultiplied 289 | #endif 290 | ) { 291 | #if QT_VERSION >= 0x050200 292 | format = order == MCO_RGBA ? QImage::Format_RGBA8888 : QImage::Format_ARGB32; 293 | #else 294 | format = QImage::Format_ARGB32; 295 | #endif 296 | } 297 | 298 | //Channel order requried by the target QImage 299 | MatColorOrder requiredOrder = getColorOrderOfRGB32Format(); 300 | #if QT_VERSION >= 0x050200 301 | if (formatHint == QImage::Format_RGBX8888 302 | || formatHint == QImage::Format_RGBA8888 303 | || formatHint == QImage::Format_RGBA8888_Premultiplied) { 304 | requiredOrder = MCO_RGBA; 305 | } 306 | #endif 307 | 308 | if (order != requiredOrder) 309 | mat_adjustCn = adjustChannelsOrder(mat, order, requiredOrder); 310 | } 311 | 312 | if (mat_adjustCn.empty()) 313 | mat_adjustCn = mat; 314 | 315 | //Adjust mat depth if needed. 316 | cv::Mat mat_adjustDepth = mat_adjustCn; 317 | if (mat.depth() != CV_8U) 318 | mat_adjustCn.convertTo(mat_adjustDepth, CV_8UC(mat_adjustCn.channels()), mat.depth() == CV_16U ? 1/255.0 : 255.0); 319 | 320 | //Should we convert the image to the format specified by formatHint? 321 | QImage image = mat2Image_shared(mat_adjustDepth, format); 322 | if (format == formatHint || formatHint == QImage::Format_Invalid) 323 | return image.copy(); 324 | else 325 | return image.convertToFormat(formatHint); 326 | } 327 | 328 | /* Convert QImage to cv::Mat without data copy 329 | */ 330 | cv::Mat image2Mat_shared(const QImage &img, MatColorOrder *order) 331 | { 332 | if (img.isNull()) 333 | return cv::Mat(); 334 | 335 | switch (img.format()) { 336 | case QImage::Format_Indexed8: 337 | break; 338 | #if QT_VERSION >= 0x040400 339 | case QImage::Format_RGB888: 340 | if (order) 341 | *order = MCO_RGB; 342 | break; 343 | #endif 344 | case QImage::Format_RGB32: 345 | case QImage::Format_ARGB32: 346 | case QImage::Format_ARGB32_Premultiplied: 347 | if (order) 348 | *order = getColorOrderOfRGB32Format(); 349 | break; 350 | #if QT_VERSION >= 0x050200 351 | case QImage::Format_RGBX8888: 352 | case QImage::Format_RGBA8888: 353 | case QImage::Format_RGBA8888_Premultiplied: 354 | if (order) 355 | *order = MCO_RGBA; 356 | break; 357 | #endif 358 | #if QT_VERSION >= 0x050500 359 | case QImage::Format_Alpha8: 360 | case QImage::Format_Grayscale8: 361 | break; 362 | #endif 363 | default: 364 | return cv::Mat(); 365 | } 366 | return cv::Mat(img.height(), img.width(), CV_8UC(img.depth()/8), (uchar*)img.bits(), img.bytesPerLine()); 367 | } 368 | 369 | /* Convert cv::Mat to QImage without data copy 370 | */ 371 | QImage mat2Image_shared(const cv::Mat &mat, QImage::Format formatHint) 372 | { 373 | Q_ASSERT(mat.type() == CV_8UC1 || mat.type() == CV_8UC3 || mat.type() == CV_8UC4); 374 | 375 | if (mat.empty()) 376 | return QImage(); 377 | 378 | //Adjust formatHint if needed. 379 | if (mat.type() == CV_8UC1) { 380 | if (formatHint != QImage::Format_Indexed8 381 | #if QT_VERSION >= 0x050500 382 | && formatHint != QImage::Format_Alpha8 383 | && formatHint != QImage::Format_Grayscale8 384 | #endif 385 | ) { 386 | formatHint = QImage::Format_Indexed8; 387 | } 388 | #if QT_VERSION >= 0x040400 389 | } else if (mat.type() == CV_8UC3) { 390 | formatHint = QImage::Format_RGB888; 391 | #endif 392 | } else if (mat.type() == CV_8UC4) { 393 | if (formatHint != QImage::Format_RGB32 394 | && formatHint != QImage::Format_ARGB32 395 | && formatHint != QImage::Format_ARGB32_Premultiplied 396 | #if QT_VERSION >= 0x050200 397 | && formatHint != QImage::Format_RGBX8888 398 | && formatHint != QImage::Format_RGBA8888 399 | && formatHint != QImage::Format_RGBA8888_Premultiplied 400 | #endif 401 | ) { 402 | formatHint = QImage::Format_ARGB32; 403 | } 404 | } 405 | 406 | QImage img(mat.data, mat.cols, mat.rows, mat.step, formatHint); 407 | 408 | //Should we add directly support for user-customed-colorTable? 409 | if (formatHint == QImage::Format_Indexed8) { 410 | QVector colorTable; 411 | for (int i=0; i<256; ++i) 412 | colorTable.append(qRgb(i,i,i)); 413 | img.setColorTable(colorTable); 414 | } 415 | return img; 416 | } 417 | 418 | } //namespace QtOcv 419 | -------------------------------------------------------------------------------- /cvmatandqimage.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Copyright (c) 2012-2015 Debao Zhang 3 | ** All right reserved. 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining 6 | ** a copy of this software and associated documentation files (the 7 | ** "Software"), to deal in the Software without restriction, including 8 | ** without limitation the rights to use, copy, modify, merge, publish, 9 | ** distribute, sublicense, and/or sell copies of the Software, and to 10 | ** permit persons to whom the Software is furnished to do so, subject to 11 | ** the following conditions: 12 | ** 13 | ** The above copyright notice and this permission notice shall be 14 | ** included in all copies or substantial portions of the Software. 15 | ** 16 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #ifndef CVMATANDQIMAGE_H 27 | #define CVMATANDQIMAGE_H 28 | 29 | #include 30 | #include 31 | 32 | namespace QtOcv { 33 | 34 | enum MatColorOrder { 35 | MCO_BGR, 36 | MCO_RGB, 37 | MCO_BGRA = MCO_BGR, 38 | MCO_RGBA = MCO_RGB, 39 | MCO_ARGB 40 | }; 41 | 42 | 43 | /* Convert QImage to/from cv::Mat 44 | * 45 | * - cv::Mat 46 | * - Supported channels 47 | * - 1 channel 48 | * - 3 channels (B G R), (R G B) 49 | * - 4 channels (B G R A), (R G B A), (A R G B) 50 | * - Supported depth 51 | * - CV_8U [0, 255] 52 | * - CV_16U [0, 65535] 53 | * - CV_32F [0, 1.0] 54 | * 55 | * - QImage 56 | * - All of the formats of QImage are supported. 57 | */ 58 | cv::Mat image2Mat(const QImage &img, int requiredMatType = CV_8UC(0), MatColorOrder requiredOrder=MCO_BGR); 59 | QImage mat2Image(const cv::Mat &mat, MatColorOrder order=MCO_BGR, QImage::Format formatHint = QImage::Format_Invalid); 60 | 61 | /* Convert QImage to/from cv::Mat without data copy 62 | * 63 | * - Supported QImage formats and cv::Mat types are: 64 | * - QImage::Format_Indexed8 <==> CV_8UC1 65 | * - QImage::Format_Alpha8 <==> CV_8UC1 66 | * - QImage::Format_Grayscale8 <==> CV_8UC1 67 | * - QImage::Format_RGB888 <==> CV_8UC3 (R G B) 68 | * - QImage::Format_RGB32 <==> CV_8UC4 (A R G B or B G R A) 69 | * - QImage::Format_ARGB32 <==> CV_8UC4 (A R G B or B G R A) 70 | * - QImage::Format_ARGB32_Premultiplied <==> CV_8UC4 (A R G B or B G R A) 71 | * - QImage::Format_RGBX8888 <==> CV_8UC4 (R G B A) 72 | * - QImage::Format_RGBA8888 <==> CV_8UC4 (R G B A) 73 | * - QImage::Format_RGBA8888_Premultiplied <==> CV_8UC4 (R G B A) 74 | * 75 | * - For QImage::Format_RGB32 ,QImage::Format_ARGB32 76 | * and QImage::Format_ARGB32_Premultiplied, the 77 | * color channel order of cv::Mat will be (B G R A) in little 78 | * endian system or (A R G B) in big endian system. 79 | * 80 | * - User must make sure that the color channels order is the same as 81 | * the color channels order requried by QImage. 82 | */ 83 | cv::Mat image2Mat_shared(const QImage &img, MatColorOrder *order=0); 84 | QImage mat2Image_shared(const cv::Mat &mat, QImage::Format formatHint = QImage::Format_Invalid); 85 | 86 | } //namespace QtOcv 87 | 88 | #endif // CVMATANDQIMAGE_H 89 | -------------------------------------------------------------------------------- /examples/capture/cameradevice.cpp: -------------------------------------------------------------------------------- 1 | #include "cameradevice.h" 2 | #include 3 | #include 4 | #include "opencv2/core/core.hpp" 5 | #include "opencv2/highgui/highgui.hpp" 6 | #include "cvmatandqimage.h" 7 | 8 | CameraDevice::CameraDevice(QObject *parent) : 9 | QObject(parent) 10 | { 11 | m_capture = new cv::VideoCapture; 12 | m_timer = new QTimer(this); 13 | 14 | connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimeout())); 15 | } 16 | 17 | CameraDevice::~CameraDevice() 18 | { 19 | delete m_capture; 20 | m_capture = NULL; 21 | } 22 | 23 | bool CameraDevice::start() 24 | { 25 | if (m_capture->isOpened()) 26 | return true; 27 | 28 | m_capture->open(CV_CAP_ANY); 29 | if (m_capture->isOpened()) 30 | m_timer->start(40); 31 | 32 | return m_capture->isOpened(); 33 | } 34 | 35 | bool CameraDevice::stop() 36 | { 37 | if (m_capture->isOpened()) 38 | m_capture->release(); 39 | 40 | return true; 41 | } 42 | 43 | void CameraDevice::onTimeout() 44 | { 45 | if (!m_capture->isOpened()) 46 | return; 47 | 48 | static cv::Mat frame; 49 | *m_capture >> frame; 50 | if (frame.cols) 51 | emit imageReady(QtOcv::mat2Image(frame)); 52 | } 53 | -------------------------------------------------------------------------------- /examples/capture/cameradevice.h: -------------------------------------------------------------------------------- 1 | #ifndef CAMERADEVICE_H 2 | #define CAMERADEVICE_H 3 | 4 | #include 5 | 6 | QT_BEGIN_NAMESPACE 7 | class QTimer; 8 | class QImage; 9 | QT_END_NAMESPACE 10 | 11 | namespace cv{ 12 | class VideoCapture; 13 | class Mat; 14 | } 15 | 16 | class CameraDevice : public QObject 17 | { 18 | Q_OBJECT 19 | public: 20 | explicit CameraDevice(QObject *parent = 0); 21 | ~CameraDevice(); 22 | 23 | signals: 24 | void imageReady(const QImage& image); 25 | 26 | public slots: 27 | bool start(); 28 | bool stop(); 29 | 30 | private slots: 31 | void onTimeout(); 32 | 33 | private: 34 | cv::VideoCapture * m_capture; 35 | QTimer * m_timer; 36 | }; 37 | 38 | #endif // CAMERADEVICE_H 39 | -------------------------------------------------------------------------------- /examples/capture/capture.pro: -------------------------------------------------------------------------------- 1 | include(../../opencv.pri) 2 | include(../shared/shared.pri) 3 | 4 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 5 | 6 | TEMPLATE = app 7 | 8 | SOURCES += main.cpp\ 9 | dialog.cpp\ 10 | cameradevice.cpp 11 | 12 | HEADERS += dialog.h \ 13 | cameradevice.h 14 | 15 | FORMS += dialog.ui 16 | -------------------------------------------------------------------------------- /examples/capture/dialog.cpp: -------------------------------------------------------------------------------- 1 | #include "dialog.h" 2 | #include "ui_dialog.h" 3 | #include "cameradevice.h" 4 | 5 | Dialog::Dialog(QWidget *parent) : 6 | QDialog(parent), ui(new Ui::Dialog), m_camera(new CameraDevice(this)) 7 | { 8 | ui->setupUi(this); 9 | 10 | connect(m_camera, SIGNAL(imageReady(QImage)), this, SLOT(onImageArrival(QImage))); 11 | connect(ui->startButton, SIGNAL(clicked()), m_camera, SLOT(start())); 12 | connect(ui->stopButton, SIGNAL(clicked()), m_camera, SLOT(stop())); 13 | } 14 | 15 | Dialog::~Dialog() 16 | { 17 | delete ui; 18 | } 19 | 20 | void Dialog::onImageArrival(const QImage &image) 21 | { 22 | ui->imageWidget->setImage(image); 23 | } 24 | -------------------------------------------------------------------------------- /examples/capture/dialog.h: -------------------------------------------------------------------------------- 1 | #ifndef DIALOG_H 2 | #define DIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class Dialog; 8 | } 9 | 10 | class CameraDevice; 11 | 12 | class Dialog : public QDialog 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit Dialog(QWidget *parent = 0); 18 | ~Dialog(); 19 | 20 | private slots: 21 | void onImageArrival(const QImage & image); 22 | 23 | private: 24 | Ui::Dialog *ui; 25 | CameraDevice * m_camera; 26 | }; 27 | 28 | #endif // DIALOG_H 29 | -------------------------------------------------------------------------------- /examples/capture/dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 440 10 | 358 11 | 12 | 13 | 14 | QtOpenCV Camera Demo 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Qt::Horizontal 26 | 27 | 28 | 29 | 40 30 | 20 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Start 39 | 40 | 41 | 42 | 43 | 44 | 45 | Stop 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | QtOcv::ImageWidget 57 | QGraphicsView 58 |
cvimagewidget.h
59 |
60 |
61 | 62 | 63 |
64 | -------------------------------------------------------------------------------- /examples/capture/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "dialog.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | Dialog w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /examples/colorchannel/colorchannel.pro: -------------------------------------------------------------------------------- 1 | include(../../opencv.pri) 2 | include(../shared/shared.pri) 3 | 4 | QT += core gui 5 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 6 | 7 | TARGET = colorchannel 8 | TEMPLATE = app 9 | 10 | 11 | SOURCES += main.cpp\ 12 | mainwindow.cpp 13 | 14 | HEADERS += mainwindow.h 15 | 16 | FORMS += mainwindow.ui 17 | -------------------------------------------------------------------------------- /examples/colorchannel/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /examples/colorchannel/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | #include "cvmatandqimage.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | MainWindow::MainWindow(QWidget *parent) : 14 | QMainWindow(parent), 15 | ui(new Ui::MainWindow) 16 | { 17 | ui->setupUi(this); 18 | 19 | connect(ui->originImageWidget, SIGNAL(colorUnderMouseChanged(QColor)), SLOT(onColorUnderMouseChanged(QColor))); 20 | connect(ui->rImageWidget, SIGNAL(colorUnderMouseChanged(QColor)), SLOT(onColorUnderMouseChanged(QColor))); 21 | connect(ui->gImageWidget, SIGNAL(colorUnderMouseChanged(QColor)), SLOT(onColorUnderMouseChanged(QColor))); 22 | connect(ui->bImageWidget, SIGNAL(colorUnderMouseChanged(QColor)), SLOT(onColorUnderMouseChanged(QColor))); 23 | } 24 | 25 | MainWindow::~MainWindow() 26 | { 27 | delete ui; 28 | } 29 | 30 | void MainWindow::onColorUnderMouseChanged(const QColor &c) 31 | { 32 | if (c.isValid()) 33 | statusBar()->showMessage(QString("R %1 G %2 B %3").arg(c.red()).arg(c.green()).arg(c.blue())); 34 | else 35 | statusBar()->clearMessage(); 36 | } 37 | 38 | void MainWindow::on_action_Open_triggered() 39 | { 40 | QSettings settings("QtOpenCV_example.ini", QSettings::IniFormat); 41 | QString lastPath = settings.value("lastPath").toString(); 42 | 43 | QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), lastPath, "Images(*.png *.bmp *.jpg *.gif)"); 44 | if (fileName.isEmpty()) 45 | return; 46 | 47 | QImage img(fileName); 48 | if (img.isNull()) 49 | return; 50 | settings.setValue("lastPath", fileName); 51 | setWindowTitle(fileName); 52 | ui->originImageWidget->setImage(img); 53 | ui->originImageWidget->setCurrentScale(0); 54 | 55 | QImage image = img.convertToFormat(QImage::Format_RGB888); 56 | cv::Mat mat = QtOcv::image2Mat_shared(image); 57 | #if 0 58 | std::vector channels; 59 | cv::split(mat, channels); 60 | 61 | ui->rImageWidget->setImage(QtOcv::mat2Image_shared(channels[0])); 62 | ui->gImageWidget->setImage(QtOcv::mat2Image_shared(channels[1])); 63 | ui->bImageWidget->setImage(QtOcv::mat2Image_shared(channels[2])); 64 | #else 65 | cv::Mat rMat(mat.rows, mat.cols, mat.type(), cv::Scalar(0, 0, 0)); 66 | cv::Mat gMat = rMat.clone(); 67 | cv::Mat bMat = rMat.clone(); 68 | int r[] = {0, 0}; 69 | int g[] = {1, 1}; 70 | int b[] = {2, 2}; 71 | cv::mixChannels(&mat, 1, &rMat, 1, r, 1); 72 | cv::mixChannels(&mat, 1, &gMat, 1, g, 1); 73 | cv::mixChannels(&mat, 1, &bMat, 1, b, 1); 74 | 75 | ui->rImageWidget->setImage(QtOcv::mat2Image_shared(rMat)); 76 | ui->gImageWidget->setImage(QtOcv::mat2Image_shared(gMat)); 77 | ui->bImageWidget->setImage(QtOcv::mat2Image_shared(bMat)); 78 | #endif 79 | 80 | ui->rImageWidget->setCurrentScale(0); 81 | ui->gImageWidget->setCurrentScale(0); 82 | ui->bImageWidget->setCurrentScale(0); 83 | } 84 | -------------------------------------------------------------------------------- /examples/colorchannel/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class MainWindow; 8 | } 9 | 10 | class MainWindow : public QMainWindow 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit MainWindow(QWidget *parent = 0); 16 | ~MainWindow(); 17 | 18 | private slots: 19 | void on_action_Open_triggered(); 20 | void onColorUnderMouseChanged(const QColor &c); 21 | 22 | private: 23 | Ui::MainWindow *ui; 24 | }; 25 | 26 | #endif // MAINWINDOW_H 27 | -------------------------------------------------------------------------------- /examples/colorchannel/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 566 10 | 466 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 0 20 | 21 | 22 | 0 23 | 24 | 25 | 0 26 | 27 | 28 | 0 29 | 30 | 31 | 0 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 0 51 | 0 52 | 566 53 | 23 54 | 55 | 56 | 57 | 58 | &File 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | TopToolBarArea 67 | 68 | 69 | false 70 | 71 | 72 | 73 | 74 | 75 | &Open... 76 | 77 | 78 | 79 | 80 | 81 | 82 | QtOcv::ImageWidget 83 | QGraphicsView 84 |
cvimagewidget.h
85 |
86 |
87 | 88 | 89 |
90 | -------------------------------------------------------------------------------- /examples/examples.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | imagefft \ 5 | capture \ 6 | colorchannel \ 7 | simple \ 8 | imageprocess 9 | -------------------------------------------------------------------------------- /examples/imagefft/dialog.cpp: -------------------------------------------------------------------------------- 1 | #include "dialog.h" 2 | #include "ui_dialog.h" 3 | #include "cvmatandqimage.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace { 13 | 14 | void calcFFT(const cv::Mat &input, cv::Mat &output) 15 | { 16 | cv::Mat padded; //expand input image to optimal size 17 | int m = cv::getOptimalDFTSize( input.rows ); 18 | int n = cv::getOptimalDFTSize( input.cols ); // on the border add zero values 19 | cv::copyMakeBorder(input, padded, 0, m - input.rows, 0, n - input.cols, cv::BORDER_CONSTANT, cv::Scalar_::all(0)); 20 | 21 | cv::Mat planes[] = {cv::Mat_(padded), cv::Mat::zeros(padded.size(), CV_32F)}; 22 | cv::Mat complexI; 23 | cv::merge(planes, 2, complexI); // Add to the expanded another plane with zeros 24 | 25 | cv::dft(complexI, complexI); // this way the result may fit in the source matrix 26 | 27 | // compute the magnitude and switch to logarithmic scale 28 | // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)) 29 | cv::split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) 30 | cv::magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude 31 | output = planes[0]; 32 | 33 | output += cv::Scalar_::all(1); // switch to logarithmic scale 34 | cv::log(output, output); 35 | 36 | // crop the spectrum, if it has an odd number of rows or columns 37 | output = output(cv::Rect(0, 0, output.cols & -2, output.rows & -2)); 38 | 39 | // rearrange the quadrants of Fourier image so that the origin is at the image center 40 | int cx = output.cols/2; 41 | int cy = output.rows/2; 42 | 43 | cv::Mat q0(output, cv::Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant 44 | cv::Mat q1(output, cv::Rect(cx, 0, cx, cy)); // Top-Right 45 | cv::Mat q2(output, cv::Rect(0, cy, cx, cy)); // Bottom-Left 46 | cv::Mat q3(output, cv::Rect(cx, cy, cx, cy)); // Bottom-Right 47 | 48 | cv::Mat tmp; // swap quadrants (Top-Left with Bottom-Right) 49 | q0.copyTo(tmp); 50 | q3.copyTo(q0); 51 | tmp.copyTo(q3); 52 | 53 | q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left) 54 | q2.copyTo(q1); 55 | tmp.copyTo(q2); 56 | 57 | cv::normalize(output, output, 0, 1, CV_MINMAX); // Transform the matrix with float values into a 58 | // viewable image form (float between values 0 and 1). 59 | return; 60 | } 61 | } //namespace 62 | 63 | Dialog::Dialog(QWidget *parent) : 64 | QDialog(parent), 65 | ui(new Ui::Dialog) 66 | { 67 | ui->setupUi(this); 68 | 69 | connect(ui->openButton, SIGNAL(clicked()), SLOT(onOpenButtonClicked())); 70 | } 71 | 72 | Dialog::~Dialog() 73 | { 74 | delete ui; 75 | } 76 | 77 | void Dialog::onOpenButtonClicked() 78 | { 79 | QString filename = QFileDialog::getOpenFileName(this, tr("Open Image"), QString(), "Images(*.png *.bmp *.jpg *.gif)"); 80 | if (filename.isEmpty()) 81 | return; 82 | 83 | QImage img(filename); 84 | if (img.isNull()) 85 | return; 86 | 87 | ui->imageWidget->setImage(img); 88 | 89 | cv::Mat mat = QtOcv::image2Mat(img, CV_8UC1); 90 | cv::Mat out_mat; 91 | calcFFT(mat, out_mat); 92 | 93 | ui->fftImageWidget->setImage(QtOcv::mat2Image(out_mat)); 94 | } 95 | -------------------------------------------------------------------------------- /examples/imagefft/dialog.h: -------------------------------------------------------------------------------- 1 | #ifndef DIALOG_H 2 | #define DIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class Dialog; 8 | } 9 | 10 | namespace cv { 11 | class Mat; 12 | } 13 | 14 | class Dialog : public QDialog 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit Dialog(QWidget *parent = 0); 20 | ~Dialog(); 21 | 22 | private slots: 23 | void onOpenButtonClicked(); 24 | 25 | private: 26 | Ui::Dialog *ui; 27 | }; 28 | 29 | #endif // DIALOG_H 30 | -------------------------------------------------------------------------------- /examples/imagefft/dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 625 10 | 467 11 | 12 | 13 | 14 | QtOpenCV FFT Demo 15 | 16 | 17 | 18 | 19 | 20 | 1 21 | 22 | 23 | 24 | Original Image 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | FFT Result 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | Qt::Horizontal 50 | 51 | 52 | 53 | 40 54 | 20 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Open Image... 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | QtOcv::ImageWidget 74 | QGraphicsView 75 |
cvimagewidget.h
76 |
77 |
78 | 79 | 80 |
81 | -------------------------------------------------------------------------------- /examples/imagefft/imagefft.pro: -------------------------------------------------------------------------------- 1 | include(../../opencv.pri) 2 | include(../shared/shared.pri) 3 | 4 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 5 | 6 | TARGET = imagefft 7 | TEMPLATE = app 8 | 9 | 10 | SOURCES += main.cpp\ 11 | dialog.cpp 12 | 13 | HEADERS += dialog.h 14 | 15 | FORMS += dialog.ui 16 | -------------------------------------------------------------------------------- /examples/imagefft/main.cpp: -------------------------------------------------------------------------------- 1 | #include "dialog.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | Dialog w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /examples/imageprocess/convert.cpp: -------------------------------------------------------------------------------- 1 | #include "convert.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static QSpinBox *createSpinBox(int v, int min=0, int max=99) 11 | { 12 | QSpinBox *edit = new QSpinBox; 13 | edit->setRange(min, max); 14 | edit->setValue(v); 15 | return edit; 16 | } 17 | 18 | AbstractConvert::AbstractConvert() 19 | { 20 | 21 | } 22 | 23 | AbstractConvert::~AbstractConvert() 24 | { 25 | if (!m_widget.isNull()) 26 | delete m_widget.data(); 27 | } 28 | 29 | QWidget *AbstractConvert::paramsWidget() 30 | { 31 | if (m_widget.isNull()) { 32 | m_widget = new QWidget(); 33 | initParamsWidget(); 34 | } 35 | return m_widget.data(); 36 | } 37 | 38 | QString AbstractConvert::errorString() const 39 | { 40 | return m_errorString; 41 | } 42 | 43 | 44 | bool Gray::applyTo(const cv::Mat &input, cv::Mat &output) 45 | { 46 | if (input.channels() == 1) { 47 | m_errorString = "not a rgb color image."; 48 | return false; 49 | } 50 | cv::cvtColor(input, output, CV_RGB2GRAY); 51 | return true; 52 | } 53 | 54 | Blur::Blur() 55 | { 56 | 57 | } 58 | 59 | Blur::~Blur() 60 | { 61 | 62 | } 63 | 64 | bool Blur::applyTo(const cv::Mat &input, cv::Mat &output) 65 | { 66 | cv::blur(input, output, cv::Size(kSizeXEdit->value(), kSizeYEdit->value()), 67 | cv::Point(anchorXEdit->value(), anchorYEdit->value()), 68 | borderTypeEdit->itemData(borderTypeEdit->currentIndex()).toInt()); 69 | return true; 70 | } 71 | 72 | void Blur::initParamsWidget() 73 | { 74 | kSizeXEdit = createSpinBox(3); 75 | kSizeYEdit = createSpinBox(3); 76 | anchorXEdit = createSpinBox(-1, -10, 255); 77 | anchorYEdit = createSpinBox(-1, -10, 255); 78 | 79 | borderTypeEdit = new QComboBox; 80 | borderTypeEdit->addItem("BORDER_DEFAULT", cv::BORDER_DEFAULT); 81 | borderTypeEdit->addItem("BORDER_REPLICATE", cv::BORDER_REPLICATE); 82 | borderTypeEdit->addItem("BORDER_REFLECT", cv::BORDER_REFLECT); 83 | borderTypeEdit->addItem("BORDER_REFLECT_101", cv::BORDER_REFLECT_101); 84 | borderTypeEdit->addItem("BORDER_WRAP", cv::BORDER_WRAP); 85 | borderTypeEdit->addItem("BORDER_CONSTANT", cv::BORDER_CONSTANT); 86 | 87 | QFormLayout *layout = new QFormLayout(m_widget.data()); 88 | layout->addRow("kSize X", kSizeXEdit); 89 | layout->addRow("kSize Y", kSizeYEdit); 90 | layout->addRow("anchor X", anchorXEdit); 91 | layout->addRow("anchor Y", anchorYEdit); 92 | layout->addRow("border", borderTypeEdit); 93 | } 94 | 95 | 96 | BilateralFilter::BilateralFilter() 97 | { 98 | 99 | } 100 | 101 | BilateralFilter::~BilateralFilter() 102 | { 103 | 104 | } 105 | 106 | bool BilateralFilter::applyTo(const cv::Mat &input, cv::Mat &output) 107 | { 108 | cv::bilateralFilter(input, output, dEdit->value(), sigmaColorEdit->value(), 109 | sigmaSpaceEdit->value(), borderTypeEdit->itemData(borderTypeEdit->currentIndex()).toInt()); 110 | return true; 111 | } 112 | 113 | void BilateralFilter::initParamsWidget() 114 | { 115 | dEdit = createSpinBox(5); 116 | sigmaColorEdit = createSpinBox(150, -100, 255); 117 | sigmaSpaceEdit = createSpinBox(150, -100, 255); 118 | 119 | borderTypeEdit = new QComboBox; 120 | borderTypeEdit->addItem("BORDER_DEFAULT", cv::BORDER_DEFAULT); 121 | borderTypeEdit->addItem("BORDER_REPLICATE", cv::BORDER_REPLICATE); 122 | borderTypeEdit->addItem("BORDER_REFLECT", cv::BORDER_REFLECT); 123 | borderTypeEdit->addItem("BORDER_REFLECT_101", cv::BORDER_REFLECT_101); 124 | borderTypeEdit->addItem("BORDER_WRAP", cv::BORDER_WRAP); 125 | borderTypeEdit->addItem("BORDER_CONSTANT", cv::BORDER_CONSTANT); 126 | 127 | QFormLayout *layout = new QFormLayout(m_widget.data()); 128 | layout->addRow("d", dEdit); 129 | layout->addRow("sigmaColor", sigmaColorEdit); 130 | layout->addRow("sigmaSpace", sigmaSpaceEdit); 131 | layout->addRow("border", borderTypeEdit); 132 | } 133 | 134 | BoxFilter::BoxFilter() 135 | { 136 | 137 | } 138 | 139 | BoxFilter::~BoxFilter() 140 | { 141 | 142 | } 143 | 144 | bool BoxFilter::applyTo(const cv::Mat &input, cv::Mat &output) 145 | { 146 | cv::boxFilter(input, output, -1, cv::Size(kSizeXEdit->value(), kSizeYEdit->value()), 147 | cv::Point(anchorXEdit->value(), anchorYEdit->value()), normalizeEdit->itemData(borderTypeEdit->currentIndex()).toBool(), 148 | borderTypeEdit->itemData(borderTypeEdit->currentIndex()).toInt()); 149 | return true; 150 | } 151 | 152 | void BoxFilter::initParamsWidget() 153 | { 154 | Blur::initParamsWidget(); 155 | 156 | normalizeEdit = new QComboBox; 157 | normalizeEdit->addItem("TRUE", true); 158 | normalizeEdit->addItem("FALSE", false); 159 | 160 | static_cast(m_widget->layout())->addRow("normalized", normalizeEdit); 161 | } 162 | 163 | 164 | 165 | MedianBlur::MedianBlur() 166 | { 167 | 168 | } 169 | 170 | MedianBlur::~MedianBlur() 171 | { 172 | 173 | } 174 | 175 | bool MedianBlur::applyTo(const cv::Mat &input, cv::Mat &output) 176 | { 177 | cv::medianBlur(input, output, kSizeEdit->value()); 178 | return true; 179 | } 180 | 181 | void MedianBlur::initParamsWidget() 182 | { 183 | kSizeEdit = createSpinBox(3); 184 | 185 | QFormLayout *layout = new QFormLayout(m_widget.data()); 186 | layout->addRow("kSize", kSizeEdit); 187 | } 188 | 189 | 190 | bool GaussianBlur::applyTo(const cv::Mat &input, cv::Mat &output) 191 | { 192 | cv::GaussianBlur(input, output, cv::Size(kSizeXEdit->value(), kSizeYEdit->value()), 193 | sigmaXEdit->value(), sigmaYEdit->value(), 194 | borderTypeEdit->itemData(borderTypeEdit->currentIndex()).toInt()); 195 | return true; 196 | } 197 | 198 | void GaussianBlur::initParamsWidget() 199 | { 200 | kSizeXEdit = createSpinBox(3); 201 | kSizeYEdit = createSpinBox(3); 202 | sigmaXEdit = createSpinBox(-1, -10, 255); 203 | sigmaYEdit = createSpinBox(-1, -10, 255); 204 | 205 | borderTypeEdit = new QComboBox; 206 | borderTypeEdit->addItem("BORDER_DEFAULT", cv::BORDER_DEFAULT); 207 | borderTypeEdit->addItem("BORDER_REPLICATE", cv::BORDER_REPLICATE); 208 | borderTypeEdit->addItem("BORDER_REFLECT", cv::BORDER_REFLECT); 209 | borderTypeEdit->addItem("BORDER_REFLECT_101", cv::BORDER_REFLECT_101); 210 | borderTypeEdit->addItem("BORDER_WRAP", cv::BORDER_WRAP); 211 | borderTypeEdit->addItem("BORDER_CONSTANT", cv::BORDER_CONSTANT); 212 | 213 | QFormLayout *layout = new QFormLayout(m_widget.data()); 214 | layout->addRow("kSize X", kSizeXEdit); 215 | layout->addRow("kSize Y", kSizeYEdit); 216 | layout->addRow("anchor X", sigmaXEdit); 217 | layout->addRow("anchor Y", sigmaYEdit); 218 | layout->addRow("border", borderTypeEdit); 219 | } 220 | 221 | 222 | bool Threshold::applyTo(const cv::Mat &input, cv::Mat &output) 223 | { 224 | int type = typeEdit->itemData(typeEdit->currentIndex()).toInt(); 225 | if (otsuButton->isChecked()) { 226 | type |= cv::THRESH_OTSU; 227 | if (input.channels() != 1) { 228 | m_errorString = "THRESH_OTSU only works with gray image."; 229 | return false; 230 | } 231 | } 232 | cv::threshold(input, output, threshEdit->value(), maxvalEdit->value(), type); 233 | return true; 234 | } 235 | 236 | void Threshold::initParamsWidget() 237 | { 238 | threshEdit = createSpinBox(100, 0, 255); 239 | maxvalEdit = createSpinBox(255, 0, 255); 240 | 241 | typeEdit = new QComboBox; 242 | typeEdit->addItem("THRESH_BINARY", cv::THRESH_BINARY); 243 | typeEdit->addItem("THRESH_BINARY_INV", cv::THRESH_BINARY_INV); 244 | typeEdit->addItem("THRESH_TRUNC", cv::THRESH_TRUNC); 245 | typeEdit->addItem("THRESH_TOZERO", cv::THRESH_TOZERO); 246 | typeEdit->addItem("THRESH_TOZERO_INV", cv::THRESH_TOZERO_INV); 247 | 248 | otsuButton = new QCheckBox("THRESH_OTSU"); 249 | 250 | QFormLayout *layout = new QFormLayout(m_widget.data()); 251 | layout->addRow("thresh", threshEdit); 252 | layout->addRow("maxval", maxvalEdit); 253 | layout->addRow("type", typeEdit); 254 | layout->addRow(otsuButton); 255 | } 256 | 257 | 258 | bool Canny::applyTo(const cv::Mat &input, cv::Mat &output) 259 | { 260 | cv::Canny(input, output, threshold1Edit->value(), threshold2Edit->value(), 261 | apertureSizeEdit->value(), l2gradientButton->isChecked()); 262 | return true; 263 | } 264 | 265 | void Canny::initParamsWidget() 266 | { 267 | threshold1Edit = createSpinBox(20, 0, 255); 268 | threshold2Edit = createSpinBox(60, 0, 255); 269 | 270 | apertureSizeEdit = new QSpinBox; 271 | apertureSizeEdit->setValue(3); 272 | 273 | l2gradientButton = new QCheckBox("L2Gradient"); 274 | 275 | QFormLayout *layout = new QFormLayout(m_widget.data()); 276 | layout->addRow("threshold1", threshold1Edit); 277 | layout->addRow("threshold2", threshold2Edit); 278 | layout->addRow("apertureSize", apertureSizeEdit); 279 | layout->addRow(l2gradientButton); 280 | } 281 | 282 | 283 | bool Dilate::applyTo(const cv::Mat &input, cv::Mat &output) 284 | { 285 | cv::Mat kernel = cv::getStructuringElement(kShapeEdit->itemData(kShapeEdit->currentIndex()).toInt(), 286 | cv::Size(kSizeXEdit->value(), kSizeYEdit->value()), 287 | cv::Point(anchorXEdit->value(), anchorYEdit->value())); 288 | cv::dilate(input, output, kernel, cv::Point(anchorXEdit->value(), anchorYEdit->value()), 289 | iterationsEdit->value(), borderTypeEdit->itemData(borderTypeEdit->currentIndex()).toInt()); 290 | return true; 291 | } 292 | 293 | void Dilate::initParamsWidget() 294 | { 295 | kSizeXEdit = createSpinBox(3); 296 | kSizeYEdit = createSpinBox(3); 297 | kShapeEdit = new QComboBox; 298 | kShapeEdit->addItem("MORPH_RECT", cv::MORPH_RECT); 299 | kShapeEdit->addItem("MORPH_ELLIPSE", cv::MORPH_ELLIPSE); 300 | kShapeEdit->addItem("MORPH_CROSS", cv::MORPH_CROSS); 301 | 302 | anchorXEdit = createSpinBox(-1, -10, 255); 303 | anchorYEdit = createSpinBox(-1, -10, 255); 304 | iterationsEdit = createSpinBox(1); 305 | borderTypeEdit = new QComboBox; 306 | borderTypeEdit->addItem("BORDER_DEFAULT", cv::BORDER_DEFAULT); 307 | borderTypeEdit->addItem("BORDER_REPLICATE", cv::BORDER_REPLICATE); 308 | borderTypeEdit->addItem("BORDER_REFLECT", cv::BORDER_REFLECT); 309 | borderTypeEdit->addItem("BORDER_REFLECT_101", cv::BORDER_REFLECT_101); 310 | borderTypeEdit->addItem("BORDER_WRAP", cv::BORDER_WRAP); 311 | borderTypeEdit->addItem("BORDER_CONSTANT", cv::BORDER_CONSTANT); 312 | borderTypeEdit->setCurrentIndex(5); 313 | 314 | QFormLayout *layout = new QFormLayout(m_widget.data()); 315 | layout->addRow("kSize X", kSizeXEdit); 316 | layout->addRow("kSize Y", kSizeYEdit); 317 | layout->addRow("kShape", kShapeEdit); 318 | layout->addRow("anchor X", anchorXEdit); 319 | layout->addRow("anchor Y", anchorYEdit); 320 | layout->addRow("iterations", iterationsEdit); 321 | layout->addRow("border", borderTypeEdit); 322 | } 323 | 324 | 325 | bool Erode::applyTo(const cv::Mat &input, cv::Mat &output) 326 | { 327 | cv::Mat kernel = cv::getStructuringElement(kShapeEdit->itemData(kShapeEdit->currentIndex()).toInt(), 328 | cv::Size(kSizeXEdit->value(), kSizeYEdit->value()), 329 | cv::Point(anchorXEdit->value(), anchorYEdit->value())); 330 | cv::erode(input, output, kernel, cv::Point(anchorXEdit->value(), anchorYEdit->value()), 331 | iterationsEdit->value(), borderTypeEdit->itemData(borderTypeEdit->currentIndex()).toInt()); 332 | return true; 333 | } 334 | 335 | 336 | bool HoughCircles::applyTo(const cv::Mat &input, cv::Mat &output) 337 | { 338 | std::vector circles; 339 | cv::HoughCircles(input, circles, CV_HOUGH_GRADIENT, dpEdit->value(), minDistEdit->value(), param1Edit->value(), param2Edit->value(), 340 | minRadiusEdit->value(), maxRadiusEdit->value()); 341 | 342 | if (input.channels() == 1) 343 | cv::cvtColor(input, output, CV_GRAY2RGB); 344 | else 345 | output = input.clone(); 346 | 347 | for( size_t i = 0; i < circles.size(); i++ ) { 348 | cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); 349 | int radius = cvRound(circles[i][2]); 350 | // draw the circle center 351 | cv::circle(output, center, 3, cv::Scalar(0,255,0), -1, 8, 0 ); 352 | // draw the circle outline 353 | cv::circle(output, center, radius, cv::Scalar(0,0,255), 3, 8, 0 ); 354 | 355 | QString info = QString("Center(%1, %2) Radius %3") 356 | .arg(center.x).arg(center.y) 357 | .arg(radius); 358 | infoEdit->appendPlainText(info); 359 | } 360 | return true; 361 | } 362 | 363 | void HoughCircles::initParamsWidget() 364 | { 365 | methodEdit = new QComboBox; 366 | methodEdit->addItem("CV_HOUGH_GRADIENT"); 367 | 368 | dpEdit = createSpinBox(1); 369 | minDistEdit = createSpinBox(2, 0, 10000); 370 | param1Edit = createSpinBox(100, 0 ,255); 371 | param2Edit = createSpinBox(100, 0, 255); 372 | minRadiusEdit = createSpinBox(0, 0, 10000); 373 | maxRadiusEdit = createSpinBox(0, 0, 10000); 374 | infoEdit = new QPlainTextEdit; 375 | 376 | QFormLayout *layout = new QFormLayout(m_widget.data()); 377 | layout->addRow("method", methodEdit); 378 | layout->addRow("dp", dpEdit); 379 | layout->addRow("minDist", minDistEdit); 380 | layout->addRow("param1", param1Edit); 381 | layout->addRow("param2", param2Edit); 382 | layout->addRow("minRadius", minRadiusEdit); 383 | layout->addRow("maxRadius", maxRadiusEdit); 384 | layout->addRow(infoEdit); 385 | } 386 | 387 | 388 | bool FitEllipse::applyTo(const cv::Mat &input, cv::Mat &output) 389 | { 390 | 391 | //Find countours 392 | std::vector > contours; 393 | int find_contours_mode = CV_CHAIN_APPROX_TC89_L1; //CV_RETR_LIST 394 | cv::findContours(input, contours, find_contours_mode, CV_CHAIN_APPROX_NONE); 395 | std::sort(contours.begin(), contours.end(), [](std::vector a, std::vector b) { 396 | return b.size() < a.size(); 397 | }); 398 | 399 | if (input.channels() == 1) 400 | cv::cvtColor(input, output, CV_GRAY2RGB); 401 | else 402 | output = input.clone(); 403 | 404 | size_t maxEllipseCount = 8; 405 | for(size_t i = 0, foundCount = 0; (i < contours.size()) && (foundCount < maxEllipseCount); i++) { 406 | size_t count = contours[i].size(); 407 | 408 | if( count < 6 ) 409 | continue; 410 | 411 | cv::Mat pointsf; 412 | cv::Mat(contours[i]).convertTo(pointsf, CV_32F); 413 | cv::RotatedRect box = cv::fitEllipse(pointsf); 414 | 415 | if( qMax(box.size.width, box.size.height) > qMin(box.size.width, box.size.height)*30 ) 416 | continue; 417 | 418 | int pixVal = 255 - 20*foundCount; 419 | cv::ellipse(output, box, cv::Scalar(pixVal,0,0), 1, CV_AA); 420 | cv::ellipse(output, box.center, box.size*0.5f, box.angle, 0, 360, cv::Scalar(pixVal,pixVal,0), 1, CV_AA); 421 | QString ellipseInfo = QString("Center(%1, %2) Size(%3, %4) Angle %5") 422 | .arg(box.center.x).arg(box.center.y) 423 | .arg(box.size.width).arg(box.size.height) 424 | .arg(box.angle); 425 | infoEdit->appendPlainText(ellipseInfo); 426 | 427 | foundCount++; 428 | } 429 | return true; 430 | } 431 | 432 | void FitEllipse::initParamsWidget() 433 | { 434 | infoEdit = new QPlainTextEdit; 435 | 436 | QFormLayout *layout = new QFormLayout(m_widget.data()); 437 | layout->addRow(infoEdit); 438 | } 439 | 440 | -------------------------------------------------------------------------------- /examples/imageprocess/convert.h: -------------------------------------------------------------------------------- 1 | #ifndef ABSTRACTCONVERT_H 2 | #define ABSTRACTCONVERT_H 3 | 4 | #include 5 | #include 6 | 7 | namespace cv { 8 | class Mat; 9 | } 10 | class QWidget; 11 | class QSpinBox; 12 | class QComboBox; 13 | class QCheckBox; 14 | class QPlainTextEdit; 15 | 16 | class AbstractConvert 17 | { 18 | public: 19 | AbstractConvert(); 20 | virtual ~AbstractConvert(); 21 | 22 | virtual bool applyTo(const cv::Mat &input, cv::Mat &output) = 0; 23 | QWidget *paramsWidget(); 24 | QString errorString() const; 25 | 26 | protected: 27 | virtual void initParamsWidget() = 0; 28 | 29 | QPointer m_widget; 30 | QString m_errorString; 31 | }; 32 | 33 | class Gray : public AbstractConvert 34 | { 35 | public: 36 | Gray(){} 37 | ~Gray(){} 38 | 39 | bool applyTo(const cv::Mat &input, cv::Mat &output); 40 | 41 | private: 42 | void initParamsWidget(){} 43 | }; 44 | 45 | class Blur : public AbstractConvert 46 | { 47 | public: 48 | Blur(); 49 | ~Blur(); 50 | 51 | bool applyTo(const cv::Mat &input, cv::Mat &output); 52 | 53 | protected: 54 | void initParamsWidget(); 55 | 56 | QSpinBox *kSizeXEdit; 57 | QSpinBox *kSizeYEdit; 58 | QSpinBox *anchorXEdit; 59 | QSpinBox *anchorYEdit; 60 | QComboBox *borderTypeEdit; 61 | }; 62 | 63 | class BilateralFilter : public AbstractConvert 64 | { 65 | public: 66 | BilateralFilter(); 67 | ~BilateralFilter(); 68 | 69 | bool applyTo(const cv::Mat &input, cv::Mat &output); 70 | 71 | private: 72 | void initParamsWidget(); 73 | 74 | QSpinBox *dEdit; 75 | QSpinBox *sigmaColorEdit; 76 | QSpinBox *sigmaSpaceEdit; 77 | QComboBox *borderTypeEdit; 78 | }; 79 | 80 | class BoxFilter : public Blur 81 | { 82 | public: 83 | BoxFilter(); 84 | ~BoxFilter(); 85 | 86 | bool applyTo(const cv::Mat &input, cv::Mat &output); 87 | 88 | private: 89 | void initParamsWidget(); 90 | 91 | QComboBox *normalizeEdit; 92 | }; 93 | 94 | class MedianBlur : public AbstractConvert 95 | { 96 | public: 97 | MedianBlur(); 98 | ~MedianBlur(); 99 | 100 | bool applyTo(const cv::Mat &input, cv::Mat &output); 101 | 102 | private: 103 | void initParamsWidget(); 104 | 105 | QSpinBox *kSizeEdit; 106 | }; 107 | 108 | class GaussianBlur : public AbstractConvert 109 | { 110 | public: 111 | GaussianBlur() {} 112 | ~GaussianBlur() {} 113 | 114 | bool applyTo(const cv::Mat &input, cv::Mat &output); 115 | 116 | protected: 117 | void initParamsWidget(); 118 | 119 | QSpinBox *kSizeXEdit; 120 | QSpinBox *kSizeYEdit; 121 | QSpinBox *sigmaXEdit; 122 | QSpinBox *sigmaYEdit; 123 | QComboBox *borderTypeEdit; 124 | }; 125 | 126 | class Threshold : public AbstractConvert 127 | { 128 | public: 129 | Threshold() {} 130 | ~Threshold() {} 131 | 132 | bool applyTo(const cv::Mat &input, cv::Mat &output); 133 | 134 | protected: 135 | void initParamsWidget(); 136 | 137 | QSpinBox *threshEdit; 138 | QSpinBox *maxvalEdit; 139 | QComboBox *typeEdit; 140 | QCheckBox *otsuButton; 141 | }; 142 | 143 | class Canny : public AbstractConvert 144 | { 145 | public: 146 | Canny() {} 147 | ~Canny() {} 148 | 149 | bool applyTo(const cv::Mat &input, cv::Mat &output); 150 | 151 | protected: 152 | void initParamsWidget(); 153 | 154 | QSpinBox *threshold1Edit; 155 | QSpinBox *threshold2Edit; 156 | QSpinBox *apertureSizeEdit; 157 | QCheckBox *l2gradientButton; 158 | }; 159 | 160 | class Dilate : public AbstractConvert 161 | { 162 | public: 163 | Dilate() {} 164 | ~Dilate() {} 165 | 166 | bool applyTo(const cv::Mat &input, cv::Mat &output); 167 | 168 | protected: 169 | void initParamsWidget(); 170 | 171 | QSpinBox *kSizeXEdit; 172 | QSpinBox *kSizeYEdit; 173 | QComboBox *kShapeEdit; 174 | 175 | QSpinBox *anchorXEdit; 176 | QSpinBox *anchorYEdit; 177 | QSpinBox *iterationsEdit; 178 | QComboBox *borderTypeEdit; 179 | }; 180 | 181 | class Erode : public Dilate 182 | { 183 | public: 184 | Erode() {} 185 | ~Erode() {} 186 | 187 | bool applyTo(const cv::Mat &input, cv::Mat &output); 188 | }; 189 | 190 | class HoughCircles : public AbstractConvert 191 | { 192 | public: 193 | HoughCircles() {} 194 | ~HoughCircles() {} 195 | 196 | bool applyTo(const cv::Mat &input, cv::Mat &output); 197 | 198 | protected: 199 | void initParamsWidget(); 200 | 201 | QComboBox *methodEdit; 202 | QSpinBox *dpEdit; 203 | QSpinBox *minDistEdit; 204 | 205 | QSpinBox *param1Edit; 206 | QSpinBox *param2Edit; 207 | QSpinBox *minRadiusEdit; 208 | QSpinBox *maxRadiusEdit; 209 | QPlainTextEdit *infoEdit; 210 | }; 211 | 212 | class FitEllipse : public AbstractConvert 213 | { 214 | public: 215 | FitEllipse() {} 216 | ~FitEllipse() {} 217 | 218 | bool applyTo(const cv::Mat &input, cv::Mat &output); 219 | 220 | protected: 221 | void initParamsWidget(); 222 | 223 | QPlainTextEdit *infoEdit; 224 | }; 225 | 226 | #endif // ABSTRACTCONVERT_H 227 | -------------------------------------------------------------------------------- /examples/imageprocess/imageprocess.pro: -------------------------------------------------------------------------------- 1 | include(../../opencv.pri) 2 | include(../shared/shared.pri) 3 | 4 | greaterThan(QT_MAJOR_VERSION, 4) { 5 | QT += widgets 6 | CONFIG += C++11 7 | } else { 8 | QMAKE_CXXFLAGS += -std=c++0x 9 | } 10 | 11 | TARGET = imageprocess 12 | TEMPLATE = app 13 | 14 | SOURCES += main.cpp\ 15 | mainwindow.cpp \ 16 | recentfiles.cpp \ 17 | convert.cpp 18 | 19 | HEADERS += mainwindow.h \ 20 | recentfiles.h \ 21 | convert.h 22 | 23 | FORMS += mainwindow.ui 24 | -------------------------------------------------------------------------------- /examples/imageprocess/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | a.setApplicationName("OpenCV_ImageProcess"); 8 | a.setOrganizationName("Debao"); 9 | MainWindow w; 10 | w.showMaximized(); 11 | 12 | return a.exec(); 13 | } 14 | -------------------------------------------------------------------------------- /examples/imageprocess/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | #include "recentfiles.h" 4 | #include "convert.h" 5 | 6 | #include "opencv2/core/core.hpp" 7 | #include "opencv2/imgproc/imgproc.hpp" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | enum 15 | { 16 | E_ConvertToGray, 17 | //vvvvvvvvv 18 | E_BilateralFilter, 19 | E_Blur, 20 | E_BoxFilter, 21 | E_Filter2D, 22 | E_GaussianBlur, 23 | E_MedianBlur, 24 | E_THRESHOLD, 25 | E_Canny, 26 | E_Dilate, 27 | E_Erode, 28 | 29 | E_HoughCircles, 30 | E_FitEllipse, 31 | }; 32 | 33 | MainWindow::MainWindow(QWidget *parent) : 34 | QMainWindow(parent), 35 | ui(new Ui::MainWindow), m_recentFiles(new RecentFiles(this)) 36 | { 37 | ui->setupUi(this); 38 | ui->actionRecentFiles->setMenu(m_recentFiles->menu()); 39 | 40 | createImageActions(); 41 | 42 | connect(m_recentFiles, SIGNAL(activated(QString)), SLOT(onRecentFilesTriggered(QString))); 43 | connect(ui->actionOpen, SIGNAL(triggered()), SLOT(onFileOpenActionTriggered())); 44 | connect(ui->actionSave, SIGNAL(triggered()), SLOT(onFileSaveActionTriggered())); 45 | connect(ui->actionSaveAs, SIGNAL(triggered()), SLOT(onFileSaveAsActionTriggered())); 46 | connect(ui->filterApplyButton, SIGNAL(clicked()), SLOT(onFilterApplyButtonClicked())); 47 | connect(ui->filterPreviewButton, SIGNAL(clicked()), SLOT(onFilterPreviewButtonClicked())); 48 | connect(ui->originalView, SIGNAL(colorUnderMouseChanged(QColor)), SLOT(onColorUnderMouseChanged(QColor))); 49 | connect(ui->processView, SIGNAL(colorUnderMouseChanged(QColor)), SLOT(onColorUnderMouseChanged(QColor))); 50 | connect(ui->originalView, SIGNAL(realScaleChanged(double)), ui->processView, SLOT(setCurrentScale(double))); 51 | connect(ui->processView, SIGNAL(realScaleChanged(double)), ui->originalView, SLOT(setCurrentScale(double))); 52 | //Todo 53 | connect(ui->originalView->horizontalScrollBar(), SIGNAL(valueChanged(int)), ui->processView->horizontalScrollBar(), SLOT(setValue(int))); 54 | connect(ui->originalView->verticalScrollBar(), SIGNAL(valueChanged(int)), ui->processView->verticalScrollBar(), SLOT(setValue(int))); 55 | 56 | ui->filterDockWidget->setEnabled(false); 57 | loadSettings(); 58 | } 59 | 60 | MainWindow::~MainWindow() 61 | { 62 | delete ui; 63 | } 64 | 65 | void MainWindow::onFileOpenActionTriggered() 66 | { 67 | QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), m_recentFiles->mostRecentFile(), "Images(*.png *.bmp *.jpg *.gif)"); 68 | if (fileName.isEmpty()) 69 | return; 70 | doOpen(fileName); 71 | } 72 | 73 | void MainWindow::onRecentFilesTriggered(const QString &filePath) 74 | { 75 | doOpen(filePath); 76 | } 77 | 78 | void MainWindow::onFileSaveActionTriggered() 79 | { 80 | if (ui->originalView->pixmap().isNull()) 81 | return; 82 | ui->originalView->pixmap().save(m_recentFiles->mostRecentFile()); 83 | } 84 | 85 | void MainWindow::onFileSaveAsActionTriggered() 86 | { 87 | if (ui->originalView->pixmap().isNull()) 88 | return; 89 | 90 | QString fileName = QFileDialog::getSaveFileName(this, tr("Save Image"), m_recentFiles->mostRecentFile(), "Images(*.png *.bmp *.jpg *.gif)"); 91 | if (fileName.isEmpty()) 92 | return; 93 | ui->originalView->pixmap().save(fileName); 94 | } 95 | 96 | void MainWindow::onImageActionTriggered() 97 | { 98 | if (m_originalMat.empty()) 99 | return; 100 | 101 | QAction *act = qobject_cast(sender()); 102 | int id = act->property("id").toInt(); 103 | m_convert.clear(); 104 | 105 | switch (id) { 106 | case E_ConvertToGray: 107 | m_convert = QSharedPointer(new Gray()); 108 | break; 109 | case E_Blur: 110 | m_convert = QSharedPointer(new Blur()); 111 | break; 112 | case E_BilateralFilter: 113 | m_convert = QSharedPointer(new BilateralFilter); 114 | break; 115 | case E_BoxFilter: 116 | m_convert = QSharedPointer(new BoxFilter); 117 | break; 118 | case E_MedianBlur: 119 | m_convert = QSharedPointer(new MedianBlur); 120 | break; 121 | case E_GaussianBlur: 122 | m_convert = QSharedPointer(new GaussianBlur); 123 | break; 124 | case E_Filter2D: 125 | break; 126 | case E_THRESHOLD: 127 | m_convert = QSharedPointer(new Threshold); 128 | break; 129 | case E_Canny: 130 | m_convert = QSharedPointer(new Canny); 131 | break; 132 | case E_Dilate: 133 | m_convert = QSharedPointer(new Dilate); 134 | break; 135 | case E_Erode: 136 | m_convert = QSharedPointer(new Erode); 137 | break; 138 | 139 | case E_HoughCircles: 140 | m_convert = QSharedPointer(new HoughCircles); 141 | break; 142 | case E_FitEllipse: 143 | m_convert = QSharedPointer(new FitEllipse); 144 | break; 145 | default: 146 | break; 147 | } 148 | 149 | ui->processView->setPixmap(QPixmap()); 150 | ui->filterDockWidget->setEnabled(m_convert); 151 | if (m_convert) { 152 | ui->filterDockWidget->setWindowTitle(act->text()); 153 | ui->paramsWidget->layout()->addWidget(m_convert->paramsWidget()); 154 | } 155 | } 156 | 157 | void MainWindow::onFilterPreviewButtonClicked() 158 | { 159 | if (!m_convert) 160 | return; 161 | qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); 162 | if (m_convert->applyTo(m_originalMat, m_processMat)) 163 | ui->processView->setImage(QtOcv::mat2Image_shared(m_processMat)); 164 | else 165 | statusBar()->showMessage(m_convert->errorString(), 3000); 166 | qApp->restoreOverrideCursor(); 167 | } 168 | 169 | void MainWindow::onFilterApplyButtonClicked() 170 | { 171 | if (ui->processView->pixmap().isNull()) 172 | onFilterPreviewButtonClicked(); 173 | 174 | ui->originalView->setPixmap(ui->processView->pixmap()); 175 | m_originalMat = m_processMat; 176 | m_processMat = cv::Mat(); 177 | ui->processView->setPixmap(QPixmap()); 178 | } 179 | 180 | void MainWindow::onColorUnderMouseChanged(const QColor &c) 181 | { 182 | if (c.isValid()) 183 | statusBar()->showMessage(QString("R %1 G %2 B %3").arg(c.red()).arg(c.green()).arg(c.blue())); 184 | else 185 | statusBar()->clearMessage(); 186 | } 187 | 188 | void MainWindow::closeEvent(QCloseEvent *evt) 189 | { 190 | saveSettings(); 191 | evt->accept(); 192 | } 193 | 194 | void MainWindow::loadSettings() 195 | { 196 | QSettings settings; 197 | settings.beginGroup("RecentFiles"); 198 | m_recentFiles->setFileList(settings.value("list").toStringList()); 199 | settings.endGroup(); 200 | } 201 | 202 | void MainWindow::saveSettings() 203 | { 204 | QSettings settings; 205 | settings.beginGroup("RecentFiles"); 206 | settings.setValue("list", m_recentFiles->fileList()); 207 | settings.endGroup(); 208 | } 209 | 210 | void MainWindow::createImageAction(int id, const QString &text) 211 | { 212 | QAction *act = ui->menuImage->addAction(text, this, SLOT(onImageActionTriggered())); 213 | act->setProperty("id", id); 214 | m_imageActions.insert(id, act); 215 | } 216 | 217 | void MainWindow::createImageActions() 218 | { 219 | createImageAction(E_ConvertToGray, "Convert To Gray"); 220 | ui->menuImage->addSeparator(); 221 | createImageAction(E_THRESHOLD, "Threshold"); 222 | 223 | createImageAction(E_BilateralFilter, "Bilateral Filter"); 224 | createImageAction(E_Blur, "Blur"); 225 | createImageAction(E_BoxFilter, "Box Filter"); 226 | createImageAction(E_Filter2D, "Filter2D"); 227 | createImageAction(E_GaussianBlur, "Gaussian Blur"); 228 | createImageAction(E_MedianBlur, "Median Blur"); 229 | createImageAction(E_Canny, "Canny"); 230 | createImageAction(E_Dilate, "Dilate"); 231 | createImageAction(E_Erode, "Erode"); 232 | 233 | ui->menuImage->addSeparator(); 234 | createImageAction(E_HoughCircles, "HoughCircles"); 235 | createImageAction(E_FitEllipse, "FitEllipse"); 236 | } 237 | 238 | void MainWindow::doOpen(const QString &filePath) 239 | { 240 | QImage image(filePath); 241 | if (image.isNull()) { 242 | m_recentFiles->remove(filePath); 243 | return; 244 | } 245 | 246 | m_recentFiles->add(filePath); 247 | ui->originalView->setImage(image); 248 | ui->originalView->setCurrentScale(0);//Auto scale 249 | ui->processView->setPixmap(QPixmap()); 250 | ui->processView->setCurrentScale(0); 251 | bool isGray = image.isGrayscale(); 252 | m_originalMat = QtOcv::image2Mat(image, CV_8UC(isGray ? 1 : 3), QtOcv::MCO_RGB); 253 | setWindowTitle(QString("%1[*] - Image Process").arg(filePath)); 254 | } 255 | -------------------------------------------------------------------------------- /examples/imageprocess/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "cvmatandqimage.h" 8 | 9 | namespace Ui { 10 | class MainWindow; 11 | } 12 | class RecentFiles; 13 | class AbstractConvert; 14 | class MainWindow : public QMainWindow 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit MainWindow(QWidget *parent = 0); 20 | ~MainWindow(); 21 | 22 | private slots: 23 | void onFileOpenActionTriggered(); 24 | void onRecentFilesTriggered(const QString &filePath); 25 | void onFileSaveActionTriggered(); 26 | void onFileSaveAsActionTriggered(); 27 | void onImageActionTriggered(); 28 | void onFilterPreviewButtonClicked(); 29 | void onFilterApplyButtonClicked(); 30 | void onColorUnderMouseChanged(const QColor &c); 31 | 32 | private: 33 | void closeEvent(QCloseEvent *evt); 34 | void loadSettings(); 35 | void saveSettings(); 36 | void createImageAction(int id, const QString &text); 37 | void createImageActions(); 38 | void doOpen(const QString &filePath); 39 | 40 | Ui::MainWindow *ui; 41 | RecentFiles *m_recentFiles; 42 | QMap m_imageActions; 43 | cv::Mat m_originalMat; 44 | cv::Mat m_processMat; 45 | QSharedPointer m_convert; 46 | }; 47 | 48 | #endif // MAINWINDOW_H 49 | -------------------------------------------------------------------------------- /examples/imageprocess/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 780 10 | 444 11 | 12 | 13 | 14 | Image Process 15 | 16 | 17 | 18 | 19 | 20 | 21 | Qt::Horizontal 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 0 34 | 0 35 | 780 36 | 23 37 | 38 | 39 | 40 | 41 | &File 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | &Image 54 | 55 | 56 | 57 | 58 | &Help 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea 69 | 70 | 71 | Image Filter 72 | 73 | 74 | 2 75 | 76 | 77 | 78 | 79 | 0 80 | 81 | 82 | 0 83 | 84 | 85 | 0 86 | 87 | 88 | 0 89 | 90 | 91 | 92 | 93 | 94 | 0 95 | 0 96 | 97 | 98 | 99 | 100 | 0 101 | 102 | 103 | 0 104 | 105 | 106 | 0 107 | 108 | 109 | 0 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 0 119 | 0 120 | 121 | 122 | 123 | Preview 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 0 132 | 0 133 | 134 | 135 | 136 | Apply 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | About... 146 | 147 | 148 | 149 | 150 | &Open... 151 | 152 | 153 | 154 | 155 | Close 156 | 157 | 158 | 159 | 160 | Recent Files 161 | 162 | 163 | 164 | 165 | Save 166 | 167 | 168 | 169 | 170 | Save As... 171 | 172 | 173 | 174 | 175 | 176 | 177 | QtOcv::ImageWidget 178 | QGraphicsView 179 |
cvimagewidget.h
180 |
181 |
182 | 183 | 184 |
185 | -------------------------------------------------------------------------------- /examples/imageprocess/recentfiles.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Copyright (c) 2012-2015 Debao Zhang 3 | ** All right reserved. 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining 6 | ** a copy of this software and associated documentation files (the 7 | ** "Software"), to deal in the Software without restriction, including 8 | ** without limitation the rights to use, copy, modify, merge, publish, 9 | ** distribute, sublicense, and/or sell copies of the Software, and to 10 | ** permit persons to whom the Software is furnished to do so, subject to 11 | ** the following conditions: 12 | ** 13 | ** The above copyright notice and this permission notice shall be 14 | ** included in all copies or substantial portions of the Software. 15 | ** 16 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | ** 24 | ****************************************************************************/ 25 | #include "recentfiles.h" 26 | #include 27 | #include 28 | 29 | RecentFiles::RecentFiles(QObject *parent) : 30 | QObject(parent), m_maxCount(50), m_maxPathLength(400), m_dirty(true), m_menu(new QMenu("Recent Files")) 31 | { 32 | 33 | m_menu->installEventFilter(this); 34 | } 35 | 36 | RecentFiles::~RecentFiles() 37 | { 38 | if (!m_menu.isNull()) 39 | delete m_menu; 40 | } 41 | 42 | QMenu *RecentFiles::menu() const 43 | { 44 | return m_menu; 45 | } 46 | 47 | int RecentFiles::maxFileCount() const 48 | { 49 | return m_maxCount; 50 | } 51 | 52 | void RecentFiles::setMaxFileCount(int maxCount) 53 | { 54 | m_maxCount = maxCount; 55 | if (m_maxCount > m_fileList.count()) 56 | m_fileList = m_fileList.mid(0, m_maxCount); 57 | } 58 | 59 | QStringList RecentFiles::fileList() const 60 | { 61 | return m_fileList; 62 | } 63 | 64 | void RecentFiles::setFileList(const QStringList &fileList) 65 | { 66 | m_fileList = fileList; 67 | m_dirty = true; 68 | } 69 | 70 | QString RecentFiles::mostRecentFile() const 71 | { 72 | return m_fileList.isEmpty() ? QString() : m_fileList.at(0); 73 | } 74 | 75 | void RecentFiles::add(const QString &filePath) 76 | { 77 | if (m_fileList.count() > 0 && m_fileList[0] == filePath) 78 | return; 79 | 80 | m_fileList.removeAll(filePath); 81 | m_fileList.insert(0, filePath); 82 | while (m_fileList.count() > m_maxCount) 83 | m_fileList.removeLast(); 84 | 85 | m_dirty = true; 86 | } 87 | 88 | void RecentFiles::clear() 89 | { 90 | if (m_fileList.isEmpty()) 91 | return; 92 | m_fileList.clear(); 93 | m_dirty = true; 94 | } 95 | 96 | void RecentFiles::remove(const QString &filePath) 97 | { 98 | if (m_fileList.removeAll(filePath)) 99 | m_dirty = true; 100 | } 101 | 102 | void RecentFiles::onActionTriggered() 103 | { 104 | QAction *act = qobject_cast(sender()); 105 | if (!act) 106 | return; 107 | 108 | emit activated(act->data().toString()); 109 | } 110 | 111 | bool RecentFiles::eventFilter(QObject *obj, QEvent *evt) 112 | { 113 | if (obj == m_menu && evt->type() == QEvent::Show && m_dirty) { 114 | m_menu->clear(); 115 | foreach (QString filePath, m_fileList) { 116 | QString title = QFontMetrics(m_menu->font()).elidedText(filePath, Qt::ElideMiddle, m_maxPathLength); 117 | QAction *act = new QAction(title, m_menu.data()); 118 | act->setData(filePath); 119 | m_menu->addAction(act); 120 | 121 | connect(act, SIGNAL(triggered()), SLOT(onActionTriggered())); 122 | } 123 | m_menu->addSeparator(); 124 | QAction *clearAction = m_menu->addAction(tr("Clear Menu"), this, SLOT(clear())); 125 | clearAction->setDisabled(m_fileList.isEmpty()); 126 | m_dirty = false; 127 | } 128 | return QObject::eventFilter(obj, evt); 129 | } 130 | 131 | -------------------------------------------------------------------------------- /examples/imageprocess/recentfiles.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Copyright (c) 2012-2015 Debao Zhang 3 | ** All right reserved. 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining 6 | ** a copy of this software and associated documentation files (the 7 | ** "Software"), to deal in the Software without restriction, including 8 | ** without limitation the rights to use, copy, modify, merge, publish, 9 | ** distribute, sublicense, and/or sell copies of the Software, and to 10 | ** permit persons to whom the Software is furnished to do so, subject to 11 | ** the following conditions: 12 | ** 13 | ** The above copyright notice and this permission notice shall be 14 | ** included in all copies or substantial portions of the Software. 15 | ** 16 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | ** 24 | ****************************************************************************/ 25 | #ifndef RECENTFILES_H 26 | #define RECENTFILES_H 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | class QMenu; 33 | 34 | class RecentFiles : public QObject 35 | { 36 | Q_OBJECT 37 | public: 38 | explicit RecentFiles(QObject *parent = 0); 39 | ~RecentFiles(); 40 | 41 | QMenu *menu() const; 42 | 43 | int maxFileCount() const; 44 | void setMaxFileCount(int maxCount); 45 | 46 | QStringList fileList() const; 47 | void setFileList(const QStringList &fileList); 48 | 49 | QString mostRecentFile() const; 50 | 51 | signals: 52 | void activated(const QString &filePath); 53 | 54 | public slots: 55 | void add(const QString &filePath); 56 | void clear(); 57 | void remove(const QString &filePath); 58 | 59 | private slots: 60 | void onActionTriggered(); 61 | 62 | private: 63 | bool eventFilter(QObject *obj, QEvent *evt); 64 | void updateMenu(); 65 | int m_maxCount; 66 | int m_maxPathLength; 67 | QStringList m_fileList; 68 | bool m_dirty; 69 | QPointer m_menu; 70 | }; 71 | 72 | #endif // RECENTFILES_H 73 | -------------------------------------------------------------------------------- /examples/shared/cvimagewidget.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Copyright (c) 2012-2015 Debao Zhang 3 | ** All right reserved. 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining 6 | ** a copy of this software and associated documentation files (the 7 | ** "Software"), to deal in the Software without restriction, including 8 | ** without limitation the rights to use, copy, modify, merge, publish, 9 | ** distribute, sublicense, and/or sell copies of the Software, and to 10 | ** permit persons to whom the Software is furnished to do so, subject to 11 | ** the following conditions: 12 | ** 13 | ** The above copyright notice and this permission notice shall be 14 | ** included in all copies or substantial portions of the Software. 15 | ** 16 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | ** 24 | ****************************************************************************/ 25 | #include "cvimagewidget.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | namespace QtOcv { 37 | 38 | class ImageWidgetPrivate 39 | { 40 | public: 41 | ImageWidgetPrivate(ImageWidget *q); 42 | ~ImageWidgetPrivate(){} 43 | 44 | void dealWithScaleChanged(double rSacle, bool causedByWheel=true); 45 | void doAutoFit(); 46 | QColor getColorUnderMouse(); 47 | 48 | double m_scale; //on work when view rotate 0, 90, 180, 270 49 | double m_scaleMax; 50 | double m_scaleMin; 51 | 52 | QColor m_lastColor; 53 | 54 | bool m_wheelScaleEnabled; 55 | bool m_autoAdjustEnabled; 56 | QGraphicsPixmapItem *m_pixmapItem; 57 | 58 | ImageWidget *q; 59 | }; 60 | 61 | ImageWidgetPrivate::ImageWidgetPrivate(ImageWidget *q) : 62 | q(q) 63 | { 64 | m_scale = 1; 65 | m_scaleMin = 0.01; 66 | m_scaleMax = 64; 67 | m_wheelScaleEnabled = true; 68 | m_autoAdjustEnabled = false; 69 | } 70 | 71 | /*! 72 | This is the only place where the scale changed! 73 | When scale changed, a signal will be emitted with the new scale. 74 | Note: the function only works when the view does not rotate, or rotate n*90 degree. 75 | */ 76 | void ImageWidgetPrivate::dealWithScaleChanged(double rScale, bool causedByWheel) 77 | { 78 | if (fabs(rScale - 1)<10e-4) 79 | return; 80 | 81 | if (causedByWheel) 82 | q->setTransformationAnchor(QGraphicsView::AnchorUnderMouse); 83 | else 84 | q->setTransformationAnchor(QGraphicsView::AnchorViewCenter); 85 | 86 | q->scale(rScale, rScale); 87 | m_scale = qMax(fabs(q->transform().m11()),fabs(q->transform().m12())); 88 | emit q->scaleChanged(m_scale); 89 | emit q->realScaleChanged(m_scale); 90 | } 91 | 92 | void ImageWidgetPrivate::doAutoFit() 93 | { 94 | if (!m_autoAdjustEnabled || !q->scene()) 95 | return; 96 | 97 | q->fitInView(q->scene()->sceneRect(), Qt::KeepAspectRatio); 98 | m_scale = qMax(fabs(q->transform().m11()),fabs(q->transform().m12())); 99 | emit q->realScaleChanged(m_scale); 100 | } 101 | 102 | QColor ImageWidgetPrivate::getColorUnderMouse() 103 | { 104 | QColor c; 105 | if (!m_pixmapItem->pixmap().isNull()) { 106 | QPoint pos = q->mapToScene(q->mapFromGlobal(QCursor::pos())).toPoint(); 107 | if (q->scene()->sceneRect().contains(pos)) 108 | c = QColor(q->pixmap().copy(pos.x(), pos.y(), 1, 1).toImage().pixel(0, 0)); 109 | } 110 | return c; 111 | } 112 | 113 | /*! 114 | \class QtOcv::ImageWidget 115 | */ 116 | 117 | /*! 118 | Default constructor. 119 | */ 120 | ImageWidget::ImageWidget(QWidget *parent) 121 | :QGraphicsView(parent), d(new ImageWidgetPrivate(this)) 122 | { 123 | QGraphicsScene *sc = new QGraphicsScene(this); 124 | d->m_pixmapItem = new QGraphicsPixmapItem; 125 | sc->addItem(d->m_pixmapItem); 126 | setScene(sc); 127 | setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); 128 | setDragMode(ScrollHandDrag); 129 | setMouseTracking(true); 130 | 131 | // QPixmap pix(512, 512); 132 | // pix.fill(Qt::gray); 133 | // setPixmap(pix); 134 | } 135 | 136 | ImageWidget::~ImageWidget() 137 | { 138 | delete d; 139 | } 140 | 141 | QPixmap ImageWidget::pixmap() const 142 | { 143 | return d->m_pixmapItem->pixmap(); 144 | } 145 | 146 | QColor ImageWidget::colorUnderMouse() const 147 | { 148 | return d->m_lastColor; 149 | } 150 | 151 | void ImageWidget::setPixmap(const QPixmap &pixmap) 152 | { 153 | d->m_pixmapItem->setPixmap(pixmap); 154 | 155 | if (scene()->sceneRect() != d->m_pixmapItem->boundingRect()) { 156 | //Be careful. 157 | //Note that, when pixmap isNull, the sceneRect() is not null, 158 | //though setSceneRect(QRectF()) is called. 159 | scene()->setSceneRect(d->m_pixmapItem->boundingRect()); 160 | 161 | if (d->m_autoAdjustEnabled) 162 | d->doAutoFit(); 163 | } 164 | 165 | QColor c = d->getColorUnderMouse(); 166 | if (c != d->m_lastColor) { 167 | d->m_lastColor = c; 168 | emit colorUnderMouseChanged(c); 169 | } 170 | } 171 | 172 | void ImageWidget::setImage(const QImage &image) 173 | { 174 | setPixmap(QPixmap::fromImage(image)); 175 | } 176 | 177 | double ImageWidget::currentScale() const 178 | { 179 | if (d->m_autoAdjustEnabled) 180 | return 0; 181 | 182 | return d->m_scale; 183 | } 184 | 185 | double ImageWidget::currentRealScale() const 186 | { 187 | return d->m_scale; 188 | } 189 | 190 | bool ImageWidget::isMouseWheelEnabled() const 191 | { 192 | return d->m_wheelScaleEnabled; 193 | } 194 | 195 | /*! 196 | Set a scale value to the View. 197 | When the value is out of the scale range, the value will be adjusted. 198 | 199 | Note that, scale 0 mean auto fit. 200 | 201 | \sa setScaleRange() 202 | */ 203 | void ImageWidget::setCurrentScale(double factor) 204 | { 205 | if (factor == currentScale()) 206 | return; 207 | 208 | if (factor == 0) { 209 | if (!d->m_autoAdjustEnabled) { 210 | d->m_autoAdjustEnabled = true; 211 | d->doAutoFit(); 212 | emit scaleChanged(0); 213 | } 214 | return; 215 | } 216 | 217 | if (d->m_autoAdjustEnabled) 218 | d->m_autoAdjustEnabled = false; 219 | 220 | if (factor > d->m_scaleMax) 221 | factor = d->m_scaleMax; 222 | else if (factor < d->m_scaleMin) 223 | factor = d->m_scaleMin; 224 | 225 | d->dealWithScaleChanged(factor/d->m_scale); 226 | } 227 | 228 | void ImageWidget::setMouseWheelEnabled(bool enable) 229 | { 230 | d->m_wheelScaleEnabled = enable; 231 | } 232 | 233 | /*! 234 | Set the range of scale. 235 | When current scale value not in the range, the value will be adjusted. 236 | \sa setCurrentScale() 237 | */ 238 | void ImageWidget::setScaleRange(double min, double max) 239 | { 240 | d->m_scaleMin = min; 241 | d->m_scaleMax = max; 242 | if (!d->m_autoAdjustEnabled) { 243 | if (d->m_scale < d->m_scaleMin) 244 | setCurrentScale(d->m_scaleMin); 245 | else if (d->m_scale > d->m_scaleMax) 246 | setCurrentScale(d->m_scaleMax); 247 | } 248 | } 249 | 250 | /*! 251 | deal with wheel event. 252 | */ 253 | void ImageWidget::wheelEvent(QWheelEvent *event) 254 | { 255 | if (d->m_wheelScaleEnabled) { 256 | //Disable auto fit!! 257 | d->m_autoAdjustEnabled = false; 258 | 259 | double numDegrees = -event->delta() / 8.0; 260 | double numSteps = numDegrees / 15.0; 261 | double factor = pow(1.125, numSteps); 262 | 263 | if (numSteps > 0) 264 | factor = qMin(factor, d->m_scaleMax/d->m_scale); 265 | else 266 | factor = qMax(factor, d->m_scaleMin/d->m_scale); 267 | 268 | d->dealWithScaleChanged(factor); 269 | } 270 | 271 | //QGraphicsView::wheelEvent(event); 272 | } 273 | 274 | void ImageWidget::mouseMoveEvent(QMouseEvent *event) 275 | { 276 | QColor c = d->getColorUnderMouse(); 277 | if (c != d->m_lastColor) { 278 | d->m_lastColor = c; 279 | emit colorUnderMouseChanged(c); 280 | } 281 | 282 | QGraphicsView::mouseMoveEvent(event); 283 | } 284 | 285 | void ImageWidget::leaveEvent(QEvent *event) 286 | { 287 | if (d->m_lastColor.isValid()) { 288 | d->m_lastColor = QColor(); 289 | emit colorUnderMouseChanged(QColor()); 290 | } 291 | QGraphicsView::leaveEvent(event); 292 | } 293 | 294 | void ImageWidget::resizeEvent(QResizeEvent *event) 295 | { 296 | if (d->m_autoAdjustEnabled) { 297 | //Auto fit enabled. 298 | d->doAutoFit(); 299 | } 300 | QGraphicsView::resizeEvent(event); 301 | } 302 | 303 | } //namespace QtOcv 304 | -------------------------------------------------------------------------------- /examples/shared/cvimagewidget.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Copyright (c) 2012-2015 Debao Zhang 3 | ** All right reserved. 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining 6 | ** a copy of this software and associated documentation files (the 7 | ** "Software"), to deal in the Software without restriction, including 8 | ** without limitation the rights to use, copy, modify, merge, publish, 9 | ** distribute, sublicense, and/or sell copies of the Software, and to 10 | ** permit persons to whom the Software is furnished to do so, subject to 11 | ** the following conditions: 12 | ** 13 | ** The above copyright notice and this permission notice shall be 14 | ** included in all copies or substantial portions of the Software. 15 | ** 16 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | ** 24 | ****************************************************************************/ 25 | #ifndef QTOCVIMAGEWIDGET_H 26 | #define QTOCVIMAGEWIDGET_H 27 | 28 | #include 29 | 30 | namespace QtOcv { 31 | class ImageWidgetPrivate; 32 | class ImageWidget : public QGraphicsView 33 | { 34 | Q_OBJECT 35 | public: 36 | ImageWidget(QWidget *parent=0); 37 | ~ImageWidget(); 38 | 39 | double currentScale() const; 40 | double currentRealScale() const; 41 | bool isMouseWheelEnabled() const; 42 | 43 | QPixmap pixmap() const; 44 | QColor colorUnderMouse() const; 45 | 46 | public slots: 47 | void setCurrentScale(double currentScale); 48 | void setScaleRange(double min, double max); 49 | void setMouseWheelEnabled(bool enable); 50 | 51 | void setImage(const QImage &image); 52 | void setPixmap(const QPixmap &pixmap); 53 | 54 | signals: 55 | void scaleChanged(double scale); 56 | void realScaleChanged(double scale); 57 | void colorUnderMouseChanged(const QColor &color); 58 | 59 | protected: 60 | void wheelEvent(QWheelEvent *event); 61 | void mouseMoveEvent(QMouseEvent *event); 62 | void leaveEvent(QEvent *event); 63 | void resizeEvent(QResizeEvent *event); 64 | 65 | private: 66 | friend class ImageWidgetPrivate; 67 | ImageWidgetPrivate *d; 68 | }; 69 | 70 | } //namespace QtOcv 71 | #endif // QTOCVIMAGEWIDGET_H 72 | -------------------------------------------------------------------------------- /examples/shared/shared.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD 2 | DEPENDPATH += $$PWD 3 | 4 | HEADERS += \ 5 | $$PWD/cvimagewidget.h 6 | SOURCES += \ 7 | $$PWD/cvimagewidget.cpp 8 | -------------------------------------------------------------------------------- /examples/simple/main.cpp: -------------------------------------------------------------------------------- 1 | #include "cvmatandqimage.h" 2 | #include "cvimagewidget.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | //We don't defined any custom classes in this example. 12 | 13 | QtOcv::ImageWidget *createImageWindow(const QImage &img, const QString &title=QString()); 14 | 15 | void process1() 16 | { 17 | //Get an image file path. 18 | QString dir = ""; 19 | QString filePath = QFileDialog::getOpenFileName(0, "Open", dir, "Images(*.png *.bmp *.jpg *.gif)"); 20 | if (filePath.isEmpty()) 21 | return; 22 | 23 | //Show the original image in a window. 24 | QImage sourceImage = QImage(filePath); 25 | createImageWindow(sourceImage, filePath); 26 | 27 | //Get CV_8UC3(RGB) or CV_8UC1 mats 28 | //no matter which format the QImage is actully used. 29 | cv::Mat mat_8UC3_rgb = QtOcv::image2Mat(sourceImage, CV_8UC3, QtOcv::MCO_RGB); 30 | #if 0 31 | cv::Mat mat_8UC1_gray = QtOcv::image2Mat(sourceImage, CV_8UC1); 32 | #else 33 | cv::Mat mat_8UC1_gray(mat_8UC3_rgb.rows, mat_8UC3_rgb.cols, CV_8UC1); 34 | int from_to[] = {1, 0}; 35 | cv::mixChannels(&mat_8UC3_rgb, 1, &mat_8UC1_gray, 1, from_to, 1); 36 | #endif 37 | //Show the gray image in a new window if needed. 38 | createImageWindow(QtOcv::mat2Image_shared(mat_8UC1_gray), "Gray Image"); 39 | 40 | //Create mono chrome mat. 41 | cv::Mat mat_mono; 42 | 43 | #if 1 44 | # if 1 45 | double minVal, maxVal; 46 | cv::minMaxIdx(mat_8UC1_gray, &maxVal, &minVal); 47 | double v = (maxVal - minVal) * 0.3 + minVal; 48 | //v = 255 * 0.4; 49 | cv::threshold(mat_8UC1_gray, mat_mono, v, 255, cv::THRESH_BINARY); 50 | # else 51 | cv::adaptiveThreshold(mat_8UC1_gray, mat_mono, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 3, -1); 52 | # endif 53 | //Show the mono image in a new window if needed. 54 | createImageWindow(QtOcv::mat2Image_shared(mat_mono), "mono Image"); 55 | #else 56 | mat_mono = mat_8UC1_gray; 57 | #endif 58 | 59 | // cv::floodFill() 60 | 61 | // Apply the dilation operation 62 | cv::Mat mat_dilation; 63 | #if 0 64 | int dilation_size = 3; 65 | cv::Mat element = cv::getStructuringElement(2, cv::Size(2 * dilation_size + 1, 2 * dilation_size + 1), 66 | cv::Point(dilation_size, dilation_size)); // dilation_type = MORPH_ELLIPSE 67 | cv::dilate(mat_mono, mat_dilation, element); 68 | //Show the mono image in a new window if needed. 69 | createImageWindow(QtOcv::mat2Image_shared(mat_dilation), "Dilation Image"); 70 | #else 71 | mat_dilation = mat_mono; 72 | #endif 73 | 74 | //Try detected edges of the mono image. 75 | int kernel_size = 3; 76 | cv::Mat detected_edges; 77 | // Reduce noise with a kernel 3x3 78 | cv::blur(mat_dilation, detected_edges, cv::Size(5,5)); 79 | // Canny detector 80 | cv::Canny(detected_edges, detected_edges 81 | , 20 82 | , 60 83 | , kernel_size); 84 | createImageWindow(QtOcv::mat2Image_shared(detected_edges), "Edge Image"); 85 | 86 | // Apply the dilation operation again? 87 | cv::Mat mat_dilation2; 88 | int dilation_size2 = 3; 89 | cv::Mat elements = cv::getStructuringElement(2, cv::Size(2 * dilation_size2 + 1, 2 * dilation_size2 + 1), 90 | cv::Point(dilation_size2, dilation_size2)); // dilation_type = MORPH_ELLIPSE 91 | cv::dilate(detected_edges, mat_dilation2, elements); 92 | //Show the mono image in a new window if needed. 93 | createImageWindow(QtOcv::mat2Image_shared(mat_dilation2), "Dilation Image - 2"); 94 | 95 | //Find countours 96 | std::vector > contours; 97 | int find_contours_mode = CV_CHAIN_APPROX_TC89_L1; //CV_RETR_LIST 98 | cv::findContours(mat_dilation2, contours, find_contours_mode, CV_CHAIN_APPROX_NONE); 99 | std::sort(contours.begin(), contours.end(), [](std::vector a, std::vector b) { 100 | return b.size() < a.size(); 101 | }); 102 | 103 | size_t maxEllipseCount = 4; 104 | cv::Mat ellipseImage = mat_8UC3_rgb.clone(); 105 | for(size_t i = 0, foundCount = 0; (i < contours.size()) && (foundCount < maxEllipseCount); i++) { 106 | size_t count = contours[i].size(); 107 | 108 | if( count < 6 ) 109 | continue; 110 | 111 | cv::Mat pointsf; 112 | cv::Mat(contours[i]).convertTo(pointsf, CV_32F); 113 | cv::RotatedRect box = cv::fitEllipse(pointsf); 114 | 115 | if( qMax(box.size.width, box.size.height) > qMin(box.size.width, box.size.height)*30 ) 116 | continue; 117 | 118 | foundCount++; 119 | 120 | cv::ellipse(ellipseImage, box, cv::Scalar(0,0,255), 1, CV_AA); 121 | cv::ellipse(ellipseImage, box.center, box.size*0.5f, box.angle, 0, 360, cv::Scalar(0,255,255), 1, CV_AA); 122 | 123 | if (foundCount == 2) { 124 | //high light the second one. 125 | cv::Point2f vtx[4]; 126 | box.points(vtx); 127 | for( int j = 0; j < 4; j++ ) 128 | cv::line(ellipseImage, vtx[j], vtx[(j+1)%4], cv::Scalar(0,255,0), 1, CV_AA); 129 | } 130 | 131 | QString ellipseInfo = QString("Center(%1, %2) Size(%3, %4) Angle %5") 132 | .arg(box.center.x).arg(box.center.y) 133 | .arg(box.size.width).arg(box.size.height) 134 | .arg(box.angle); 135 | qDebug() << foundCount << ellipseInfo; 136 | } 137 | 138 | //Show the ellipse window 139 | createImageWindow(QtOcv::mat2Image_shared(ellipseImage), "Ellipse Image"); 140 | } 141 | 142 | static QTabWidget *topWidget = 0; 143 | 144 | int main(int argc, char *argv[]) 145 | { 146 | QApplication a(argc, argv); 147 | QTabWidget mw; 148 | mw.setWindowTitle("MainWindow of the QtOpenCV demo."); 149 | topWidget = &mw; 150 | 151 | //vvvvvvvvvvvvvv 152 | process1(); 153 | //^^^^^^^^^^^^^^ 154 | 155 | if (mw.count()) 156 | mw.showMaximized(); 157 | return a.exec(); 158 | } 159 | 160 | QtOcv::ImageWidget *createImageWindow(const QImage &img, const QString &title) 161 | { 162 | QtOcv::ImageWidget *w = new QtOcv::ImageWidget; 163 | w->setImage(img); 164 | w->setCurrentScale(0);//auto fit 165 | 166 | //Add to top tabWidget or shown as an top window. 167 | #if 1 168 | topWidget->addTab(w, title.isEmpty() ? QString("Tab%1").arg(topWidget->count()) : title); 169 | #else 170 | w->setAttribute(Qt::WA_DeleteOnClose); 171 | w->resize(800, 600); 172 | if (!title.isEmpty()) 173 | w->setWindowTitle(title); 174 | w->show(); 175 | #endif 176 | 177 | return w; 178 | } 179 | 180 | 181 | -------------------------------------------------------------------------------- /examples/simple/simple.pro: -------------------------------------------------------------------------------- 1 | include(../../opencv.pri) 2 | include(../shared/shared.pri) 3 | 4 | QT += core gui 5 | 6 | greaterThan(QT_MAJOR_VERSION, 4) { 7 | QT += widgets 8 | CONFIG += C++11 9 | } else { 10 | QMAKE_CXXFLAGS += -std=c++0x 11 | } 12 | 13 | TARGET = simple 14 | CONFIG += console 15 | CONFIG -= app_bundle 16 | 17 | TEMPLATE = app 18 | 19 | SOURCES += main.cpp 20 | -------------------------------------------------------------------------------- /opencv.pri: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # Copyright (c) 2016 Debao Zhang 3 | # All right reserved. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining 6 | # a copy of this software and associated documentation files (the 7 | # "Software"), to deal in the Software without restriction, including 8 | # without limitation the rights to use, copy, modify, merge, publish, 9 | # distribute, sublicense, and/or sell copies of the Software, and to 10 | # permit persons to whom the Software is furnished to do so, subject to 11 | # the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be 14 | # included in all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | # 24 | ########################################################################### 25 | 26 | ## Note for Windows user: 27 | ## you need to create an opencv.prf file, 28 | ## then move the .prf file to %QTDIR%/mkspecs/features/ 29 | ## see README.md for more information. 30 | 31 | # include this .pri file in your Qt Creator .pro file with include(opencv.pri) 32 | 33 | macx { 34 | QT_CONFIG -= no-pkg-config 35 | } 36 | 37 | unix{ 38 | CONFIG += link_pkgconfig 39 | PKGCONFIG += opencv 40 | } 41 | win32{ 42 | # load(opencv) instead of CONFIG+=opencv used here 43 | !load(opencv):message("You must create an opencv.prf, and move it to $$[QT_INSTALL_PREFIX]/mkspecs/features/") 44 | } 45 | 46 | # silence msvc warning 4819 47 | win32-msvc*:QMAKE_CXXFLAGS += -wd4819 48 | 49 | INCLUDEPATH += $$PWD 50 | DEPENDPATH += $$PWD 51 | 52 | HEADERS += \ 53 | $$PWD/cvmatandqimage.h 54 | 55 | SOURCES += \ 56 | $$PWD/cvmatandqimage.cpp 57 | -------------------------------------------------------------------------------- /opencv_prf_generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ########################################################################### 3 | # Copyright (c) 2016 Debao Zhang 4 | # All right reserved. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining 7 | # a copy of this software and associated documentation files (the 8 | # "Software"), to deal in the Software without restriction, including 9 | # without limitation the rights to use, copy, modify, merge, publish, 10 | # distribute, sublicense, and/or sell copies of the Software, and to 11 | # permit persons to whom the Software is furnished to do so, subject to 12 | # the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be 15 | # included in all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | # 25 | ########################################################################### 26 | 27 | """ 28 | Note: This script is designed to run on Windows platform only. 29 | 30 | Usage: 31 | python opencv_prf_generator.py [-q QMAKEPATH] opencvlibpath 32 | """ 33 | 34 | import os 35 | import re 36 | import sys 37 | import argparse 38 | import datetime 39 | import shutil 40 | import os.path 41 | 42 | def get_input(prompt): 43 | if sys.hexversion > 0x03000000: 44 | return input(prompt) 45 | else: 46 | return raw_input(prompt) 47 | 48 | def is_valid_opencv_inc_path(incpath): 49 | return incpath and os.path.exists(os.path.join(incpath, 'opencv2/core.hpp')) 50 | 51 | def get_libraries_name(libpath, pattern, groupno): 52 | librarynames = [] 53 | for name in os.listdir(libpath): 54 | match = pattern.match(name) 55 | if match: 56 | librarynames.append(match.group(groupno)) 57 | return librarynames 58 | 59 | def get_qmake_dir(path): 60 | if path.lower().endswith('qmake.exe') and os.path.exists(path): 61 | return os.path.dirname(path) 62 | 63 | if os.path.isdir(path) and os.path.exists(os.path.join(path, 'qmake.exe')): 64 | return path 65 | 66 | return None 67 | 68 | def get_qmake_dir2(): 69 | pathlist = os.environ['PATH'].split(';') 70 | for p in pathlist: 71 | if os.path.exists(os.path.join(p, 'qmake.exe')): 72 | return p 73 | return None 74 | 75 | def get_feature_dir(qmakedir): 76 | # should I run qmake to query some paths? 77 | return os.path.normpath(os.path.join(qmakedir, '../mkspecs/features/')) 78 | 79 | def get_fixed_path(path): 80 | path = path.replace('\\', '/') 81 | if ' ' in path: 82 | path = "'{0}'".format(path) 83 | return path 84 | 85 | if __name__ == '__main__': 86 | parser = argparse.ArgumentParser(description='Generate and install opencv.prf for Windows user') 87 | parser.add_argument('opencvlibpath', help="path to opencv's lib directory") 88 | parser.add_argument('-d', dest='opencvlibpathd', help="path to opencv's debug lib directory") 89 | parser.add_argument('-i', dest='opencvincpath', help="path to opencv's include directory") 90 | parser.add_argument('-q', dest='qmakepath', help='the full path of qmake') 91 | args = parser.parse_args() 92 | 93 | # find a valid includepath 94 | if args.opencvincpath: 95 | opencvincpath = os.path.normpath(args.opencvincpath) 96 | if not is_valid_opencv_inc_path(opencvincpath): 97 | sys.stderr.write ("Can't find valid INCLUDE directory {0}\n".format(opencvincpath)) 98 | sys.exit(-1) 99 | else: 100 | # try to find include path based on lib path 101 | opencvincpath = os.path.normpath(os.path.join(args.opencvlibpath, '../../../include')) 102 | if not is_valid_opencv_inc_path(opencvincpath) and args.opencvlibpathd: 103 | opencvincpath = os.path.normpath(os.path.join(args.opencvlibpathd, '../../../include')) 104 | if not is_valid_opencv_inc_path(opencvincpath): 105 | sys.stderr.write ("Can't find valid INCLUDE directory\n") 106 | sys.exit(-1) 107 | 108 | # find library names (Release Mode) 109 | opencvlibpath = os.path.normpath(args.opencvlibpath) 110 | librarynames = get_libraries_name(args.opencvlibpath, re.compile(r'(lib)?(opencv_.*[0-9]{3}(.dll)).(lib|a)'), 2) 111 | if not librarynames: 112 | sys.stderr.write ("Invalid LIB path: {0}\n".format(args.opencvlibpath)) 113 | sys.exit(-2) 114 | 115 | # find library names (Debug Mode) 116 | opencvlibpathd = os.path.normpath(args.opencvlibpathd) if args.opencvlibpathd else opencvlibpath 117 | librarynamesd = get_libraries_name(opencvlibpathd, re.compile(r'(lib)?(opencv_.*[0-9]{3}d(.dll)).(lib|a)'), 2) 118 | if not librarynamesd: 119 | sys.stderr.write ("Invalid LIB path: {0}\n".format(opencvlibpathd)) 120 | sys.exit(-3) 121 | 122 | with open('opencv.prf', 'w') as f: 123 | f.write("""################################################################################ 124 | # 125 | # Automatically generated by {0} 126 | # At {1} 127 | # 128 | ################################################################################ 129 | 130 | """.format( 131 | sys.argv[0], 132 | datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S %Z') 133 | )) 134 | 135 | f.write("INCLUDEPATH += {0}\n".format(get_fixed_path(opencvincpath))) 136 | if not args.opencvlibpathd: 137 | # Both debug and release library in the same directory 138 | f.write("LIBS += -L{0}\n".format(get_fixed_path(opencvlibpath))) 139 | 140 | f.write("CONFIG(debug, debug|release) {\n") 141 | if args.opencvlibpathd: 142 | f.write(" LIBS += -L{0}\n".format(get_fixed_path(opencvlibpathd))) 143 | for name in librarynamesd: 144 | f.write(" LIBS += -l{0}\n".format(name)) 145 | f.write("} else {\n") 146 | if args.opencvlibpathd: 147 | f.write(" LIBS += -L{0}\n".format(get_fixed_path(opencvlibpath))) 148 | for name in librarynames: 149 | f.write(" LIBS += -l{0}\n".format(name)) 150 | f.write("}\n") 151 | 152 | print ("OK, opencv.prf has been generated.") 153 | 154 | # find qmake 155 | installok = False 156 | qmakedir = get_qmake_dir(args.qmakepath) if args.qmakepath else None 157 | if qmakedir: 158 | featurepath = get_feature_dir(qmakedir) 159 | shutil.copy2('opencv.prf', featurepath) 160 | installok = True 161 | print ("OK, opencv.prf has been copied to {0}".format(featurepath)) 162 | else: 163 | qmakedir = get_qmake_dir2() 164 | if qmakedir: 165 | select = get_input("qmake found in {0}, do you want to use this?[y/N]".format(qmakedir)) 166 | if select.lower().startswith('y'): 167 | featurepath = get_feature_dir(qmakedir) 168 | shutil.copy2('opencv.prf', featurepath) 169 | installok = True 170 | print ("OK, opencv.prf has been copied to {0}".format(featurepath)) 171 | 172 | if not installok: 173 | print ("You should copy opencv.prf to the %QTDIR%/mkspecs/features/ folder.") 174 | -------------------------------------------------------------------------------- /tests/testcvmatandimage/testcvmatandimage.pro: -------------------------------------------------------------------------------- 1 | include(../../opencv.pri) 2 | 3 | QT += testlib 4 | 5 | TARGET = tst_cvmatandimagetest 6 | 7 | CONFIG += console 8 | CONFIG -= app_bundle 9 | 10 | TEMPLATE = app 11 | 12 | SOURCES += \ 13 | tst_cvmatandimagetest.cpp 14 | DEFINES += SRCDIR=\\\"$$PWD/\\\" 15 | -------------------------------------------------------------------------------- /tests/testcvmatandimage/tst_cvmatandimagetest.cpp: -------------------------------------------------------------------------------- 1 | #include "cvmatandqimage.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | using namespace QtOcv; 15 | 16 | Q_DECLARE_METATYPE(QImage::Format) 17 | Q_DECLARE_METATYPE(MatColorOrder) 18 | Q_DECLARE_METATYPE(cv::Mat) 19 | Q_DECLARE_METATYPE(cv::Vec4b) 20 | 21 | static bool lenientCompare(const QImage &actual, const QImage &expected) 22 | { 23 | if (expected.format() != actual.format()) { 24 | qWarning("Image format comparison failed: expected: %d, got %d", 25 | expected.format(),actual.format()); 26 | return false; 27 | } 28 | 29 | QImage expectedImage = expected.convertToFormat(QImage::Format_ARGB32); 30 | QImage actualImage = actual.convertToFormat(QImage::Format_ARGB32); 31 | 32 | if (expectedImage.size() != actualImage.size()) { 33 | qWarning("Image size comparison failed: expected: %dx%d, got %dx%d", 34 | expectedImage.size().width(), expectedImage.size().height(), 35 | actualImage.size().width(), actualImage.size().height()); 36 | return false; 37 | } 38 | 39 | const int size = actual.width() * actual.height(); 40 | const int threshold = 2; 41 | 42 | QRgb *a = (QRgb *)actualImage.bits(); 43 | QRgb *e = (QRgb *)expectedImage.bits(); 44 | for (int i = 0; i < size; ++i) { 45 | const QColor ca(a[i]); 46 | const QColor ce(e[i]); 47 | if (qAbs(ca.red() - ce.red()) > threshold 48 | || qAbs(ca.green() - ce.green()) > threshold 49 | || qAbs(ca.blue() - ce.blue()) > threshold 50 | || qAbs(ca.blue() - ce.blue()) > threshold) { 51 | qWarning("Color mismatch at pixel #%d: Expected: %d,%d,%d,%d got %d,%d,%d,%d", 52 | i, ce.red(), ce.green(), ce.blue(), ce.alpha(), 53 | ca.red(), ca.green(), ca.blue(), ca.alpha()); 54 | return false; 55 | } 56 | } 57 | 58 | return true; 59 | } 60 | 61 | template 62 | static bool lenientCompare(const cv::Mat &actual, const cv::Mat &expected) 63 | { 64 | if (expected.type() != actual.type()) { 65 | qWarning("cv::Mat comparison failed: expected: depth %d channels %d, got depth %d channels %d", 66 | expected.depth(), expected.channels(), 67 | actual.depth(), actual.channels()); 68 | return false; 69 | } 70 | 71 | if (expected.rows != actual.rows || expected.cols != actual.cols) { 72 | qWarning("cv::Mat comparison failed: expected: %dX%d, got %dX%d", 73 | expected.cols, expected.rows, 74 | actual.cols, actual.rows); 75 | return false; 76 | } 77 | 78 | double threshold = 2.0e-1; 79 | 80 | std::vector actualPlanes(actual.channels()); 81 | std::vector expectedPlanes(expected.channels()); 82 | 83 | cv::split(actual, actualPlanes); 84 | cv::split(expected, expectedPlanes); 85 | 86 | for (int c=0; c(i, j); 90 | T e = expectedPlanes[c].at(i, j); 91 | if (qAbs(a-e) > threshold*(qAbs(a)+qAbs(e))) { 92 | qWarning()<= 0x050500 159 | QImage image_grayscale8; 160 | #endif 161 | QImage image_rgb32; 162 | QImage image_argb32; 163 | #if QT_VERSION >= 0x040400 164 | QImage image_rgb888; 165 | #endif 166 | #if QT_VERSION >= 0x050200 167 | QImage image_rgbx8888; 168 | QImage image_rgba8888; 169 | #endif 170 | }; 171 | 172 | CvMatAndImageTest::CvMatAndImageTest() 173 | { 174 | const int width = 200; 175 | const int height = 100; 176 | 177 | mat_8UC1 = cv::Mat(height, width, CV_8UC1); 178 | mat_16UC1 = cv::Mat(height, width, CV_16UC1); 179 | mat_32FC1 = cv::Mat(height, width, CV_32FC1); 180 | 181 | mat_8UC3_rgb = cv::Mat(height, width, CV_8UC3); 182 | mat_16UC3_rgb = cv::Mat(height, width, CV_16UC3); 183 | mat_32FC3_rgb = cv::Mat(height, width, CV_32FC3); 184 | mat_8UC3_bgr = cv::Mat(height, width, CV_8UC3); 185 | mat_16UC3_bgr = cv::Mat(height, width, CV_16UC3); 186 | mat_32FC3_bgr = cv::Mat(height, width, CV_32FC3); 187 | 188 | mat_8UC4_rgba = cv::Mat(height, width, CV_8UC4); 189 | mat_16UC4_rgba = cv::Mat(height, width, CV_16UC4); 190 | mat_32FC4_rgba = cv::Mat(height, width, CV_32FC4); 191 | mat_8UC4_argb = cv::Mat(height, width, CV_8UC4); 192 | mat_16UC4_argb = cv::Mat(height, width, CV_16UC4); 193 | mat_32FC4_argb = cv::Mat(height, width, CV_32FC4); 194 | mat_8UC4_bgra = cv::Mat(height, width, CV_8UC4); 195 | mat_16UC4_bgra = cv::Mat(height, width, CV_16UC4); 196 | mat_32FC4_bgra = cv::Mat(height, width, CV_32FC4); 197 | 198 | mat_8UC4_rgbx = cv::Mat(height, width, CV_8UC4); 199 | mat_16UC4_rgbx = cv::Mat(height, width, CV_16UC4); 200 | mat_32FC4_rgbx = cv::Mat(height, width, CV_32FC4); 201 | mat_8UC4_xrgb = cv::Mat(height, width, CV_8UC4); 202 | mat_16UC4_xrgb = cv::Mat(height, width, CV_16UC4); 203 | mat_32FC4_xrgb = cv::Mat(height, width, CV_32FC4); 204 | mat_8UC4_bgrx = cv::Mat(height, width, CV_8UC4); 205 | mat_16UC4_bgrx = cv::Mat(height, width, CV_16UC4); 206 | mat_32FC4_bgrx = cv::Mat(height, width, CV_32FC4); 207 | 208 | image_indexed8 = QImage(width, height, QImage::Format_Indexed8); 209 | QVector colorTable; 210 | for (int i=0; i<256; ++i) 211 | colorTable.append(qRgb(i, i, i)); 212 | image_indexed8.setColorTable(colorTable); 213 | #if QT_VERSION >= 0x050500 214 | image_grayscale8 = QImage(width, height, QImage::Format_Grayscale8); 215 | #endif 216 | image_rgb32 = QImage(width, height, QImage::Format_RGB32); 217 | image_argb32 = QImage(width, height, QImage::Format_ARGB32); 218 | #if QT_VERSION >= 0x040400 219 | image_rgb888 = QImage(width, height, QImage::Format_RGB888); 220 | #endif 221 | #if QT_VERSION >= 0x050200 222 | image_rgbx8888 = QImage(width, height, QImage::Format_RGBX8888); 223 | image_rgba8888 = QImage(width, height, QImage::Format_RGBA8888); 224 | #endif 225 | for (int row=0; row(row, col) = r; 232 | mat_16UC1.at(row, col) = r*255; 233 | mat_32FC1.at(row, col) = r/255.0; 234 | 235 | mat_8UC3_rgb.at(row, col) = cv::Vec3b(r, g, b); 236 | mat_16UC3_rgb.at(row, col) = cv::Vec3w(r*255, g*255, b*255); 237 | mat_32FC3_rgb.at(row, col) = cv::Vec3f(r/255.0, g/255.0, b/255.0); 238 | 239 | mat_8UC3_bgr.at(row, col) = cv::Vec3b(b, g, r); 240 | mat_16UC3_bgr.at(row, col) = cv::Vec3w(b*255, g*255, r*255); 241 | mat_32FC3_bgr.at(row, col) = cv::Vec3f(b/255.0, g/255.0, r/255.0); 242 | 243 | mat_8UC4_rgba.at(row, col) = cv::Vec4b(r, g, b, a); 244 | mat_8UC4_argb.at(row, col) = cv::Vec4b(a, r, g, b); 245 | mat_8UC4_bgra.at(row, col) = cv::Vec4b(b, g, r, a); 246 | mat_8UC4_rgbx.at(row, col) = cv::Vec4b(r, g, b, 255); 247 | mat_8UC4_xrgb.at(row, col) = cv::Vec4b(255, r, g, b); 248 | mat_8UC4_bgrx.at(row, col) = cv::Vec4b(b, g, r, 255); 249 | 250 | mat_16UC4_rgba.at(row, col) = cv::Vec4w(r*255, g*255, b*255, a*255); 251 | mat_16UC4_argb.at(row, col) = cv::Vec4w(a*255, r*255, g*255, b*255); 252 | mat_16UC4_bgra.at(row, col) = cv::Vec4w(b*255, g*255, r*255, a*255); 253 | mat_16UC4_rgbx.at(row, col) = cv::Vec4w(r*255, g*255, b*255, 65535); 254 | mat_16UC4_xrgb.at(row, col) = cv::Vec4w(65535, r*255, g*255, b*255); 255 | mat_16UC4_bgrx.at(row, col) = cv::Vec4w(b*255, g*255, r*255, 65535); 256 | 257 | mat_32FC4_rgba.at(row, col) = cv::Vec4f(r/255.0, g/255.0, b/255.0, a/255.0); 258 | mat_32FC4_argb.at(row, col) = cv::Vec4f(a/255.0, r/255.0, g/255.0, b/255.0); 259 | mat_32FC4_bgra.at(row, col) = cv::Vec4f(b/255.0, g/255.0, r/255.0, a/255.0); 260 | mat_32FC4_rgbx.at(row, col) = cv::Vec4f(r/255.0, g/255.0, b/255.0, 1); 261 | mat_32FC4_xrgb.at(row, col) = cv::Vec4f(1, r/255.0, g/255.0, b/255.0); 262 | mat_32FC4_bgrx.at(row, col) = cv::Vec4f(b/255.0, g/255.0, r/255.0, 1); 263 | 264 | image_indexed8.setPixel(col, row, r); 265 | #if QT_VERSION >= 0x050500 266 | //Note, unlike indexed8, this should be rgb value. 267 | image_grayscale8.setPixel(col, row, qRgb(r,r,r)); 268 | #endif 269 | image_rgb32.setPixel(col, row, qRgb(r, g, b)); 270 | image_argb32.setPixel(col, row, qRgba(r, g, b, a)); 271 | #if QT_VERSION >= 0x040400 272 | image_rgb888.setPixel(col, row, qRgb(r, g, b)); 273 | #endif 274 | #if QT_VERSION >= 0x050200 275 | image_rgbx8888.setPixel(col, row, qRgb(r, g, b)); 276 | image_rgba8888.setPixel(col, row, qRgba(r, g, b, a)); 277 | #endif 278 | } 279 | } 280 | } 281 | 282 | CvMatAndImageTest::~CvMatAndImageTest() 283 | { 284 | } 285 | 286 | void CvMatAndImageTest::testMatChannelsOrder() 287 | { 288 | #if QT_VERSION >= 0x040400 289 | //Save a QImage as a .png file, then load with highgui's method 290 | //note that the order is (B G R) instead of (R G B) 291 | const char* fileName1 = "tst_data1.png"; 292 | image_rgb888.save(fileName1); 293 | 294 | cv::Mat mat = cv::imread(fileName1); 295 | QVERIFY(lenientCompare(mat, mat_8UC3_bgr)); 296 | #endif 297 | 298 | //generate a (B G R A) OpenCV Image, then save as a .png file 299 | const char* fileName2 = "tst_data2.png"; 300 | cv::imwrite(fileName2, mat_8UC4_bgra); 301 | 302 | QImage image(fileName2); 303 | QVERIFY(lenientCompare(image, image_argb32)); 304 | } 305 | 306 | void CvMatAndImageTest::testMat2QImage_data() 307 | { 308 | QTest::addColumn("mat"); 309 | QTest::addColumn("mcOrder"); 310 | QTest::addColumn("formatHint"); 311 | QTest::addColumn("expect"); 312 | 313 | //Test data: C1 ==> Indexed8 314 | QTest::newRow("8UC1_Invalid") << mat_8UC1 << MCO_BGR << QImage::Format_Invalid << image_indexed8; 315 | QTest::newRow("8UC1_Indexed8") << mat_8UC1 << MCO_BGR << QImage::Format_Indexed8 << image_indexed8; 316 | QTest::newRow("16UC1") << mat_16UC1 << MCO_BGR << QImage::Format_Indexed8 << image_indexed8; 317 | QTest::newRow("32FC1") << mat_32FC1 << MCO_BGR << QImage::Format_Indexed8 << image_indexed8; 318 | 319 | #if QT_VERSION >= 0x050500 320 | //Test data: C1 ==> Grayscale8 321 | QTest::newRow("8UC1_Grayscale8") << mat_8UC1 << MCO_BGR << QImage::Format_Grayscale8 << image_grayscale8; 322 | #endif 323 | 324 | #if QT_VERSION >= 0x040400 325 | //Test data: C3 ==> RGB8888 326 | QTest::newRow("8UC3(RGB)_Invalid") << mat_8UC3_rgb << MCO_RGB << QImage::Format_Invalid << image_rgb888; 327 | QTest::newRow("8UC3(RGB)_RGB888") << mat_8UC3_rgb << MCO_RGB << QImage::Format_RGB888 << image_rgb888; 328 | QTest::newRow("16UC3(RGB)_RGB888") << mat_16UC3_rgb << MCO_RGB << QImage::Format_RGB888 << image_rgb888; 329 | QTest::newRow("32FC3(RGB)_RGB888") << mat_32FC3_rgb << MCO_RGB << QImage::Format_RGB888 << image_rgb888; 330 | QTest::newRow("8UC3(BGR)_Invalid") << mat_8UC3_bgr << MCO_BGR << QImage::Format_Invalid << image_rgb888; 331 | QTest::newRow("8UC3(BGR)_RGB888") << mat_8UC3_bgr << MCO_BGR << QImage::Format_RGB888 << image_rgb888; 332 | QTest::newRow("16UC3(BGR)_RGB888") << mat_16UC3_bgr << MCO_BGR << QImage::Format_RGB888 << image_rgb888; 333 | QTest::newRow("32FC3(BGR)_RGB888") << mat_32FC3_bgr << MCO_BGR << QImage::Format_RGB888 << image_rgb888; 334 | #endif 335 | //Test data: C3 ==> RGB32 336 | QTest::newRow("8UC3(RGB)_RGB32") << mat_8UC3_rgb << MCO_RGB << QImage::Format_RGB32 << image_rgb32; 337 | QTest::newRow("16UC3(RGB)_RGB32") << mat_16UC3_rgb << MCO_RGB << QImage::Format_RGB32 << image_rgb32; 338 | QTest::newRow("32FC3(RGB)_RGB32") << mat_32FC3_rgb << MCO_RGB << QImage::Format_RGB32 << image_rgb32; 339 | QTest::newRow("8UC3(BGR)_RGB32") << mat_8UC3_bgr << MCO_BGR << QImage::Format_RGB32 << image_rgb32; 340 | QTest::newRow("16UC3(BGR)_RGB32") << mat_16UC3_bgr << MCO_BGR << QImage::Format_RGB32 << image_rgb32; 341 | QTest::newRow("32FC3(BGR)_RGB32") << mat_32FC3_bgr << MCO_BGR << QImage::Format_RGB32 << image_rgb32; 342 | 343 | //Test data: C4 ==> RGB32 344 | QTest::newRow("8UC4(BGRX)_RGB32") << mat_8UC4_bgrx << MCO_BGRA << QImage::Format_RGB32 << image_rgb32; 345 | QTest::newRow("16UC4(BGRX)_RGB32") << mat_16UC4_bgrx << MCO_BGRA << QImage::Format_RGB32 << image_rgb32; 346 | QTest::newRow("32FC4(BGRX)_RGB32") << mat_32FC4_bgrx << MCO_BGRA << QImage::Format_RGB32 << image_rgb32; 347 | 348 | QTest::newRow("8UC4(RGBX)_RGB32") << mat_8UC4_rgbx << MCO_RGBA << QImage::Format_RGB32 << image_rgb32; 349 | QTest::newRow("16UC4(RGBX)_RGB32") << mat_16UC4_rgbx << MCO_RGBA << QImage::Format_RGB32 << image_rgb32; 350 | QTest::newRow("32FC4(RGBX)_RGB32") << mat_32FC4_rgbx << MCO_RGBA << QImage::Format_RGB32 << image_rgb32; 351 | 352 | QTest::newRow("8UC4(XRGB)_RGB32") << mat_8UC4_xrgb << MCO_ARGB << QImage::Format_RGB32 << image_rgb32; 353 | QTest::newRow("16UC4(XRGB)_RGB32") << mat_16UC4_xrgb << MCO_ARGB << QImage::Format_RGB32 << image_rgb32; 354 | QTest::newRow("32FC4(XRGB)_RGB32") << mat_32FC4_xrgb << MCO_ARGB << QImage::Format_RGB32 << image_rgb32; 355 | 356 | //Test data: C4 ==> ARGB32 357 | QTest::newRow("8UC4(BGRA)_ARGB32_Invalid") << mat_8UC4_bgra << MCO_BGRA << QImage::Format_Invalid << image_argb32; 358 | QTest::newRow("8UC4(BGRA)_ARGB32") << mat_8UC4_bgra << MCO_BGRA << QImage::Format_ARGB32 << image_argb32; 359 | QTest::newRow("16UC4(BGRA)_ARGB32") << mat_16UC4_bgra << MCO_BGRA << QImage::Format_ARGB32 << image_argb32; 360 | QTest::newRow("32FC4(BGRA)_ARGB32") << mat_32FC4_bgra << MCO_BGRA << QImage::Format_ARGB32 << image_argb32; 361 | 362 | QTest::newRow("8UC4(RGBA)_ARGB32") << mat_8UC4_rgba << MCO_RGBA << QImage::Format_ARGB32 << image_argb32; 363 | QTest::newRow("16UC4(RGBA)_ARGB32") << mat_16UC4_rgba << MCO_RGBA << QImage::Format_ARGB32 << image_argb32; 364 | QTest::newRow("32FC4(RGBA)_ARGB32") << mat_32FC4_rgba << MCO_RGBA << QImage::Format_ARGB32 << image_argb32; 365 | 366 | QTest::newRow("8UC4(ARGB)_ARGB32_Invalid") << mat_8UC4_argb << MCO_ARGB << QImage::Format_Invalid << image_argb32; 367 | QTest::newRow("8UC4(ARGB)_ARGB32") << mat_8UC4_argb << MCO_ARGB << QImage::Format_ARGB32 << image_argb32; 368 | QTest::newRow("16UC4(ARGB)_ARGB32") << mat_16UC4_argb << MCO_ARGB << QImage::Format_ARGB32 << image_argb32; 369 | QTest::newRow("32FC4(ARGB)_ARGB32") << mat_32FC4_argb << MCO_ARGB << QImage::Format_ARGB32 << image_argb32; 370 | 371 | #if QT_VERSION >= 0x050200 372 | //Test data: C4 ==> RGBA8888 373 | QTest::newRow("8UC4(RGBA)_RGBA8888") << mat_8UC4_rgba << MCO_RGBA << QImage::Format_RGBA8888 << image_rgba8888; 374 | QTest::newRow("16UC4(RGBA)_RGBA8888") << mat_16UC4_rgba << MCO_RGBA << QImage::Format_RGBA8888 << image_rgba8888; 375 | QTest::newRow("32FC4(RGBA)_RGBA8888") << mat_32FC4_rgba << MCO_RGBA << QImage::Format_RGBA8888 << image_rgba8888; 376 | #endif 377 | } 378 | 379 | void CvMatAndImageTest::testMat2QImage() 380 | { 381 | QFETCH(cv::Mat, mat); 382 | QFETCH(MatColorOrder, mcOrder); 383 | QFETCH(QImage::Format, formatHint); 384 | QFETCH(QImage, expect); 385 | 386 | QImage convertedImage = mat2Image(mat, mcOrder, formatHint); 387 | QVERIFY(lenientCompare(convertedImage, expect)); 388 | } 389 | 390 | 391 | void CvMatAndImageTest::testMat2QImageShared_data() 392 | { 393 | QTest::addColumn("mat"); 394 | QTest::addColumn("formatHint"); 395 | QTest::addColumn("expect"); 396 | 397 | //Test data: C1 ==> Indexed8 398 | QTest::newRow("8UC1_Invalid") << mat_8UC1 << QImage::Format_Invalid << image_indexed8; 399 | QTest::newRow("8UC1_Indexed8") << mat_8UC1 << QImage::Format_Indexed8 << image_indexed8; 400 | 401 | #if QT_VERSION >= 0x050500 402 | //Test data: C1 ==> Grayscale8 403 | QTest::newRow("8UC1_Grayscale8") << mat_8UC1 << QImage::Format_Grayscale8 << image_grayscale8; 404 | #endif 405 | 406 | #if QT_VERSION >= 0x040400 407 | //Test data: C3 ==> RGB8888 408 | QTest::newRow("8UC3_Invalid") << mat_8UC3_rgb << QImage::Format_Invalid << image_rgb888; 409 | #endif 410 | 411 | //Test data: C4 ==> ARGB32 412 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 413 | QTest::newRow("8UC4_ARGB32_Invalid") << mat_8UC4_bgra << QImage::Format_Invalid << image_argb32; 414 | QTest::newRow("8UC4_ARGB32") << mat_8UC4_bgra << QImage::Format_ARGB32 << image_argb32; 415 | #else 416 | QTest::newRow("8UC4_ARGB32_Invalid") << mat_8UC4_argb << QImage::Format_Invalid << image_argb32; 417 | QTest::newRow("8UC4_ARGB32") << mat_8UC4_argb << QImage::Format_ARGB32 << image_argb32; 418 | #endif 419 | 420 | #if QT_VERSION >= 0x050200 421 | //Test data: C4 ==> RGBA8888 422 | QTest::newRow("8UC4_RGBA8888") << mat_8UC4_rgba << QImage::Format_RGBA8888 << image_rgba8888; 423 | #endif 424 | } 425 | 426 | void CvMatAndImageTest::testMat2QImageShared() 427 | { 428 | QFETCH(cv::Mat, mat); 429 | QFETCH(QImage::Format, formatHint); 430 | QFETCH(QImage, expect); 431 | 432 | QImage convertedImage = mat2Image_shared(mat, formatHint); 433 | QVERIFY(lenientCompare(convertedImage, expect)); 434 | } 435 | 436 | void CvMatAndImageTest::testQImage2Mat_data() 437 | { 438 | QTest::addColumn("image"); 439 | QTest::addColumn("order"); 440 | QTest::addColumn("matType"); 441 | QTest::addColumn("expect"); 442 | 443 | //Test data: Indexed8 ==> C1 444 | QTest::newRow("Indexed8_8UC1") << image_indexed8 << MCO_BGR << CV_8UC1 << mat_8UC1; 445 | QTest::newRow("Indexed8_16UC1") << image_indexed8 << MCO_BGR << CV_16UC1 << mat_16UC1; 446 | QTest::newRow("Indexed8_32FC1") << image_indexed8 << MCO_BGR << CV_32FC1 << mat_32FC1; 447 | 448 | #if QT_VERSION >= 0x050500 449 | //Test data: Grayscale8 ==> C1 450 | QTest::newRow("Grayscale8_8UC1") << image_grayscale8 << MCO_BGR << CV_8UC1 << mat_8UC1; 451 | #endif 452 | 453 | #if QT_VERSION >= 0x040400 454 | //Test data: RGB888 ==> C3 455 | QTest::newRow("RGB888_8UC3(RGB)") << image_rgb888 << MCO_RGB << CV_8UC3 << mat_8UC3_rgb; 456 | QTest::newRow("RGB888_16UC3(RGB)") << image_rgb888 << MCO_RGB << CV_16UC3 << mat_16UC3_rgb; 457 | QTest::newRow("RGB888_32FC3(RGB)") << image_rgb888 << MCO_RGB << CV_32FC3 << mat_32FC3_rgb; 458 | QTest::newRow("RGB888_8UC3(BGR)") << image_rgb888 << MCO_BGR << CV_8UC3 << mat_8UC3_bgr; 459 | QTest::newRow("RGB888_16UC3(BGR)") << image_rgb888 << MCO_BGR << CV_16UC3 << mat_16UC3_bgr; 460 | QTest::newRow("RGB888_32FC3(BGR)") << image_rgb888 << MCO_BGR << CV_32FC3 << mat_32FC3_bgr; 461 | 462 | //Test data: RGB888 ==> C4 463 | QTest::newRow("RGB888_8UC4(RGBX)") << image_rgb888 << MCO_RGBA << CV_8UC4 << mat_8UC4_rgbx; 464 | QTest::newRow("RGB888_16UC4(RGBX)") << image_rgb888 << MCO_RGBA << CV_16UC4 << mat_16UC4_rgbx; 465 | QTest::newRow("RGB888_32FC4(RGBX)") << image_rgb888 << MCO_RGBA << CV_32FC4 << mat_32FC4_rgbx; 466 | #endif 467 | 468 | //Test data: ARGB32 ==> C4 469 | QTest::newRow("ARGB32_8UC4(BGRA)") << image_argb32 << MCO_BGRA << CV_8UC4 << mat_8UC4_bgra; 470 | QTest::newRow("ARGB32_16UC4(BGRA)") << image_argb32 << MCO_BGRA << CV_16UC4 << mat_16UC4_bgra; 471 | QTest::newRow("ARGB32_32FC4(BGRA)") << image_argb32 << MCO_BGRA << CV_32FC4 << mat_32FC4_bgra; 472 | QTest::newRow("ARGB32_8UC4(RGBA)") << image_argb32 << MCO_RGBA << CV_8UC4 << mat_8UC4_rgba; 473 | QTest::newRow("ARGB32_16UC4(RGBA)") << image_argb32 << MCO_RGBA << CV_16UC4 << mat_16UC4_rgba; 474 | QTest::newRow("ARGB32_32FC4(RGBA)") << image_argb32 << MCO_RGBA << CV_32FC4 << mat_32FC4_rgba; 475 | QTest::newRow("ARGB32_8UC4(ARGB)") << image_argb32 << MCO_ARGB << CV_8UC4 << mat_8UC4_argb; 476 | QTest::newRow("ARGB32_16UC4(ARGB)") << image_argb32 << MCO_ARGB << CV_16UC4 << mat_16UC4_argb; 477 | QTest::newRow("ARGB32_32FC4(ARGB)") << image_argb32 << MCO_ARGB << CV_32FC4 << mat_32FC4_argb; 478 | 479 | #if QT_VERSION >= 0x050200 480 | //Test data: RGBA8888 ==> C4 481 | QTest::newRow("RGBA8888_8UC4(RGBA)") << image_rgba8888 << MCO_RGBA << CV_8UC4 << mat_8UC4_rgba; 482 | QTest::newRow("RGBA8888_16UC4(RGBA)") << image_rgba8888 << MCO_RGBA << CV_16UC4 << mat_16UC4_rgba; 483 | QTest::newRow("RGBA8888_32FC4(RGBA)") << image_rgba8888 << MCO_RGBA << CV_32FC4 << mat_32FC4_rgba; 484 | 485 | QTest::newRow("RGBA8888_8UC4(BGRA)") << image_rgba8888 << MCO_BGRA << CV_8UC4 << mat_8UC4_bgra; 486 | QTest::newRow("RGBA8888_16UC4(BGRA)") << image_rgba8888 << MCO_BGRA << CV_16UC4 << mat_16UC4_bgra; 487 | QTest::newRow("RGBA8888_32FC4(BGRA)") << image_rgba8888 << MCO_BGRA << CV_32FC4 << mat_32FC4_bgra; 488 | #endif 489 | } 490 | 491 | void CvMatAndImageTest::testQImage2Mat() 492 | { 493 | QFETCH(QImage, image); 494 | QFETCH(MatColorOrder, order); 495 | QFETCH(int, matType); 496 | QFETCH(cv::Mat, expect); 497 | 498 | cv::Mat mat = image2Mat(image, matType, order); 499 | if (mat.depth() == CV_8U) 500 | QVERIFY(lenientCompare(mat, expect)); 501 | else if (mat.depth() == CV_16U) 502 | QVERIFY(lenientCompare(mat, expect)); 503 | else if (mat.depth() == CV_32F) 504 | QVERIFY(lenientCompare(mat, expect)); 505 | else 506 | QVERIFY(false); 507 | } 508 | 509 | void CvMatAndImageTest::testQImage2MatShared_data() 510 | { 511 | QTest::addColumn("image"); 512 | QTest::addColumn("expect"); 513 | 514 | //Test data: Indexed8 ==> C1 515 | QTest::newRow("Indexed8_8UC1") << image_indexed8 << mat_8UC1; 516 | 517 | #if QT_VERSION >= 0x050500 518 | //Test data: Grayscale8 ==> C1 519 | QTest::newRow("Grayscale8_8UC1") << image_grayscale8 << mat_8UC1; 520 | #endif 521 | 522 | #if QT_VERSION >= 0x040400 523 | //Test data: RGB8888 ==> C3 524 | QTest::newRow("RGB8888_8UC3") << image_rgb888 << mat_8UC3_rgb; 525 | #endif 526 | 527 | //Test data: ARGB32 ==> C4 528 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 529 | QTest::newRow("ARGB32_8UC4") << image_argb32 << mat_8UC4_bgra; 530 | #else 531 | QTest::newRow("ARGB32_8UC4") << image_argb32 << mat_8UC4_argb; 532 | #endif 533 | 534 | #if QT_VERSION >= 0x050200 535 | //Test data: RGBA8888 ==> C4 536 | QTest::newRow("RGBA8888_8UC4") << image_rgba8888 << mat_8UC4_rgba; 537 | #endif 538 | } 539 | 540 | void CvMatAndImageTest::testQImage2MatShared() 541 | { 542 | QFETCH(QImage, image); 543 | QFETCH(cv::Mat, expect); 544 | 545 | cv::Mat convertedMat = image2Mat_shared(image); 546 | QVERIFY(lenientCompare(convertedMat, expect)); 547 | } 548 | 549 | QTEST_MAIN(CvMatAndImageTest) 550 | 551 | #include "tst_cvmatandimagetest.moc" 552 | -------------------------------------------------------------------------------- /tests/tests.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | testcvmatandimage 5 | --------------------------------------------------------------------------------