├── CameraConnectDialog.cpp ├── CameraConnectDialog.h ├── CameraConnectDialog.ui ├── CaptureThread.cpp ├── CaptureThread.h ├── Controller.cpp ├── Controller.h ├── DefaultValues.h ├── FaceDetect.cpp ├── FaceDetect.h ├── FrameLabel.cpp ├── FrameLabel.h ├── ImageBuffer.cpp ├── ImageBuffer.h ├── MainWindow.cpp ├── MainWindow.h ├── MainWindow.ui ├── ProcessingSettingsDialog.cpp ├── ProcessingSettingsDialog.h ├── ProcessingSettingsDialog.ui ├── ProcessingThread.cpp ├── ProcessingThread.h ├── ShowIplImage.cpp ├── ShowIplImage.h ├── Structures.h ├── haarcascades ├── haarcascade_eye.xml ├── haarcascade_eye_tree_eyeglasses.xml ├── haarcascade_frontalface_alt.xml ├── haarcascade_frontalface_alt2.xml ├── haarcascade_frontalface_alt_tree.xml ├── haarcascade_frontalface_default.xml ├── haarcascade_fullbody.xml ├── haarcascade_lefteye_2splits.xml ├── haarcascade_lowerbody.xml ├── haarcascade_mcs_eyepair_big.xml ├── haarcascade_mcs_eyepair_small.xml ├── haarcascade_mcs_lefteye.xml ├── haarcascade_mcs_mouth.xml ├── haarcascade_mcs_nose.xml ├── haarcascade_mcs_righteye.xml ├── haarcascade_mcs_upperbody.xml ├── haarcascade_profileface.xml ├── haarcascade_righteye_2splits.xml └── haarcascade_upperbody.xml ├── main.cpp ├── qt-opencv-multithreaded.pro └── qt-opencv-multithreaded.pro.user /CameraConnectDialog.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* CameraConnectDialog.cpp */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #include "CameraConnectDialog.h" 34 | 35 | // Qt header files 36 | #include 37 | // Header file containing default values 38 | #include "DefaultValues.h" 39 | 40 | CameraConnectDialog::CameraConnectDialog(QWidget *parent) : QDialog(parent) 41 | { 42 | // Setup dialog 43 | setupUi(this); 44 | // deviceNumberEdit (device number) input string validation 45 | QRegExp rx1("[0-9]\\d{0,2}"); // Integers 0 to 999 46 | QRegExpValidator *validator1 = new QRegExpValidator(rx1, 0); 47 | deviceNumberEdit->setValidator(validator1); 48 | // imageBufferSizeEdit (image buffer size) input string validation 49 | QRegExp rx2("[0-9]\\d{0,2}"); // Integers 0 to 999 50 | QRegExpValidator *validator2 = new QRegExpValidator(rx2, 0); 51 | imageBufferSizeEdit->setValidator(validator2); 52 | // Set imageBufferSizeEdit to default value 53 | imageBufferSizeEdit->setText(QString::number(DEFAULT_IMAGE_BUFFER_SIZE)); 54 | // Initially set deviceNumber and imageBufferSize to defaults 55 | deviceNumber=-1; 56 | imageBufferSize=DEFAULT_IMAGE_BUFFER_SIZE; 57 | } // CameraConnectDialog constructor 58 | 59 | void CameraConnectDialog::setDeviceNumber() 60 | { 61 | // "Any available camera" 62 | if(anyCameraButton->isChecked()) 63 | deviceNumber=-1; 64 | // "Device number" 65 | else 66 | { 67 | // Set device number to default (any available camera) if field is blank 68 | if(deviceNumberEdit->text().isEmpty()) 69 | { 70 | QMessageBox::warning(this->parentWidget(), "WARNING:","Device Number field blank.\nAutomatically set to 'any available camera'."); 71 | deviceNumber=-1; 72 | } 73 | // User-specified camera 74 | else 75 | deviceNumber=deviceNumberEdit->text().toInt(); 76 | } 77 | } // setDeviceNumber() 78 | 79 | void CameraConnectDialog::setImageBufferSize() 80 | { 81 | // Set image buffer size to default if field is blank 82 | if(imageBufferSizeEdit->text().isEmpty()) 83 | { 84 | QMessageBox::warning(this->parentWidget(), "WARNING:","Image Buffer Size field blank.\nAutomatically set to default value."); 85 | imageBufferSize=DEFAULT_IMAGE_BUFFER_SIZE; 86 | } 87 | // Set image buffer size to default if field is zero 88 | else if(imageBufferSizeEdit->text().toInt()==0) 89 | { 90 | QMessageBox::warning(this->parentWidget(), "WARNING:","Image Buffer Size cannot be zero.\nAutomatically set to default value."); 91 | imageBufferSize=DEFAULT_IMAGE_BUFFER_SIZE;; 92 | } 93 | // Use image buffer size specified by user 94 | else 95 | imageBufferSize=imageBufferSizeEdit->text().toInt(); 96 | } // setImageBufferSize() 97 | 98 | int CameraConnectDialog::getDeviceNumber() 99 | { 100 | return deviceNumber; 101 | } // getDeviceNumber() 102 | 103 | int CameraConnectDialog::getImageBufferSize() 104 | { 105 | return imageBufferSize; 106 | } // getImageBufferSize() 107 | -------------------------------------------------------------------------------- /CameraConnectDialog.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* CameraConnectDialog.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef CAMERACONNECTDIALOG_H 34 | #define CAMERACONNECTDIALOG_H 35 | 36 | #include "ui_CameraConnectDialog.h" 37 | 38 | class CameraConnectDialog : public QDialog, private Ui::CameraConnectDialog 39 | { 40 | Q_OBJECT 41 | 42 | public: 43 | CameraConnectDialog(QWidget *parent = 0); 44 | void setDeviceNumber(); 45 | void setImageBufferSize(); 46 | int getDeviceNumber(); 47 | int getImageBufferSize(); 48 | private: 49 | int deviceNumber; 50 | int imageBufferSize; 51 | }; 52 | 53 | #endif // CAMERACONNECTDIALOG_H 54 | -------------------------------------------------------------------------------- /CameraConnectDialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CameraConnectDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 410 10 | 170 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | 21 | 410 22 | 170 23 | 24 | 25 | 26 | Connect to Camera 27 | 28 | 29 | 30 | 31 | 10 32 | 10 33 | 391 34 | 150 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 75 43 | true 44 | 45 | 46 | 47 | Select Camera: 48 | 49 | 50 | 51 | 52 | 53 | 54 | Connect to any available camera 55 | 56 | 57 | true 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | Device Number: 67 | 68 | 69 | 70 | 71 | 72 | 73 | false 74 | 75 | 76 | 77 | 0 78 | 0 79 | 80 | 81 | 82 | 83 | 50 84 | 0 85 | 86 | 87 | 88 | 89 | 50 90 | 16777215 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | Qt::Horizontal 99 | 100 | 101 | 102 | 40 103 | 20 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 75 117 | true 118 | 119 | 120 | 121 | Image Buffer Size (no. of images): 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 0 130 | 0 131 | 132 | 133 | 134 | 135 | 50 136 | 0 137 | 138 | 139 | 140 | 141 | 50 142 | 16777215 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | Qt::Horizontal 151 | 152 | 153 | 154 | 40 155 | 20 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | Qt::Horizontal 166 | 167 | 168 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | anyCameraButton 177 | deviceNumberButton 178 | deviceNumberEdit 179 | imageBufferSizeEdit 180 | okCancelBox 181 | 182 | 183 | 184 | 185 | okCancelBox 186 | accepted() 187 | CameraConnectDialog 188 | accept() 189 | 190 | 191 | 430 192 | 136 193 | 194 | 195 | 157 196 | 274 197 | 198 | 199 | 200 | 201 | okCancelBox 202 | rejected() 203 | CameraConnectDialog 204 | reject() 205 | 206 | 207 | 430 208 | 136 209 | 210 | 211 | 286 212 | 274 213 | 214 | 215 | 216 | 217 | anyCameraButton 218 | clicked(bool) 219 | deviceNumberEdit 220 | setDisabled(bool) 221 | 222 | 223 | 205 224 | 38 225 | 226 | 227 | 217 228 | 67 229 | 230 | 231 | 232 | 233 | deviceNumberButton 234 | clicked(bool) 235 | deviceNumberEdit 236 | setEnabled(bool) 237 | 238 | 239 | 130 240 | 93 241 | 242 | 243 | 281 244 | 93 245 | 246 | 247 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /CaptureThread.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* CaptureThread.cpp */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #include "CaptureThread.h" 34 | #include "ImageBuffer.h" 35 | 36 | // Qt header files 37 | #include 38 | 39 | CaptureThread::CaptureThread(ImageBuffer *buffer, int deviceNumber):QThread(), imageBuffer(buffer) 40 | { 41 | // Open camera 42 | capture=cvCaptureFromCAM(deviceNumber); 43 | // Initialize variables 44 | stopped=false; 45 | sampleNo=0; 46 | fpsSum=0; 47 | avgFPS=0; 48 | fps.clear(); 49 | } // CaptureThread constructor 50 | 51 | void CaptureThread::run() 52 | { 53 | while(1) 54 | { 55 | ///////////////////////////////// 56 | // Stop thread if stopped=TRUE // 57 | ///////////////////////////////// 58 | stoppedMutex.lock(); 59 | if (stopped) 60 | { 61 | stopped=false; 62 | stoppedMutex.unlock(); 63 | break; 64 | } 65 | stoppedMutex.unlock(); 66 | ///////////////////////////////// 67 | ///////////////////////////////// 68 | // Save capture time 69 | captureTime=t.elapsed(); 70 | // Start timer (used to calculate capture rate) 71 | t.start(); 72 | // Capture and add frame to buffer 73 | imageBuffer->addFrame(cvQueryFrame(capture)); 74 | // Update statistics 75 | updateFPS(captureTime); 76 | } 77 | qDebug() << "Stopping capture thread..."; 78 | } // run() 79 | 80 | void CaptureThread::disconnectCamera() 81 | { 82 | // Disconnect camera if connected 83 | if(capture!=NULL) 84 | { 85 | cvReleaseCapture(&capture); 86 | if(capture==NULL) 87 | qDebug() << "Camera successfully disconnected."; 88 | else 89 | qDebug() << "ERROR: Camera could not be disconnected."; 90 | } 91 | } // disconnectCamera() 92 | 93 | void CaptureThread::updateFPS(int timeElapsed) 94 | { 95 | // Add instantaneous FPS value to queue 96 | if(timeElapsed>0) 97 | { 98 | fps.enqueue((int)1000/timeElapsed); 99 | // Increment sample number 100 | sampleNo++; 101 | } 102 | // Maximum size of queue is 16 103 | if(fps.size() > 16) 104 | fps.dequeue(); 105 | // Update FPS value every 16 samples 106 | if((fps.size()==16)&&(sampleNo==16)) 107 | { 108 | // Empty queue and store sum 109 | while(!fps.empty()) 110 | fpsSum+=fps.dequeue(); 111 | avgFPS=fpsSum/16; // Calculate average FPS 112 | fpsSum=0; // Reset sum 113 | sampleNo=0; // Reset sample number 114 | } 115 | } // updateFPS() 116 | 117 | void CaptureThread::stopCaptureThread() 118 | { 119 | stoppedMutex.lock(); 120 | stopped=true; 121 | stoppedMutex.unlock(); 122 | } // stopCaptureThread() 123 | 124 | int CaptureThread::getAvgFPS() 125 | { 126 | return avgFPS; 127 | } // getAvgFPS() 128 | 129 | bool CaptureThread::isCameraConnected() 130 | { 131 | if(capture!=NULL) 132 | return true; 133 | else 134 | return false; 135 | } // isCameraConnected() 136 | 137 | int CaptureThread::getInputSourceWidth() 138 | { 139 | return cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH); 140 | } // getInputSourceWidth() 141 | 142 | int CaptureThread::getInputSourceHeight() 143 | { 144 | return cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT); 145 | } // getInputSourceHeight() 146 | -------------------------------------------------------------------------------- /CaptureThread.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* CaptureThread.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef CAPTURETHREAD_H 34 | #define CAPTURETHREAD_H 35 | 36 | // Qt header files 37 | #include 38 | #include 39 | // OpenCV header files 40 | #include "opencv/highgui.h" 41 | 42 | class ImageBuffer; 43 | 44 | class CaptureThread : public QThread 45 | { 46 | Q_OBJECT 47 | 48 | public: 49 | CaptureThread(ImageBuffer *buffer, int deviceNumber); 50 | void disconnectCamera(); 51 | void stopCaptureThread(); 52 | int getAvgFPS(); 53 | bool isCameraConnected(); 54 | int getInputSourceWidth(); 55 | int getInputSourceHeight(); 56 | private: 57 | void updateFPS(int); 58 | ImageBuffer *imageBuffer; 59 | CvCapture *capture; 60 | QTime t; 61 | QMutex stoppedMutex; 62 | int captureTime; 63 | int avgFPS; 64 | QQueue fps; 65 | int sampleNo; 66 | int fpsSum; 67 | volatile bool stopped; 68 | protected: 69 | void run(); 70 | }; 71 | 72 | #endif // CAPTURETHREAD_H 73 | -------------------------------------------------------------------------------- /Controller.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* Controller.cpp */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #include "Controller.h" 34 | #include "ImageBuffer.h" 35 | 36 | // Qt header files 37 | #include 38 | 39 | Controller::Controller(int deviceNumber, int imageBufferSize) : imageBufferSize(imageBufferSize) 40 | { 41 | // Create image buffer with user-defined size 42 | imageBuffer = new ImageBuffer(imageBufferSize); 43 | // Create capture thread with user-defined device number 44 | captureThread = new CaptureThread(imageBuffer, deviceNumber); 45 | // Create processing thread 46 | processingThread = new ProcessingThread(imageBuffer,getInputSourceWidth(),getInputSourceHeight()); 47 | } // Controller constructor 48 | 49 | Controller::~Controller() 50 | { 51 | // Delete image buffer 52 | delete imageBuffer; 53 | } // Controller destructor 54 | 55 | void Controller::disconnectCamera() 56 | { 57 | captureThread->disconnectCamera(); 58 | } // disconnectCamera() 59 | 60 | void Controller::stopCaptureThread() 61 | { 62 | qDebug() << "About to stop capture thread..."; 63 | captureThread->stopCaptureThread(); 64 | // Take one frame off a FULL queue to allow the capture thread to finish 65 | if(imageBuffer->getSizeOfImageBuffer()==imageBufferSize) 66 | { 67 | IplImage* temp; 68 | temp=imageBuffer->getFrame(); 69 | cvReleaseImage(&temp); 70 | } 71 | captureThread->wait(); 72 | qDebug() << "Capture thread successfully stopped."; 73 | } // stopCaptureThread() 74 | 75 | void Controller::stopProcessingThread() 76 | { 77 | qDebug() << "About to stop processing thread..."; 78 | processingThread->stopProcessingThread(); 79 | processingThread->wait(); 80 | qDebug() << "Processing thread successfully stopped."; 81 | } // stopProcessingThread() 82 | 83 | void Controller::deleteCaptureThread() 84 | { 85 | // Delete thread 86 | delete captureThread; 87 | } // deleteCaptureThread() 88 | 89 | void Controller::deleteProcessingThread() 90 | { 91 | // Delete thread 92 | delete processingThread; 93 | } // deleteProcessingThread() 94 | 95 | void Controller::clearImageBuffer() 96 | { 97 | imageBuffer->clearBuffer(); 98 | } // clearImageBuffer() 99 | 100 | int Controller::getInputSourceWidth() 101 | { 102 | return captureThread->getInputSourceWidth(); 103 | } // getInputSourceWidth() 104 | 105 | int Controller::getInputSourceHeight() 106 | { 107 | return captureThread->getInputSourceHeight(); 108 | } // getInputSourceHeight() 109 | -------------------------------------------------------------------------------- /Controller.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* Controller.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef CONTROLLER_H 34 | #define CONTROLLER_H 35 | 36 | #include "CaptureThread.h" 37 | #include "ProcessingThread.h" 38 | 39 | // Qt header files 40 | #include 41 | // OpenCV header files 42 | #include 43 | 44 | class ImageBuffer; 45 | 46 | class Controller : public QObject 47 | { 48 | Q_OBJECT 49 | 50 | public: 51 | Controller(int deviceNumber, int imageBufferSize); 52 | ~Controller(); 53 | ImageBuffer *imageBuffer; 54 | ProcessingThread *processingThread; 55 | CaptureThread *captureThread; 56 | void disconnectCamera(); 57 | void stopCaptureThread(); 58 | void stopProcessingThread(); 59 | void deleteCaptureThread(); 60 | void deleteProcessingThread(); 61 | void clearImageBuffer(); 62 | int getInputSourceWidth(); 63 | int getInputSourceHeight(); 64 | private: 65 | int imageBufferSize; 66 | }; 67 | 68 | #endif // CONTROLLER_H 69 | -------------------------------------------------------------------------------- /DefaultValues.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* DefaultValues.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef DEFAULTVALUES_H 34 | #define DEFAULTVALUES_H 35 | 36 | // OpenCV header files 37 | #include 38 | #include 39 | 40 | // Image buffer size 41 | #define DEFAULT_IMAGE_BUFFER_SIZE 1 42 | // SMOOTH 43 | #define DEFAULT_SMOOTH_TYPE CV_GAUSSIAN // Options: [CV_BLUR_NO_SCALE,CV_BLUR,CV_GAUSSIAN,CV_MEDIAN] 44 | #define DEFAULT_SMOOTH_PARAM_1 3 45 | #define DEFAULT_SMOOTH_PARAM_2 0 46 | #define DEFAULT_SMOOTH_PARAM_3 0 47 | #define DEFAULT_SMOOTH_PARAM_4 0 48 | // DILATE 49 | #define DEFAULT_DILATE_ITERATIONS 1 50 | // ERODE 51 | #define DEFAULT_ERODE_ITERATIONS 1 52 | // FLIP 53 | #define DEFAULT_FLIP_MODE 0 // Options: [x-axis=0,y-axis=1,both axes=-1] 54 | // CANNY 55 | #define DEFAULT_CANNY_THRESHOLD_1 10 56 | #define DEFAULT_CANNY_THRESHOLD_2 100 57 | #define DEFAULT_CANNY_APERTURE_SIZE 3 58 | // FACEDETECT 59 | #define DEFAULT_FACEDETECT_SCALE 1.0 60 | #define DEFAULT_FACEDETECT_CASCADE_FILENAME "haarcascades/haarcascade_frontalface_alt.xml" 61 | #define DEFAULT_FACEDETECT_NESTED_CASCADE_FILENAME "haarcascades/haarcascade_eye_tree_eyeglasses.xml" 62 | 63 | #endif // DEFAULTVALUES_H 64 | -------------------------------------------------------------------------------- /FaceDetect.cpp: -------------------------------------------------------------------------------- 1 | #include "FaceDetect.h" 2 | 3 | using namespace std; 4 | using namespace cv; 5 | 6 | void faceDetect( IplImage *iplImage, 7 | CascadeClassifier& cascade, CascadeClassifier& nestedCascade, 8 | double scale) 9 | { 10 | Mat img = cvarrToMat(iplImage); 11 | int i = 0; 12 | double t = 0; 13 | vector faces; 14 | const static Scalar colors[] = { CV_RGB(0,0,255), 15 | CV_RGB(0,128,255), 16 | CV_RGB(0,255,255), 17 | CV_RGB(0,255,0), 18 | CV_RGB(255,128,0), 19 | CV_RGB(255,255,0), 20 | CV_RGB(255,0,0), 21 | CV_RGB(255,0,255)} ; 22 | Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 ); 23 | 24 | cvtColor( img, gray, CV_BGR2GRAY ); 25 | resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR ); 26 | equalizeHist( smallImg, smallImg ); 27 | 28 | t = (double)cvGetTickCount(); 29 | cascade.detectMultiScale( smallImg, faces, 30 | 1.1, 2, 0 31 | //|CV_HAAR_FIND_BIGGEST_OBJECT 32 | //|CV_HAAR_DO_ROUGH_SEARCH 33 | |CV_HAAR_SCALE_IMAGE 34 | , 35 | Size(30, 30) ); 36 | t = (double)cvGetTickCount() - t; 37 | //printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) ); 38 | for( vector::const_iterator r = faces.begin(); r != faces.end(); r++, i++ ) 39 | { 40 | Mat smallImgROI; 41 | vector nestedObjects; 42 | Point center; 43 | Scalar color = colors[i%8]; 44 | int radius; 45 | center.x = cvRound((r->x + r->width*0.5)*scale); 46 | center.y = cvRound((r->y + r->height*0.5)*scale); 47 | radius = cvRound((r->width + r->height)*0.25*scale); 48 | circle( img, center, radius, color, 3, 8, 0 ); 49 | if( nestedCascade.empty() ) 50 | continue; 51 | smallImgROI = smallImg(*r); 52 | nestedCascade.detectMultiScale( smallImgROI, nestedObjects, 53 | 1.1, 2, 0 54 | //|CV_HAAR_FIND_BIGGEST_OBJECT 55 | //|CV_HAAR_DO_ROUGH_SEARCH 56 | //|CV_HAAR_DO_CANNY_PRUNING 57 | |CV_HAAR_SCALE_IMAGE 58 | , 59 | Size(30, 30) ); 60 | for( vector::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++ ) 61 | { 62 | center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale); 63 | center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale); 64 | radius = cvRound((nr->width + nr->height)*0.25*scale); 65 | circle( img, center, radius, color, 3, 8, 0 ); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /FaceDetect.h: -------------------------------------------------------------------------------- 1 | #ifndef FACEDETECT_H 2 | #define FACEDETECT_H 3 | 4 | // Qt header files 5 | #include 6 | #include 7 | // OpenCV header files 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | void faceDetect( IplImage *iplImage, 15 | cv::CascadeClassifier& cascade, cv::CascadeClassifier& nestedCascade, 16 | double scale); 17 | 18 | #endif // FACEDETECT_H 19 | -------------------------------------------------------------------------------- /FrameLabel.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* FrameLabel.cpp */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #include "FrameLabel.h" 34 | 35 | FrameLabel::FrameLabel(QWidget *parent) : QLabel(parent) 36 | { 37 | // Initialize variables 38 | startPoint.setX(0); 39 | startPoint.setY(0); 40 | mouseCursorPos.setX(0); 41 | mouseCursorPos.setY(0); 42 | drawBox=false; 43 | // Initialize MouseData structure 44 | mouseData.leftButtonRelease=false; 45 | mouseData.rightButtonRelease=false; 46 | } // FrameLabel constructor 47 | 48 | void FrameLabel::mouseMoveEvent(QMouseEvent *ev) 49 | { 50 | // Save mouse cursor position 51 | setMouseCursorPos(ev->pos()); 52 | // Update box width and height if box drawing is in progress 53 | if(drawBox) 54 | { 55 | box->setWidth(getMouseCursorPos().x()-startPoint.x()); 56 | box->setHeight(getMouseCursorPos().y()-startPoint.y()); 57 | } 58 | // Inform main window of mouse move event 59 | emit onMouseMoveEvent(); 60 | } // mouseMoveEvent() 61 | 62 | void FrameLabel::setMouseCursorPos(QPoint input) 63 | { 64 | mouseCursorPos=input; 65 | } // setMouseCursorPos() 66 | 67 | QPoint FrameLabel::getMouseCursorPos() 68 | { 69 | return mouseCursorPos; 70 | } // getMouseXPos() 71 | 72 | void FrameLabel::mouseReleaseEvent(QMouseEvent *ev) 73 | { 74 | // Update cursor position 75 | setMouseCursorPos(ev->pos()); 76 | // On left mouse button release 77 | if(ev->button()==Qt::LeftButton) 78 | { 79 | // Set leftButtonRelease flag to TRUE 80 | mouseData.leftButtonRelease=true; 81 | if(drawBox) 82 | { 83 | // Stop drawing box 84 | drawBox=false; 85 | // Save box dimensions 86 | mouseData.selectionBox.setX(box->left()); 87 | mouseData.selectionBox.setY(box->top()); 88 | mouseData.selectionBox.setWidth(box->width()); 89 | mouseData.selectionBox.setHeight(box->height()); 90 | // Set leftButtonRelease flag to TRUE 91 | mouseData.leftButtonRelease=true; 92 | // Inform main window of event 93 | emit newMouseData(mouseData); 94 | } 95 | // Set leftButtonRelease flag to FALSE 96 | mouseData.leftButtonRelease=false; 97 | } 98 | // On right mouse button release 99 | else if(ev->button()==Qt::RightButton) 100 | { 101 | // If user presses (and then releases) the right mouse button while drawing box, stop drawing box 102 | if(drawBox) 103 | drawBox=false; 104 | else 105 | { 106 | // Set rightButtonRelease flag to TRUE 107 | mouseData.rightButtonRelease=true; 108 | // Inform main window of event 109 | emit newMouseData(mouseData); 110 | // Set rightButtonRelease flag to FALSE 111 | mouseData.rightButtonRelease=false; 112 | } 113 | } 114 | } // mouseReleaseEvent() 115 | 116 | void FrameLabel::mousePressEvent(QMouseEvent *ev) 117 | { 118 | // Update cursor position 119 | setMouseCursorPos(ev->pos());; 120 | if(ev->button()==Qt::LeftButton) 121 | { 122 | // Start drawing box 123 | startPoint=ev->pos(); 124 | box=new QRect(startPoint.x(),startPoint.y(),0,0); 125 | drawBox=true; 126 | } 127 | } // mousePressEvent() 128 | 129 | void FrameLabel::paintEvent(QPaintEvent *ev) 130 | { 131 | QLabel::paintEvent(ev); 132 | QPainter painter(this); 133 | // Draw box 134 | if(drawBox) 135 | { 136 | painter.setPen(Qt::blue); 137 | painter.drawRect(*box); 138 | } 139 | } // paintEvent() 140 | -------------------------------------------------------------------------------- /FrameLabel.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* FrameLabel.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef FRAMELABEL_H 34 | #define FRAMELABEL_H 35 | 36 | #include "Structures.h" 37 | 38 | // Qt header files 39 | #include 40 | 41 | class FrameLabel : public QLabel 42 | { 43 | Q_OBJECT 44 | 45 | public: 46 | FrameLabel(QWidget *parent = 0); 47 | void setMouseCursorPos(QPoint); 48 | QPoint getMouseCursorPos(); 49 | private: 50 | MouseData mouseData; 51 | QPoint startPoint; 52 | QPoint mouseCursorPos; 53 | bool drawBox; 54 | QRect *box; 55 | protected: 56 | void mouseMoveEvent(QMouseEvent *ev); 57 | void mousePressEvent(QMouseEvent *ev); 58 | void mouseReleaseEvent(QMouseEvent *ev); 59 | void paintEvent(QPaintEvent *ev); 60 | signals: 61 | void newMouseData(struct MouseData mouseData); 62 | void onMouseMoveEvent(); 63 | }; 64 | 65 | #endif // FRAMELABEL_H 66 | -------------------------------------------------------------------------------- /ImageBuffer.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* ImageBuffer.cpp */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #include "ImageBuffer.h" 34 | 35 | // Qt header files 36 | #include 37 | 38 | ImageBuffer::ImageBuffer(int bufferSize) : bufferSize(bufferSize) 39 | { 40 | // Semaphore initializations 41 | freeSlots = new QSemaphore(bufferSize); 42 | usedSlots = new QSemaphore(0); 43 | clearBuffer1 = new QSemaphore(1); 44 | clearBuffer2 = new QSemaphore(1); 45 | } // ImageBuffer constructor 46 | 47 | void ImageBuffer::addFrame(const IplImage* image) 48 | { 49 | clearBuffer1->acquire(); 50 | freeSlots->acquire(); 51 | // Copy the input IplImage 52 | IplImage* temp = cvCloneImage(image); 53 | // Add image to queue 54 | mutex.lock(); 55 | imageQueue.enqueue(temp); 56 | mutex.unlock(); 57 | clearBuffer1->release(); 58 | usedSlots->release(); 59 | } // addFrame() 60 | 61 | IplImage* ImageBuffer::getFrame() 62 | { 63 | clearBuffer2->acquire(); 64 | usedSlots->acquire(); 65 | IplImage* temp=0; 66 | // Take image from queue 67 | mutex.lock(); 68 | temp=imageQueue.dequeue(); 69 | mutex.unlock(); 70 | freeSlots->release(); 71 | clearBuffer2->release(); 72 | // Return image to caller 73 | return temp; 74 | } // getFrame() 75 | 76 | void ImageBuffer::clearBuffer() 77 | { 78 | // Check if buffer is not empty 79 | if(imageQueue.size()!=0) 80 | { 81 | // Stop adding frames to buffer 82 | clearBuffer1->acquire(); 83 | // Stop taking frames from buffer 84 | clearBuffer2->acquire(); 85 | // Release all remaining slots in queue 86 | freeSlots->release(imageQueue.size()); 87 | // Acquire all queue slots 88 | freeSlots->acquire(bufferSize); 89 | // Reset usedSlots to zero 90 | usedSlots->acquire(imageQueue.size()); 91 | // Clear buffer by dequeuing items 92 | while(imageQueue.size()!=0) 93 | { 94 | // Local temporary storage 95 | IplImage* temp; 96 | // Dequeue IplImage 97 | temp=imageQueue.dequeue(); 98 | // Release IplImage 99 | cvReleaseImage(&temp); 100 | } 101 | // Release all slots 102 | freeSlots->release(bufferSize); 103 | // Allow getFrame() to resume 104 | clearBuffer2->release(); 105 | // Allow addFrame() to resume 106 | clearBuffer1->release(); 107 | qDebug() << "Image buffer successfully cleared."; 108 | } 109 | else 110 | qDebug() << "WARNING: Could not clear image buffer: already empty."; 111 | } // clearBuffer() 112 | 113 | int ImageBuffer::getSizeOfImageBuffer() 114 | { 115 | return imageQueue.size(); 116 | } // getSizeOfImageBuffer() 117 | -------------------------------------------------------------------------------- /ImageBuffer.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* ImageBuffer.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef IMAGEBUFFER_H 34 | #define IMAGEBUFFER_H 35 | 36 | // Qt header files 37 | #include 38 | #include 39 | #include 40 | #include 41 | // OpenCV header files 42 | #include 43 | 44 | class ImageBuffer 45 | { 46 | 47 | public: 48 | ImageBuffer(int size); 49 | void addFrame(const IplImage *image); 50 | IplImage* getFrame(); 51 | void clearBuffer(); 52 | int getSizeOfImageBuffer(); 53 | private: 54 | QMutex mutex; 55 | QQueue imageQueue; 56 | QSemaphore *freeSlots; 57 | QSemaphore *usedSlots; 58 | QSemaphore *clearBuffer1; 59 | QSemaphore *clearBuffer2; 60 | int bufferSize; 61 | }; 62 | 63 | #endif // IMAGEBUFFER_H 64 | -------------------------------------------------------------------------------- /MainWindow.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* MainWindow.cpp */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #include "CameraConnectDialog.h" 34 | #include "ProcessingSettingsDialog.h" 35 | #include "Controller.h" 36 | #include "MainWindow.h" 37 | 38 | // Qt header files 39 | #include 40 | // Header file containing default values 41 | #include "DefaultValues.h" 42 | 43 | MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) 44 | { 45 | // Setup user interface 46 | setupUi(this); 47 | // Initially set controller to NULL 48 | controller=NULL; 49 | // Create processingSettingsDialog 50 | processingSettingsDialog = new ProcessingSettingsDialog(this); 51 | // Initialize ProcessingFlags structure 52 | processingFlags.grayscaleOn=false; 53 | processingFlags.smoothOn=false; 54 | processingFlags.dilateOn=false; 55 | processingFlags.erodeOn=false; 56 | processingFlags.flipOn=false; 57 | processingFlags.cannyOn=false; 58 | processingFlags.facedetectOn=false; 59 | // Save application version in QString variable 60 | appVersion=QUOTE(APP_VERSION); 61 | // Connect signals to slots 62 | connect(connectToCameraAction, SIGNAL(triggered()), this, SLOT(connectToCamera())); 63 | connect(disconnectCameraAction, SIGNAL(triggered()), this, SLOT(disconnectCamera())); 64 | connect(exitAction, SIGNAL(triggered()), this, SLOT(close())); 65 | connect(grayscaleAction, SIGNAL(toggled(bool)), this, SLOT(setGrayscale(bool))); 66 | connect(smoothAction, SIGNAL(toggled(bool)), this, SLOT(setSmooth(bool))); 67 | connect(dilateAction, SIGNAL(toggled(bool)), this, SLOT(setDilate(bool))); 68 | connect(erodeAction, SIGNAL(toggled(bool)), this, SLOT(setErode(bool))); 69 | connect(flipAction, SIGNAL(toggled(bool)), this, SLOT(setFlip(bool))); 70 | connect(cannyAction, SIGNAL(toggled(bool)), this, SLOT(setCanny(bool))); 71 | connect(facedetectAction, SIGNAL(toggled(bool)), this, SLOT(setFacedetect(bool))); 72 | connect(settingsAction, SIGNAL(triggered()), this, SLOT(setProcessingSettings())); 73 | connect(aboutAction, SIGNAL(triggered()), this, SLOT(about())); 74 | connect(clearImageBufferButton, SIGNAL(released()), this, SLOT(clearImageBuffer())); 75 | connect(frameLabel, SIGNAL(onMouseMoveEvent()), this, SLOT(updateMouseCursorPosLabel())); 76 | qRegisterMetaType("MouseData"); 77 | connect(this->frameLabel,SIGNAL(newMouseData(struct MouseData)),this,SLOT(newMouseData(struct MouseData))); 78 | // Enable/disable appropriate menu items 79 | connectToCameraAction->setDisabled(false); 80 | disconnectCameraAction->setDisabled(true); 81 | processingMenu->setDisabled(true); 82 | // Set GUI in main window 83 | grayscaleAction->setChecked(false); 84 | smoothAction->setChecked(false); 85 | dilateAction->setChecked(false); 86 | erodeAction->setChecked(false); 87 | flipAction->setChecked(false); 88 | cannyAction->setChecked(false); 89 | facedetectAction->setChecked(false); 90 | frameLabel->setText("No camera connected."); 91 | imageBufferBar->setValue(0); 92 | imageBufferLabel->setText("[000/000]"); 93 | captureRateLabel->setText(""); 94 | processingRateLabel->setText(""); 95 | deviceNumberLabel->setText(""); 96 | cameraResolutionLabel->setText(""); 97 | roiLabel->setText(""); 98 | mouseCursorPosLabel->setText(""); 99 | clearImageBufferButton->setDisabled(true); 100 | } // MainWindow constructor 101 | 102 | MainWindow::~MainWindow() 103 | { 104 | // Check if controller exists 105 | if(controller!=NULL) 106 | { 107 | // Disconnect queued connections 108 | disconnect(controller->processingThread,SIGNAL(newFrame(QImage)),this,SLOT(updateFrame(QImage))); 109 | disconnect(this,SIGNAL(newProcessingFlags(struct ProcessingFlags)),controller->processingThread,SLOT(updateProcessingFlags(struct ProcessingFlags))); 110 | disconnect(this->processingSettingsDialog,SIGNAL(newProcessingSettings(struct ProcessingSettings)),controller->processingThread,SLOT(updateProcessingSettings(struct ProcessingSettings))); 111 | disconnect(this,SIGNAL(newTaskData(struct TaskData)),controller->processingThread,SLOT(updateTaskData(struct TaskData))); 112 | // Stop processing thread 113 | if(controller->processingThread->isRunning()) 114 | controller->stopProcessingThread(); 115 | // Stop capture thread 116 | if(controller->captureThread->isRunning()) 117 | controller->stopCaptureThread(); 118 | // Clear image buffer 119 | controller->clearImageBuffer(); 120 | // Check if threads have stopped 121 | if((controller->captureThread->isFinished())&&(controller->processingThread->isFinished())) 122 | { 123 | // Disconnect camera if connected 124 | if(controller->captureThread->isCameraConnected()) 125 | controller->disconnectCamera(); 126 | // Delete processing and capture threads 127 | controller->deleteProcessingThread(); 128 | controller->deleteCaptureThread(); 129 | } 130 | // Delete controller 131 | delete controller; 132 | controller=NULL; 133 | } 134 | } // MainWindow destructor 135 | 136 | void MainWindow::connectToCamera() 137 | { 138 | // Create dialog 139 | cameraConnectDialog = new CameraConnectDialog(this); 140 | // Prompt user 141 | // If user presses OK button on dialog, tell controller to connect to camera; else do nothing 142 | if(cameraConnectDialog->exec()==1) 143 | { 144 | // Set private member variables in cameraConnectDialog to values in dialog 145 | cameraConnectDialog->setDeviceNumber(); 146 | cameraConnectDialog->setImageBufferSize(); 147 | // Store image buffer size in local variable 148 | imageBufferSize=cameraConnectDialog->getImageBufferSize(); 149 | // Store device number in local variable 150 | deviceNumber=cameraConnectDialog->getDeviceNumber(); 151 | // Create controller 152 | controller = new Controller(deviceNumber,imageBufferSize); 153 | // If camera was successfully connected 154 | if(controller->captureThread->isCameraConnected()) 155 | { 156 | // Create queued connection between processing thread (emitter) and GUI thread (receiver/listener) 157 | connect(controller->processingThread,SIGNAL(newFrame(QImage)),this,SLOT(updateFrame(QImage)),Qt::QueuedConnection); 158 | // Create queued connections between GUI thread (emitter) and processing thread (receiver/listener) 159 | qRegisterMetaType("ProcessingFlags"); 160 | connect(this,SIGNAL(newProcessingFlags(struct ProcessingFlags)),controller->processingThread,SLOT(updateProcessingFlags(struct ProcessingFlags)),Qt::QueuedConnection); 161 | qRegisterMetaType("ProcessingSettings"); 162 | connect(this->processingSettingsDialog,SIGNAL(newProcessingSettings(struct ProcessingSettings)),controller->processingThread,SLOT(updateProcessingSettings(struct ProcessingSettings)),Qt::QueuedConnection); 163 | qRegisterMetaType("TaskData"); 164 | connect(this,SIGNAL(newTaskData(struct TaskData)),controller->processingThread,SLOT(updateTaskData(struct TaskData)),Qt::QueuedConnection); 165 | // Setup imageBufferBar in main window with minimum and maximum values 166 | imageBufferBar->setMinimum(0); 167 | imageBufferBar->setMaximum(imageBufferSize); 168 | // Enable/disable appropriate menu items 169 | connectToCameraAction->setDisabled(true); 170 | disconnectCameraAction->setDisabled(false); 171 | processingMenu->setDisabled(false); 172 | // Enable "Clear Image Buffer" push button in main window 173 | clearImageBufferButton->setDisabled(false); 174 | // Get input stream properties 175 | sourceWidth=controller->getInputSourceWidth(); 176 | sourceHeight=controller->getInputSourceHeight(); 177 | // Set text in labels in main window 178 | deviceNumberLabel->setNum(deviceNumber); 179 | cameraResolutionLabel->setText(QString::number(sourceWidth)+QString("x")+QString::number(sourceHeight)); 180 | /* 181 | QThread::IdlePriority 0 scheduled only when no other threads are running. 182 | QThread::LowestPriority 1 scheduled less often than LowPriority. 183 | QThread::LowPriority 2 scheduled less often than NormalPriority. 184 | QThread::NormalPriority 3 the default priority of the operating system. 185 | QThread::HighPriority 4 scheduled more often than NormalPriority. 186 | QThread::HighestPriority 5 scheduled more often than HighPriority. 187 | QThread::TimeCriticalPriority 6 scheduled as often as possible. 188 | QThread::InheritPriority 7 use the same priority as the creating thread. This is the default. 189 | */ 190 | // Start capturing frames from camera 191 | controller->captureThread->start(QThread::IdlePriority); 192 | // Start processing captured frames 193 | controller->processingThread->start(); 194 | } 195 | // Display error dialog if camera connection is unsuccessful 196 | else 197 | QMessageBox::warning(this,"ERROR:","Could not connect to camera."); 198 | } 199 | } // connectToCamera() 200 | 201 | void MainWindow::disconnectCamera() 202 | { 203 | // Check if controller exists 204 | if(controller!=NULL) 205 | { 206 | // Disconnect queued connections 207 | disconnect(controller->processingThread,SIGNAL(newFrame(QImage)),this,SLOT(updateFrame(QImage))); 208 | disconnect(this,SIGNAL(newProcessingFlags(struct ProcessingFlags)),controller->processingThread,SLOT(updateProcessingFlags(struct ProcessingFlags))); 209 | disconnect(this->processingSettingsDialog,SIGNAL(newProcessingSettings(struct ProcessingSettings)),controller->processingThread,SLOT(updateProcessingSettings(struct ProcessingSettings))); 210 | disconnect(this,SIGNAL(newTaskData(struct TaskData)),controller->processingThread,SLOT(updateTaskData(struct TaskData))); 211 | // Stop processing thread 212 | if(controller->processingThread->isRunning()) 213 | controller->stopProcessingThread(); 214 | // Stop capture thread 215 | if(controller->captureThread->isRunning()) 216 | controller->stopCaptureThread(); 217 | // Clear image buffer 218 | controller->clearImageBuffer(); 219 | // Check if threads have stopped 220 | if((controller->captureThread->isFinished())&&(controller->processingThread->isFinished())) 221 | { 222 | // Disconnect camera if connected 223 | if(controller->captureThread->isCameraConnected()) 224 | controller->disconnectCamera(); 225 | // Delete processing and capture threads 226 | controller->deleteProcessingThread(); 227 | controller->deleteCaptureThread(); 228 | } 229 | // Delete controller 230 | delete controller; 231 | controller=NULL; 232 | // Enable/Disable appropriate menu items 233 | connectToCameraAction->setDisabled(false); 234 | disconnectCameraAction->setDisabled(true); 235 | processingMenu->setDisabled(true); 236 | // Set GUI in main window 237 | grayscaleAction->setChecked(false); 238 | smoothAction->setChecked(false); 239 | dilateAction->setChecked(false); 240 | erodeAction->setChecked(false); 241 | flipAction->setChecked(false); 242 | cannyAction->setChecked(false); 243 | facedetectAction->setChecked(false); 244 | frameLabel->setText("No camera connected."); 245 | imageBufferBar->setValue(0); 246 | imageBufferLabel->setText("[000/000]"); 247 | captureRateLabel->setText(""); 248 | processingRateLabel->setText(""); 249 | deviceNumberLabel->setText(""); 250 | cameraResolutionLabel->setText(""); 251 | roiLabel->setText(""); 252 | mouseCursorPosLabel->setText(""); 253 | clearImageBufferButton->setDisabled(true); 254 | } 255 | // Display error dialog if camera could not be disconnected 256 | else 257 | QMessageBox::warning(this,"ERROR:","Could not disconnect camera."); 258 | } // disconnectCamera() 259 | 260 | void MainWindow::about() 261 | { 262 | QMessageBox::information(this,"About",QString("Written by Nick D'Ademo\n\nContact: nickdademo@gmail.com\nWebsite: www.nickdademo.com\n\nVersion: ")+appVersion); 263 | } // about() 264 | 265 | void MainWindow::clearImageBuffer() 266 | { 267 | controller->clearImageBuffer(); 268 | } // clearImageBuffer() 269 | 270 | void MainWindow::setGrayscale(bool input) 271 | { 272 | // Not checked 273 | if(!input) 274 | processingFlags.grayscaleOn=false; 275 | // Checked 276 | else if(input) 277 | processingFlags.grayscaleOn=true; 278 | // Update processing flags in processingThread 279 | emit newProcessingFlags(processingFlags); 280 | } // setGrayscale() 281 | 282 | void MainWindow::setSmooth(bool input) 283 | { 284 | // Not checked 285 | if(!input) 286 | processingFlags.smoothOn=false; 287 | // Checked 288 | else if(input) 289 | processingFlags.smoothOn=true; 290 | // Update processing flags in processingThread 291 | emit newProcessingFlags(processingFlags); 292 | } // setSmooth() 293 | 294 | void MainWindow::setDilate(bool input) 295 | { 296 | // Not checked 297 | if(!input) 298 | processingFlags.dilateOn=false; 299 | // Checked 300 | else if(input) 301 | processingFlags.dilateOn=true; 302 | // Update processing flags in processingThread 303 | emit newProcessingFlags(processingFlags); 304 | } // setDilate() 305 | 306 | void MainWindow::setErode(bool input) 307 | { 308 | // Not checked 309 | if(!input) 310 | processingFlags.erodeOn=false; 311 | // Checked 312 | else if(input) 313 | processingFlags.erodeOn=true; 314 | // Update processing flags in processingThread 315 | emit newProcessingFlags(processingFlags); 316 | } // setErode() 317 | 318 | void MainWindow::setFlip(bool input) 319 | { 320 | // Not checked 321 | if(!input) 322 | processingFlags.flipOn=false; 323 | // Checked 324 | else if(input) 325 | processingFlags.flipOn=true; 326 | // Update processing flags in processingThread 327 | emit newProcessingFlags(processingFlags); 328 | } // setFlip() 329 | 330 | void MainWindow::setCanny(bool input) 331 | { 332 | // Not checked 333 | if(!input) 334 | processingFlags.cannyOn=false; 335 | // Checked 336 | else if(input) 337 | processingFlags.cannyOn=true; 338 | // Update processing flags in processingThread 339 | emit newProcessingFlags(processingFlags); 340 | } // setCanny() 341 | 342 | void MainWindow::setFacedetect(bool input) 343 | { 344 | // Not checked 345 | if(!input) 346 | processingFlags.facedetectOn=false; 347 | // Checked 348 | else if(input) 349 | processingFlags.facedetectOn=true; 350 | // Update processing flags in processingThread 351 | emit newProcessingFlags(processingFlags); 352 | } // setFacedetect() 353 | 354 | void MainWindow::updateFrame(const QImage &frame) 355 | { 356 | // Show [number of images in buffer / image buffer size] in imageBufferLabel in main window 357 | imageBufferLabel->setText(QString("[")+QString::number(controller->processingThread->getCurrentSizeOfBuffer())+ 358 | QString("/")+QString::number(imageBufferSize)+QString("]")); 359 | // Show percentage of image bufffer full in imageBufferBar in main window 360 | imageBufferBar->setValue(controller->processingThread->getCurrentSizeOfBuffer()); 361 | // Show processing rate in captureRateLabel in main window 362 | captureRateLabel->setNum(controller->captureThread->getAvgFPS()); 363 | captureRateLabel->setText(captureRateLabel->text()+" fps"); 364 | // Show processing rate in processingRateLabel in main window 365 | processingRateLabel->setNum(controller->processingThread->getAvgFPS()); 366 | processingRateLabel->setText(processingRateLabel->text()+" fps"); 367 | // Show ROI information in roiLabel in main window 368 | roiLabel->setText(QString("(")+QString::number(controller->processingThread->getCurrentROI().x)+QString(",")+ 369 | QString::number(controller->processingThread->getCurrentROI().y)+QString(") ")+ 370 | QString::number(controller->processingThread->getCurrentROI().width)+ 371 | QString("x")+QString::number(controller->processingThread->getCurrentROI().height)); 372 | // Display frame in main window 373 | frameLabel->setPixmap(QPixmap::fromImage(frame)); 374 | } // updateFrame() 375 | 376 | void MainWindow::setProcessingSettings() 377 | { 378 | // Prompt user: 379 | // If user presses OK button on dialog, update processing settings 380 | if(processingSettingsDialog->exec()==1) 381 | processingSettingsDialog->updateStoredSettingsFromDialog(); 382 | // Else, restore dialog state 383 | else 384 | processingSettingsDialog->updateDialogSettingsFromStored(); 385 | } // setProcessingSettings() 386 | 387 | void MainWindow::updateMouseCursorPosLabel() 388 | { 389 | // Update mouse cursor position in mouseCursorPosLabel in main window 390 | mouseCursorPosLabel->setText(QString("(")+QString::number(frameLabel->getMouseCursorPos().x())+ 391 | QString(",")+QString::number(frameLabel->getMouseCursorPos().y())+ 392 | QString(")")); 393 | } // updateMouseCursorPosLabel() 394 | 395 | void MainWindow::newMouseData(struct MouseData mouseData) 396 | { 397 | // Local variables 398 | int x_temp, y_temp, width_temp, height_temp; 399 | // Set ROI 400 | if(mouseData.leftButtonRelease) 401 | { 402 | // Copy box dimensions from mouseData to taskData 403 | taskData.selectionBox.setX(mouseData.selectionBox.x()); 404 | taskData.selectionBox.setY(mouseData.selectionBox.y()); 405 | taskData.selectionBox.setWidth(mouseData.selectionBox.width()); 406 | taskData.selectionBox.setHeight(mouseData.selectionBox.height()); 407 | // Check if selection box has NON-ZERO dimensions 408 | if((taskData.selectionBox.width()!=0)&&((taskData.selectionBox.height())!=0)) 409 | { 410 | // Selection box can also be drawn from bottom-right to top-left corner 411 | if(taskData.selectionBox.width()<0) 412 | { 413 | x_temp=taskData.selectionBox.x(); 414 | width_temp=taskData.selectionBox.width(); 415 | taskData.selectionBox.setX(x_temp+taskData.selectionBox.width()); 416 | taskData.selectionBox.setWidth(width_temp*-1); 417 | } 418 | if(taskData.selectionBox.height()<0) 419 | { 420 | y_temp=taskData.selectionBox.y(); 421 | height_temp=taskData.selectionBox.height(); 422 | taskData.selectionBox.setY(y_temp+taskData.selectionBox.height()); 423 | taskData.selectionBox.setHeight(height_temp*-1); 424 | } 425 | // Check if selection box is not outside window 426 | if((taskData.selectionBox.x()<0)||(taskData.selectionBox.y()<0)|| 427 | ((taskData.selectionBox.x()+taskData.selectionBox.width())>sourceWidth)|| 428 | ((taskData.selectionBox.y()+taskData.selectionBox.height())>sourceHeight)) 429 | { 430 | // Display error message 431 | QMessageBox::warning(this,"ERROR:","Selection box outside range. Please try again."); 432 | } 433 | else 434 | { 435 | // Set setROIFlag to TRUE 436 | taskData.setROIFlag=true; 437 | // Update task data in processingThread 438 | emit newTaskData(taskData); 439 | // Set setROIFlag to FALSE 440 | taskData.setROIFlag=false; 441 | } 442 | } 443 | } 444 | // Reset ROI 445 | else if(mouseData.rightButtonRelease) 446 | { 447 | // Set resetROIFlag to TRUE 448 | taskData.resetROIFlag=true; 449 | // Update task data in processingThread 450 | emit newTaskData(taskData); 451 | // Set resetROIFlag to FALSE 452 | taskData.resetROIFlag=false; 453 | } 454 | } // newMouseData() 455 | -------------------------------------------------------------------------------- /MainWindow.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* MainWindow.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef MAINWINDOW_H 34 | #define MAINWINDOW_H 35 | 36 | #include "ui_MainWindow.h" 37 | #include "Structures.h" 38 | 39 | #define QUOTE_(x) #x 40 | #define QUOTE(x) QUOTE_(x) 41 | 42 | class CameraConnectDialog; 43 | class ProcessingSettingsDialog; 44 | class Controller; 45 | 46 | class MainWindow : public QMainWindow, private Ui::MainWindow 47 | { 48 | Q_OBJECT 49 | 50 | public: 51 | MainWindow(QWidget *parent = 0); 52 | ~MainWindow(); 53 | private: 54 | CameraConnectDialog *cameraConnectDialog; 55 | ProcessingSettingsDialog *processingSettingsDialog; 56 | Controller *controller; 57 | ProcessingFlags processingFlags; 58 | TaskData taskData; 59 | QString appVersion; 60 | int sourceWidth; 61 | int sourceHeight; 62 | int deviceNumber; 63 | int imageBufferSize; 64 | public slots: 65 | void connectToCamera(); 66 | void disconnectCamera(); 67 | void about(); 68 | void clearImageBuffer(); 69 | void setGrayscale(bool); 70 | void setSmooth(bool); 71 | void setDilate(bool); 72 | void setErode(bool); 73 | void setFlip(bool); 74 | void setCanny(bool); 75 | void setFacedetect(bool); 76 | void setProcessingSettings(); 77 | void updateMouseCursorPosLabel(); 78 | void newMouseData(struct MouseData); 79 | private slots: 80 | void updateFrame(const QImage &frame); 81 | signals: 82 | void newProcessingFlags(struct ProcessingFlags p_flags); 83 | void newTaskData(struct TaskData taskData); 84 | }; 85 | 86 | #endif // MAINWINDOW_H 87 | -------------------------------------------------------------------------------- /MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 661 10 | 633 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | 21 | 661 22 | 633 23 | 24 | 25 | 26 | qt-opencv-multithreaded 27 | 28 | 29 | false 30 | 31 | 32 | 33 | 34 | 35 | 10 36 | 10 37 | 642 38 | 591 39 | 40 | 41 | 42 | 43 | 44 | 45 | true 46 | 47 | 48 | 49 | 0 50 | 0 51 | 52 | 53 | 54 | 55 | 640 56 | 480 57 | 58 | 59 | 60 | true 61 | 62 | 63 | true 64 | 65 | 66 | QFrame::Box 67 | 68 | 69 | QFrame::Raised 70 | 71 | 72 | 1 73 | 74 | 75 | Qt::AlignCenter 76 | 77 | 78 | 79 | 80 | 81 | 82 | Qt::Horizontal 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 0 95 | 0 96 | 97 | 98 | 99 | 100 | 0 101 | 20 102 | 103 | 104 | 105 | 106 | 16777215 107 | 20 108 | 109 | 110 | 111 | 112 | 8 113 | 75 114 | true 115 | 116 | 117 | 118 | Image Buffer Status (% full): 119 | 120 | 121 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 0 130 | 0 131 | 132 | 133 | 134 | 135 | 0 136 | 20 137 | 138 | 139 | 140 | 141 | 16777215 142 | 20 143 | 144 | 145 | 146 | 147 | 8 148 | 149 | 150 | 151 | 0 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 0 160 | 0 161 | 162 | 163 | 164 | 165 | 0 166 | 20 167 | 168 | 169 | 170 | 171 | 16777215 172 | 20 173 | 174 | 175 | 176 | 177 | 8 178 | 179 | 180 | 181 | Qt::AlignCenter 182 | 183 | 184 | 185 | 186 | 187 | 188 | Qt::Vertical 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 0 197 | 0 198 | 199 | 200 | 201 | 202 | 0 203 | 20 204 | 205 | 206 | 207 | 208 | 16777215 209 | 20 210 | 211 | 212 | 213 | 214 | 8 215 | 75 216 | true 217 | 218 | 219 | 220 | Capture Rate: 221 | 222 | 223 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 224 | 225 | 226 | 227 | 228 | 229 | 230 | true 231 | 232 | 233 | 234 | 0 235 | 0 236 | 237 | 238 | 239 | 240 | 0 241 | 20 242 | 243 | 244 | 245 | 246 | 16777215 247 | 20 248 | 249 | 250 | 251 | 252 | 8 253 | 254 | 255 | 256 | Qt::AlignCenter 257 | 258 | 259 | 260 | 261 | 262 | 263 | Qt::Vertical 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 0 272 | 0 273 | 274 | 275 | 276 | 277 | 0 278 | 20 279 | 280 | 281 | 282 | 283 | 16777215 284 | 20 285 | 286 | 287 | 288 | 289 | 8 290 | 75 291 | true 292 | 293 | 294 | 295 | Processing Rate: 296 | 297 | 298 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 0 307 | 0 308 | 309 | 310 | 311 | 312 | 0 313 | 20 314 | 315 | 316 | 317 | 318 | 16777215 319 | 20 320 | 321 | 322 | 323 | 324 | 8 325 | 326 | 327 | 328 | Qt::AlignCenter 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 0 341 | 0 342 | 343 | 344 | 345 | 346 | 0 347 | 20 348 | 349 | 350 | 351 | 352 | 16777215 353 | 20 354 | 355 | 356 | 357 | 358 | 8 359 | 75 360 | true 361 | 362 | 363 | 364 | Camera Dev No: 365 | 366 | 367 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 30 376 | 20 377 | 378 | 379 | 380 | 381 | 30 382 | 20 383 | 384 | 385 | 386 | 387 | 16777215 388 | 20 389 | 390 | 391 | 392 | 393 | 8 394 | 395 | 396 | 397 | Qt::AlignCenter 398 | 399 | 400 | 401 | 402 | 403 | 404 | Qt::Vertical 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 0 413 | 0 414 | 415 | 416 | 417 | 418 | 0 419 | 20 420 | 421 | 422 | 423 | 424 | 16777215 425 | 20 426 | 427 | 428 | 429 | 430 | 8 431 | 75 432 | true 433 | 434 | 435 | 436 | Camera Resolution: 437 | 438 | 439 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 70 448 | 20 449 | 450 | 451 | 452 | 453 | 70 454 | 20 455 | 456 | 457 | 458 | 459 | 16777215 460 | 20 461 | 462 | 463 | 464 | 465 | 8 466 | 467 | 468 | 469 | Qt::AlignCenter 470 | 471 | 472 | 473 | 474 | 475 | 476 | Qt::Vertical 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 0 485 | 0 486 | 487 | 488 | 489 | 490 | 0 491 | 20 492 | 493 | 494 | 495 | 496 | 16777215 497 | 20 498 | 499 | 500 | 501 | 502 | 8 503 | 75 504 | true 505 | 506 | 507 | 508 | ROI: 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 100 517 | 20 518 | 519 | 520 | 521 | 522 | 70 523 | 20 524 | 525 | 526 | 527 | 528 | 16777215 529 | 20 530 | 531 | 532 | 533 | 534 | 8 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | Qt::Vertical 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 8 551 | 75 552 | true 553 | 554 | 555 | 556 | Cursor 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 70 565 | 20 566 | 567 | 568 | 569 | 570 | 70 571 | 20 572 | 573 | 574 | 575 | 576 | 16777215 577 | 20 578 | 579 | 580 | 581 | 582 | 8 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 8 594 | 595 | 596 | 597 | Clear Image Buffer 598 | 599 | 600 | 601 | 602 | 603 | 604 | Qt::Horizontal 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 0 617 | 0 618 | 661 619 | 26 620 | 621 | 622 | 623 | 624 | Main 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | Help 634 | 635 | 636 | 637 | 638 | 639 | Processing 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | Connect to Camera... 658 | 659 | 660 | 661 | 662 | Disconnect Camera 663 | 664 | 665 | 666 | 667 | Exit 668 | 669 | 670 | 671 | 672 | About... 673 | 674 | 675 | 676 | 677 | true 678 | 679 | 680 | 1: Grayscale 681 | 682 | 683 | 684 | 685 | true 686 | 687 | 688 | 2: Smooth 689 | 690 | 691 | 692 | 693 | true 694 | 695 | 696 | 5: Flip 697 | 698 | 699 | 700 | 701 | true 702 | 703 | 704 | 3: Dilate 705 | 706 | 707 | 708 | 709 | true 710 | 711 | 712 | 4: Erode 713 | 714 | 715 | 716 | 717 | true 718 | 719 | 720 | 6. Canny 721 | 722 | 723 | 724 | 725 | Settings... 726 | 727 | 728 | 729 | 730 | true 731 | 732 | 733 | 7: Facedetect 734 | 735 | 736 | 737 | 738 | 739 | FrameLabel 740 | QLabel 741 |
FrameLabel.h
742 |
743 |
744 | 745 | clearImageBufferButton 746 | 747 | 748 | 749 |
750 | -------------------------------------------------------------------------------- /ProcessingSettingsDialog.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* ProcessingSettingsDialog.cpp */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #include "ProcessingSettingsDialog.h" 34 | 35 | // Qt header files 36 | #include 37 | #include 38 | // Header file containing default values 39 | #include "DefaultValues.h" 40 | 41 | #include 42 | 43 | 44 | cv::String ConvertQString2CVString(const QString &qs) 45 | { 46 | // QString->cv::String 47 | // see: http://stackoverflow.com/questions/4214369/how-to-convert-qstring-to-stdstring 48 | cv::String cs = qs.toUtf8().constData(); 49 | return cs; 50 | } 51 | 52 | ProcessingSettingsDialog::ProcessingSettingsDialog(QWidget *parent) : QDialog(parent) 53 | { 54 | // Setup dialog 55 | setupUi(this); 56 | // Connect GUI signals and slots 57 | connect(resetAllToDefaultsButton,SIGNAL(released()),SLOT(resetAllDialogToDefaults())); 58 | connect(resetSmoothToDefaultsButton,SIGNAL(released()),SLOT(resetSmoothDialogToDefaults())); 59 | connect(resetDilateToDefaultsButton,SIGNAL(released()),SLOT(resetDilateDialogToDefaults())); 60 | connect(resetErodeToDefaultsButton,SIGNAL(released()),SLOT(resetErodeDialogToDefaults())); 61 | connect(resetFlipToDefaultsButton,SIGNAL(released()),SLOT(resetFlipDialogToDefaults())); 62 | connect(resetCannyToDefaultsButton,SIGNAL(released()),SLOT(resetCannyDialogToDefaults())); 63 | connect(resetFaceDetectToDefaultsButton,SIGNAL(released()),SLOT(resetFaceDetectToDefaults())); 64 | connect(applyButton,SIGNAL(released()),SLOT(updateStoredSettingsFromDialog())); 65 | connect(smoothTypeGroup,SIGNAL(buttonReleased(QAbstractButton*)),SLOT(smoothTypeChange(QAbstractButton*))); 66 | connect(chooseFacedetectCascadeFileButton,SIGNAL(released()),SLOT(chooseFacedetectCascadeFile())); 67 | connect(chooseFacedetectNestedCascadeFileButton,SIGNAL(released()),SLOT(chooseFacedetectNestedCascadeFile())); 68 | // dilateIterationsEdit input string validation 69 | QRegExp rx5("[1-9]\\d{0,1}"); // Integers 1 to 99 70 | QRegExpValidator *validator5 = new QRegExpValidator(rx5, 0); 71 | dilateIterationsEdit->setValidator(validator5); 72 | // erodeIterationsEdit input string validation 73 | QRegExp rx6("[1-9]\\d{0,1}"); // Integers 1 to 99 74 | QRegExpValidator *validator6 = new QRegExpValidator(rx6, 0); 75 | erodeIterationsEdit->setValidator(validator6); 76 | // cannyThresh1Edit input string validation 77 | QRegExp rx7("[0-9]\\d{0,2}"); // Integers 0 to 999 78 | QRegExpValidator *validator7 = new QRegExpValidator(rx7, 0); 79 | cannyThresh1Edit->setValidator(validator7); 80 | // cannyThresh2Edit input string validation 81 | QRegExp rx8("[0-9]\\d{0,2}"); // Integers 0 to 999 82 | QRegExpValidator *validator8 = new QRegExpValidator(rx8, 0); 83 | cannyThresh2Edit->setValidator(validator8); 84 | // cannyApertureSizeEdit input string validation 85 | QRegExp rx9("[3,5,7]\\d{0,0}"); // Integers 3,5,7 86 | QRegExpValidator *validator9 = new QRegExpValidator(rx9, 0); 87 | cannyApertureSizeEdit->setValidator(validator9); 88 | // Set dialog values to defaults 89 | resetAllDialogToDefaults(); 90 | // Update processing settings in processingSettings structure and processingThread 91 | updateStoredSettingsFromDialog(); 92 | } // ProcessingSettingsDialog constructor 93 | 94 | void ProcessingSettingsDialog::updateStoredSettingsFromDialog() 95 | { 96 | // Validate values in dialog before storing 97 | validateDialog(); 98 | // Smooth 99 | if(smoothTypeGroup->checkedButton()==(QAbstractButton*)smoothBlurNoScaleButton) 100 | processingSettings.smoothType=CV_BLUR_NO_SCALE; 101 | else if(smoothTypeGroup->checkedButton()==(QAbstractButton*)smoothBlurButton) 102 | processingSettings.smoothType=CV_BLUR; 103 | else if(smoothTypeGroup->checkedButton()==(QAbstractButton*)smoothGaussianButton) 104 | processingSettings.smoothType=CV_GAUSSIAN; 105 | else if(smoothTypeGroup->checkedButton()==(QAbstractButton*)smoothMedianButton) 106 | processingSettings.smoothType=CV_MEDIAN; 107 | processingSettings.smoothParam1=smoothParam1Edit->text().toInt(); 108 | processingSettings.smoothParam2=smoothParam2Edit->text().toInt(); 109 | processingSettings.smoothParam3=smoothParam3Edit->text().toDouble(); 110 | processingSettings.smoothParam4=smoothParam4Edit->text().toDouble(); 111 | // Dilate 112 | processingSettings.dilateNumberOfIterations=dilateIterationsEdit->text().toInt(); 113 | // Erode 114 | processingSettings.erodeNumberOfIterations=erodeIterationsEdit->text().toInt(); 115 | // Flip 116 | if(flipModeGroup->checkedButton()==(QAbstractButton*)flipXAxisButton) 117 | processingSettings.flipMode=0; 118 | else if(flipModeGroup->checkedButton()==(QAbstractButton*)flipYAxisButton) 119 | processingSettings.flipMode=1; 120 | else if(flipModeGroup->checkedButton()==(QAbstractButton*)flipBothAxesButton) 121 | processingSettings.flipMode=-1; 122 | // Canny 123 | processingSettings.cannyThreshold1=cannyThresh1Edit->text().toDouble(); 124 | processingSettings.cannyThreshold2=cannyThresh2Edit->text().toDouble(); 125 | processingSettings.cannyApertureSize=cannyApertureSizeEdit->text().toInt(); 126 | // Facedetect 127 | processingSettings.facedetectScale=facedetectScaleEdit->text().toDouble(); 128 | processingSettings.facedetectCascadeFilename=facedetectCascadeFilenameEdit->text(); 129 | if(!processingSettings.facedetectCascadeFile.load(ConvertQString2CVString(processingSettings.facedetectCascadeFilename))) 130 | qDebug() << "ERROR: Can not open cascade file."; 131 | processingSettings.facedetectNestedCascadeFilename=facedetectNestedCasssscadeFilenameEdit->text(); 132 | if(processingSettings.facedetectNestedCascadeFile.load(ConvertQString2CVString(processingSettings.facedetectNestedCascadeFilename))) 133 | qDebug() << "ERROR: Can not open nested cascade file."; 134 | // Update processing flags in processingThread 135 | emit newProcessingSettings(processingSettings); 136 | } // updateStoredSettingsFromDialog() 137 | 138 | void ProcessingSettingsDialog::updateDialogSettingsFromStored() 139 | { 140 | // Smooth 141 | if(processingSettings.smoothType==CV_BLUR_NO_SCALE) 142 | smoothBlurNoScaleButton->setChecked(true); 143 | else if(processingSettings.smoothType==CV_BLUR) 144 | smoothBlurButton->setChecked(true); 145 | else if(processingSettings.smoothType==CV_GAUSSIAN) 146 | smoothGaussianButton->setChecked(true); 147 | else if(processingSettings.smoothType==CV_MEDIAN) 148 | smoothMedianButton->setChecked(true); 149 | smoothParam1Edit->setText(QString::number(processingSettings.smoothParam1)); 150 | smoothParam2Edit->setText(QString::number(processingSettings.smoothParam2)); 151 | smoothParam3Edit->setText(QString::number(processingSettings.smoothParam3)); 152 | smoothParam4Edit->setText(QString::number(processingSettings.smoothParam4)); 153 | // Dilate 154 | dilateIterationsEdit->setText(QString::number(processingSettings.dilateNumberOfIterations)); 155 | // Erode 156 | erodeIterationsEdit->setText(QString::number(processingSettings.erodeNumberOfIterations)); 157 | // Flip 158 | if(processingSettings.flipMode==0) 159 | flipXAxisButton->setChecked(true); 160 | else if(processingSettings.flipMode==1) 161 | flipYAxisButton->setChecked(true); 162 | else if(processingSettings.flipMode==-1) 163 | flipBothAxesButton->setChecked(true); 164 | // Canny 165 | cannyThresh1Edit->setText(QString::number(processingSettings.cannyThreshold1)); 166 | cannyThresh2Edit->setText(QString::number(processingSettings.cannyThreshold2)); 167 | cannyApertureSizeEdit->setText(QString::number(processingSettings.cannyApertureSize)); 168 | // Facedetct 169 | facedetectScaleEdit->setText(QString::number(processingSettings.facedetectScale)); 170 | facedetectCascadeFilenameEdit->setText(processingSettings.facedetectCascadeFilename); 171 | facedetectNestedCasssscadeFilenameEdit->setText(processingSettings.facedetectNestedCascadeFilename); 172 | // Enable/disable appropriate Smooth parameter inputs 173 | smoothTypeChange(smoothTypeGroup->checkedButton()); 174 | } // updateDialogSettingsFromStored() 175 | 176 | void ProcessingSettingsDialog::resetAllDialogToDefaults() 177 | { 178 | // Smooth 179 | resetSmoothDialogToDefaults(); 180 | // Dilate 181 | resetDilateDialogToDefaults(); 182 | // Erode 183 | resetErodeDialogToDefaults(); 184 | // Flip 185 | resetFlipDialogToDefaults(); 186 | // Canny 187 | resetCannyDialogToDefaults(); 188 | // Facedetect 189 | resetFaceDetectToDefaults(); 190 | } // resetAllDialogToDefaults() 191 | 192 | void ProcessingSettingsDialog::smoothTypeChange(QAbstractButton *input) 193 | { 194 | if(input==(QAbstractButton*)smoothBlurNoScaleButton) 195 | { 196 | // smoothParam1Edit input string validation 197 | QRegExp rx1("[1-9]\\d{0,1}"); // Integers 1 to 99 198 | QRegExpValidator *validator1 = new QRegExpValidator(rx1, 0); 199 | smoothParam1Edit->setValidator(validator1); 200 | // smoothParam2Edit input string validation 201 | QRegExp rx2("[0-9]\\d{0,1}"); // Integers 0 to 99 202 | QRegExpValidator *validator2 = new QRegExpValidator(rx2, 0); 203 | smoothParam2Edit->setValidator(validator2); 204 | // Enable/disable appropriate parameter inputs 205 | smoothParam1Edit->setEnabled(true); 206 | smoothParam2Edit->setEnabled(true); 207 | smoothParam3Edit->setEnabled(false); 208 | smoothParam4Edit->setEnabled(false); 209 | // Set parameter range labels 210 | smoothParam1RangeLabel->setText("[1-99]"); 211 | smoothParam2RangeLabel->setText("[0-99]"); 212 | smoothParam3RangeLabel->setText(""); 213 | smoothParam4RangeLabel->setText(""); 214 | } 215 | else if(input==(QAbstractButton*)smoothBlurButton) 216 | { 217 | // smoothParam1Edit input string validation 218 | QRegExp rx1("[1-9]\\d{0,1}"); // Integers 1 to 99 219 | QRegExpValidator *validator1 = new QRegExpValidator(rx1, 0); 220 | smoothParam1Edit->setValidator(validator1); 221 | // smoothParam2Edit input string validation 222 | QRegExp rx2("[0-9]\\d{0,1}"); // Integers 0 to 99 223 | QRegExpValidator *validator2 = new QRegExpValidator(rx2, 0); 224 | smoothParam2Edit->setValidator(validator2); 225 | // Enable/disable appropriate parameter inputs 226 | smoothParam1Edit->setEnabled(true); 227 | smoothParam2Edit->setEnabled(true); 228 | smoothParam3Edit->setEnabled(false); 229 | smoothParam4Edit->setEnabled(false); 230 | // Set parameter range labels 231 | smoothParam1RangeLabel->setText("[1-99]"); 232 | smoothParam2RangeLabel->setText("[0-99]"); 233 | smoothParam3RangeLabel->setText(""); 234 | smoothParam4RangeLabel->setText(""); 235 | } 236 | else if(input==(QAbstractButton*)smoothGaussianButton) 237 | { 238 | // smoothParam1Edit input string validation 239 | QRegExp rx1("[0-9]\\d{0,1}"); // Integers 0 to 99 240 | QRegExpValidator *validator1 = new QRegExpValidator(rx1, 0); 241 | smoothParam1Edit->setValidator(validator1); 242 | // smoothParam2Edit input string validation 243 | QRegExp rx2("[0-9]\\d{0,1}"); // Integers 0 to 99 244 | QRegExpValidator *validator2 = new QRegExpValidator(rx2, 0); 245 | smoothParam2Edit->setValidator(validator2); 246 | // smoothParam3Edit input string validation 247 | QDoubleValidator *validator3 = new QDoubleValidator(0.0, 99.99, 2, this); 248 | validator3->setNotation(QDoubleValidator::StandardNotation); 249 | smoothParam3Edit->setValidator(validator3); 250 | // Enable/disable appropriate parameter inputs 251 | smoothParam1Edit->setEnabled(true); 252 | smoothParam2Edit->setEnabled(true); 253 | smoothParam3Edit->setEnabled(true); 254 | smoothParam4Edit->setEnabled(false); 255 | // Set parameter range labels 256 | smoothParam1RangeLabel->setText("[0-99]"); 257 | smoothParam2RangeLabel->setText("[0-99]"); 258 | smoothParam3RangeLabel->setText("[0.00-99.99]"); 259 | smoothParam4RangeLabel->setText(""); 260 | } 261 | else if(input==(QAbstractButton*)smoothMedianButton) 262 | { 263 | // smoothParam1Edit input string validation 264 | QRegExp rx1("[1-9]\\d{0,1}"); // Integers 1 to 99 265 | QRegExpValidator *validator1 = new QRegExpValidator(rx1, 0); 266 | smoothParam1Edit->setValidator(validator1); 267 | // Enable/disable appropriate parameter inputs 268 | smoothParam1Edit->setEnabled(true); 269 | smoothParam2Edit->setEnabled(false); 270 | smoothParam3Edit->setEnabled(false); 271 | smoothParam4Edit->setEnabled(false); 272 | // Set parameter range labels 273 | smoothParam1RangeLabel->setText("[1-99]"); 274 | smoothParam2RangeLabel->setText(""); 275 | smoothParam3RangeLabel->setText(""); 276 | smoothParam4RangeLabel->setText(""); 277 | } 278 | } // smoothTypeChange() 279 | 280 | void ProcessingSettingsDialog::validateDialog() 281 | { 282 | // Local variables 283 | bool inputEmpty=false; 284 | 285 | // If value of Smooth parameter 1 is EVEN (and not zero), convert to ODD by adding 1 286 | if(((smoothParam1Edit->text().toInt()%2)==0)&&(smoothParam1Edit->text().toInt()!=0)) 287 | { 288 | smoothParam1Edit->setText(QString::number(smoothParam1Edit->text().toInt()+1)); 289 | QMessageBox::information(this->parentWidget(),"NOTE:","Smooth parameter 1 must be an ODD number.\n\nAutomatically set to (inputted value+1)."); 290 | } 291 | // If value of Smooth parameter 2 is EVEN (and not zero), convert to ODD by adding 1 292 | if(((smoothParam2Edit->text().toInt()%2)==0)&&(smoothParam2Edit->text().toInt()!=0)) 293 | { 294 | smoothParam2Edit->setText(QString::number(smoothParam2Edit->text().toInt()+1)); 295 | QMessageBox::information(this->parentWidget(),"NOTE:","Smooth parameter 2 must be an ODD number (or zero).\n\nAutomatically set to (inputted value+1)."); 296 | } 297 | 298 | // Check for empty inputs: if empty, set to default values 299 | if(smoothParam1Edit->text().isEmpty()) 300 | { 301 | smoothParam1Edit->setText(QString::number(DEFAULT_SMOOTH_PARAM_1)); 302 | inputEmpty=true; 303 | } 304 | if(smoothParam2Edit->text().isEmpty()) 305 | { 306 | smoothParam2Edit->setText(QString::number(DEFAULT_SMOOTH_PARAM_2)); 307 | inputEmpty=true; 308 | } 309 | if(smoothParam3Edit->text().isEmpty()) 310 | { 311 | smoothParam3Edit->setText(QString::number(DEFAULT_SMOOTH_PARAM_3)); 312 | inputEmpty=true; 313 | } 314 | if(smoothParam4Edit->text().isEmpty()) 315 | { 316 | smoothParam4Edit->setText(QString::number(DEFAULT_SMOOTH_PARAM_4)); 317 | inputEmpty=true; 318 | } 319 | if(dilateIterationsEdit->text().isEmpty()) 320 | { 321 | dilateIterationsEdit->setText(QString::number(DEFAULT_DILATE_ITERATIONS)); 322 | inputEmpty=true; 323 | } 324 | if(erodeIterationsEdit->text().isEmpty()) 325 | { 326 | erodeIterationsEdit->setText(QString::number(DEFAULT_ERODE_ITERATIONS)); 327 | inputEmpty=true; 328 | } 329 | if(cannyThresh1Edit->text().isEmpty()) 330 | { 331 | cannyThresh1Edit->setText(QString::number(DEFAULT_CANNY_THRESHOLD_1)); 332 | inputEmpty=true; 333 | } 334 | if(cannyThresh2Edit->text().isEmpty()) 335 | { 336 | cannyThresh2Edit->setText(QString::number(DEFAULT_CANNY_THRESHOLD_2)); 337 | inputEmpty=true; 338 | } 339 | if(cannyApertureSizeEdit->text().isEmpty()) 340 | { 341 | cannyApertureSizeEdit->setText(QString::number(DEFAULT_CANNY_APERTURE_SIZE)); 342 | inputEmpty=true; 343 | } 344 | if(facedetectScaleEdit->text().isEmpty()) 345 | { 346 | facedetectScaleEdit->setText(QString::number(DEFAULT_FACEDETECT_SCALE)); 347 | inputEmpty=true; 348 | } 349 | // Check if any of the inputs were empty 350 | if(inputEmpty) 351 | QMessageBox::warning(this->parentWidget(),"WARNING:","One or more inputs empty.\n\nAutomatically set to default values."); 352 | 353 | // Check for special parameter case when smoothing type is GAUSSIAN 354 | if((smoothTypeGroup->checkedButton()==(QAbstractButton*)smoothGaussianButton)&& 355 | (smoothParam1Edit->text().toInt()==0)&&(smoothParam3Edit->text().toDouble()==0.00)) 356 | { 357 | smoothParam1Edit->setText(QString::number(DEFAULT_SMOOTH_PARAM_1)); 358 | smoothParam3Edit->setText(QString::number(DEFAULT_SMOOTH_PARAM_3)); 359 | QMessageBox::warning(this->parentWidget(),"ERROR:","Parameters 1 and 3 cannot BOTH be zero when the smoothing type is GAUSSIAN.\n\nAutomatically set to default values."); 360 | } 361 | } // validateDialog() 362 | 363 | void ProcessingSettingsDialog::resetSmoothDialogToDefaults() 364 | { 365 | if(DEFAULT_SMOOTH_TYPE==CV_BLUR_NO_SCALE) 366 | smoothBlurNoScaleButton->setChecked(true); 367 | else if(DEFAULT_SMOOTH_TYPE==CV_BLUR) 368 | smoothBlurButton->setChecked(true); 369 | else if(DEFAULT_SMOOTH_TYPE==CV_GAUSSIAN) 370 | smoothGaussianButton->setChecked(true); 371 | else if(DEFAULT_SMOOTH_TYPE==CV_MEDIAN) 372 | smoothMedianButton->setChecked(true); 373 | smoothParam1Edit->setText(QString::number(DEFAULT_SMOOTH_PARAM_1)); 374 | smoothParam2Edit->setText(QString::number(DEFAULT_SMOOTH_PARAM_2)); 375 | smoothParam3Edit->setText(QString::number(DEFAULT_SMOOTH_PARAM_3)); 376 | smoothParam4Edit->setText(QString::number(DEFAULT_SMOOTH_PARAM_4)); 377 | // Enable/disable appropriate Smooth parameter inputs 378 | smoothTypeChange(smoothTypeGroup->checkedButton()); 379 | } // resetSmoothDialogToDefaults() 380 | 381 | void ProcessingSettingsDialog::resetDilateDialogToDefaults() 382 | { 383 | dilateIterationsEdit->setText(QString::number(DEFAULT_DILATE_ITERATIONS)); 384 | } // resetDilateDialogToDefaults() 385 | 386 | void ProcessingSettingsDialog::resetErodeDialogToDefaults() 387 | { 388 | erodeIterationsEdit->setText(QString::number(DEFAULT_ERODE_ITERATIONS)); 389 | } // resetErodeDialogToDefaults() 390 | 391 | void ProcessingSettingsDialog::resetFlipDialogToDefaults() 392 | { 393 | if(DEFAULT_FLIP_MODE==0) 394 | flipXAxisButton->setChecked(true); 395 | else if(DEFAULT_FLIP_MODE==1) 396 | flipYAxisButton->setChecked(true); 397 | else if(DEFAULT_FLIP_MODE==-1) 398 | flipBothAxesButton->setChecked(true); 399 | } // resetFlipDialogToDefaults() 400 | 401 | void ProcessingSettingsDialog::resetCannyDialogToDefaults() 402 | { 403 | cannyThresh1Edit->setText(QString::number(DEFAULT_CANNY_THRESHOLD_1)); 404 | cannyThresh2Edit->setText(QString::number(DEFAULT_CANNY_THRESHOLD_2)); 405 | cannyApertureSizeEdit->setText(QString::number(DEFAULT_CANNY_APERTURE_SIZE)); 406 | } // resetCannyDialogToDefaults() 407 | 408 | void ProcessingSettingsDialog::resetFaceDetectToDefaults() 409 | { 410 | facedetectScaleEdit->setText(QString::number(DEFAULT_FACEDETECT_SCALE)); 411 | facedetectCascadeFilenameEdit->setText(QString::fromUtf8(DEFAULT_FACEDETECT_CASCADE_FILENAME)); 412 | facedetectNestedCasssscadeFilenameEdit->setText(QString::fromUtf8(DEFAULT_FACEDETECT_NESTED_CASCADE_FILENAME)); 413 | } // resetFaceDetectToDefaults() 414 | 415 | void ProcessingSettingsDialog::chooseFacedetectCascadeFile() 416 | { 417 | QString fileName = QFileDialog::getOpenFileName(this, 418 | tr("Open Front Face Cascade Classifier File"), ".", tr("XML Files (*.xml)")); 419 | if(fileName.isNull()) 420 | { 421 | fileName = QString::fromUtf8(DEFAULT_FACEDETECT_CASCADE_FILENAME); 422 | } 423 | facedetectCascadeFilenameEdit->setText(fileName); 424 | } //chooseFacedetectCascadeFile() 425 | 426 | void ProcessingSettingsDialog::chooseFacedetectNestedCascadeFile() 427 | { 428 | QString fileName = QFileDialog::getOpenFileName(this, 429 | tr("Open Nested Cascade Classifier File"), ".", tr("XML Files (*.xml)")); 430 | if(fileName.isNull()) 431 | { 432 | fileName = QString::fromUtf8(DEFAULT_FACEDETECT_NESTED_CASCADE_FILENAME); 433 | } 434 | facedetectNestedCasssscadeFilenameEdit->setText(fileName); 435 | } 436 | -------------------------------------------------------------------------------- /ProcessingSettingsDialog.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* ProcessingSettingsDialog.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef PROCESSINGSETTINGSDIALOG_H 34 | #define PROCESSINGSETTINGSDIALOG_H 35 | 36 | #include "ui_ProcessingSettingsDialog.h" 37 | #include "Structures.h" 38 | 39 | class ProcessingSettingsDialog : public QDialog, private Ui::ProcessingSettingsDialog 40 | { 41 | Q_OBJECT 42 | 43 | public: 44 | ProcessingSettingsDialog(QWidget *parent = 0); 45 | void updateDialogSettingsFromStored(); 46 | private: 47 | ProcessingSettings processingSettings; 48 | public slots: 49 | void updateStoredSettingsFromDialog(); 50 | private slots: 51 | void resetAllDialogToDefaults(); 52 | void resetSmoothDialogToDefaults(); 53 | void resetDilateDialogToDefaults(); 54 | void resetErodeDialogToDefaults(); 55 | void resetFlipDialogToDefaults(); 56 | void resetCannyDialogToDefaults(); 57 | void resetFaceDetectToDefaults(); 58 | void validateDialog(); 59 | void smoothTypeChange(QAbstractButton*); 60 | void chooseFacedetectCascadeFile(); 61 | void chooseFacedetectNestedCascadeFile(); 62 | signals: 63 | void newProcessingSettings(struct ProcessingSettings p_settings); 64 | }; 65 | 66 | #endif // PROCESSINGSETTINGSDIALOG_H 67 | -------------------------------------------------------------------------------- /ProcessingSettingsDialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ProcessingSettingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 441 10 | 381 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | 21 | 0 22 | 0 23 | 24 | 25 | 26 | Processing Settings 27 | 28 | 29 | 30 | 31 | 11 32 | 11 33 | 421 34 | 361 35 | 36 | 37 | 38 | 39 | 40 | 41 | 5 42 | 43 | 44 | 45 | Smooth 46 | 47 | 48 | 49 | 50 | 10 51 | 10 52 | 401 53 | 225 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 0 66 | 0 67 | 68 | 69 | 70 | 71 | 0 72 | 27 73 | 74 | 75 | 76 | 77 | 16777215 78 | 27 79 | 80 | 81 | 82 | 83 | 8 84 | 75 85 | true 86 | 87 | 88 | 89 | Type: 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 8 100 | 101 | 102 | 103 | Blur (no scale) 104 | 105 | 106 | smoothTypeGroup 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 8 115 | 116 | 117 | 118 | Blur 119 | 120 | 121 | smoothTypeGroup 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 8 130 | 131 | 132 | 133 | Gaussian 134 | 135 | 136 | smoothTypeGroup 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 8 145 | 146 | 147 | 148 | Median 149 | 150 | 151 | smoothTypeGroup 152 | 153 | 154 | 155 | 156 | 157 | 158 | Qt::Vertical 159 | 160 | 161 | 162 | 20 163 | 40 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 0 179 | 27 180 | 181 | 182 | 183 | 184 | 16777215 185 | 27 186 | 187 | 188 | 189 | 190 | 8 191 | 75 192 | true 193 | 194 | 195 | 196 | Parameters: 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 0 209 | 0 210 | 211 | 212 | 213 | 214 | 20 215 | 0 216 | 217 | 218 | 219 | 220 | 20 221 | 16777215 222 | 223 | 224 | 225 | 226 | 8 227 | 228 | 229 | 230 | 1: 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 0 239 | 0 240 | 241 | 242 | 243 | 244 | 50 245 | 0 246 | 247 | 248 | 249 | 250 | 50 251 | 16777215 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 8 261 | 75 262 | true 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 0 279 | 0 280 | 281 | 282 | 283 | 284 | 20 285 | 0 286 | 287 | 288 | 289 | 290 | 20 291 | 16777215 292 | 293 | 294 | 295 | 296 | 8 297 | 298 | 299 | 300 | 2: 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 0 309 | 0 310 | 311 | 312 | 313 | 314 | 50 315 | 0 316 | 317 | 318 | 319 | 320 | 50 321 | 16777215 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 8 331 | 75 332 | true 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 0 349 | 0 350 | 351 | 352 | 353 | 354 | 20 355 | 0 356 | 357 | 358 | 359 | 360 | 20 361 | 16777215 362 | 363 | 364 | 365 | 366 | 8 367 | 368 | 369 | 370 | 3: 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 0 379 | 0 380 | 381 | 382 | 383 | 384 | 50 385 | 0 386 | 387 | 388 | 389 | 390 | 50 391 | 16777215 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 8 401 | 75 402 | true 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 0 419 | 0 420 | 421 | 422 | 423 | 424 | 20 425 | 0 426 | 427 | 428 | 429 | 430 | 20 431 | 16777215 432 | 433 | 434 | 435 | 436 | 8 437 | 438 | 439 | 440 | 4: 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 0 449 | 0 450 | 451 | 452 | 453 | 454 | 50 455 | 0 456 | 457 | 458 | 459 | 460 | 50 461 | 16777215 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 8 471 | 75 472 | true 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | Qt::Vertical 486 | 487 | 488 | 489 | 20 490 | 40 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | Qt::Vertical 505 | 506 | 507 | 508 | 20 509 | 40 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | Reset to Defaults 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | Dilate 527 | 528 | 529 | 530 | 531 | 10 532 | 10 533 | 401 534 | 221 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 8 545 | 75 546 | true 547 | 548 | 549 | 550 | Number of iterations: 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 0 559 | 0 560 | 561 | 562 | 563 | 564 | 50 565 | 0 566 | 567 | 568 | 569 | 570 | 50 571 | 16777215 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 8 581 | 75 582 | true 583 | 584 | 585 | 586 | [1-99] 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | Qt::Vertical 596 | 597 | 598 | 599 | 20 600 | 40 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | Reset to Defaults 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | Erode 618 | 619 | 620 | 621 | 622 | 10 623 | 10 624 | 401 625 | 221 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 8 636 | 75 637 | true 638 | 639 | 640 | 641 | Number of iterations: 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 0 650 | 0 651 | 652 | 653 | 654 | 655 | 50 656 | 0 657 | 658 | 659 | 660 | 661 | 50 662 | 16777215 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 8 672 | 75 673 | true 674 | 675 | 676 | 677 | [1-99] 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | Qt::Vertical 687 | 688 | 689 | 690 | 20 691 | 40 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | Reset to Defaults 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | Flip 709 | 710 | 711 | 712 | 713 | 10 714 | 10 715 | 401 716 | 221 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 0 727 | 0 728 | 729 | 730 | 731 | 732 | 0 733 | 27 734 | 735 | 736 | 737 | 738 | 16777215 739 | 27 740 | 741 | 742 | 743 | 744 | 8 745 | 75 746 | true 747 | 748 | 749 | 750 | Mode: 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 8 759 | 760 | 761 | 762 | X-axis 763 | 764 | 765 | flipModeGroup 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 8 774 | 775 | 776 | 777 | Y-axis 778 | 779 | 780 | flipModeGroup 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 8 789 | 790 | 791 | 792 | Both axes 793 | 794 | 795 | flipModeGroup 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | Qt::Vertical 805 | 806 | 807 | 808 | 20 809 | 40 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | Reset to Defaults 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | Canny 827 | 828 | 829 | 830 | 831 | 10 832 | 10 833 | 401 834 | 221 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 8 845 | 75 846 | true 847 | 848 | 849 | 850 | Threshold 1: 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 0 859 | 0 860 | 861 | 862 | 863 | 864 | 50 865 | 0 866 | 867 | 868 | 869 | 870 | 50 871 | 16777215 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 8 881 | 75 882 | true 883 | 884 | 885 | 886 | [0-999] 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 8 899 | 75 900 | true 901 | 902 | 903 | 904 | Threshold 2: 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 0 913 | 0 914 | 915 | 916 | 917 | 918 | 50 919 | 0 920 | 921 | 922 | 923 | 924 | 50 925 | 16777215 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 8 935 | 75 936 | true 937 | 938 | 939 | 940 | [0-999] 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 8 953 | 75 954 | true 955 | 956 | 957 | 958 | Aperture Size: 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 0 967 | 0 968 | 969 | 970 | 971 | 972 | 50 973 | 0 974 | 975 | 976 | 977 | 978 | 50 979 | 16777215 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 8 989 | 75 990 | true 991 | 992 | 993 | 994 | [3/5/7] 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | Qt::Vertical 1004 | 1005 | 1006 | 1007 | 20 1008 | 40 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | Reset to Defaults 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | Facedetect 1026 | 1027 | 1028 | 1029 | 1030 | 10 1031 | 10 1032 | 401 1033 | 226 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 8 1044 | 75 1045 | true 1046 | 1047 | 1048 | 1049 | Scale: 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 0 1058 | 0 1059 | 1060 | 1061 | 1062 | 1063 | 50 1064 | 0 1065 | 1066 | 1067 | 1068 | 1069 | 50 1070 | 16777215 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 8 1080 | 75 1081 | true 1082 | 1083 | 1084 | 1085 | [1.0 - 2.0] 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | Front Face Cascade Classifier File: 1095 | 1096 | 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | Choose... 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | Nested Cascade Classifire File: 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | Choose... 1128 | 1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | Qt::Vertical 1137 | 1138 | 1139 | 1140 | 20 1141 | 40 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | Reset to Defaults 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | Qt::Horizontal 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | Apply 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | 1177 | Reset All to Defaults 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | Qt::Horizontal 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | Qt::Horizontal 1194 | 1195 | 1196 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | tabWidget 1205 | smoothBlurNoScaleButton 1206 | smoothBlurButton 1207 | smoothGaussianButton 1208 | smoothMedianButton 1209 | smoothParam1Edit 1210 | smoothParam2Edit 1211 | smoothParam3Edit 1212 | smoothParam4Edit 1213 | resetSmoothToDefaultsButton 1214 | dilateIterationsEdit 1215 | resetDilateToDefaultsButton 1216 | erodeIterationsEdit 1217 | resetErodeToDefaultsButton 1218 | flipXAxisButton 1219 | flipYAxisButton 1220 | flipBothAxesButton 1221 | resetFlipToDefaultsButton 1222 | cannyThresh1Edit 1223 | cannyThresh2Edit 1224 | cannyApertureSizeEdit 1225 | resetCannyToDefaultsButton 1226 | applyButton 1227 | resetAllToDefaultsButton 1228 | okCancelBox 1229 | 1230 | 1231 | 1232 | 1233 | okCancelBox 1234 | accepted() 1235 | ProcessingSettingsDialog 1236 | accept() 1237 | 1238 | 1239 | 430 1240 | 136 1241 | 1242 | 1243 | 157 1244 | 274 1245 | 1246 | 1247 | 1248 | 1249 | okCancelBox 1250 | rejected() 1251 | ProcessingSettingsDialog 1252 | reject() 1253 | 1254 | 1255 | 430 1256 | 136 1257 | 1258 | 1259 | 286 1260 | 274 1261 | 1262 | 1263 | 1264 | 1265 | 1266 | 1267 | 1268 | 1269 | 1270 | -------------------------------------------------------------------------------- /ProcessingThread.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* ProcessingThread.cpp */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #include "ImageBuffer.h" 34 | #include "ProcessingThread.h" 35 | #include "ShowIplImage.h" 36 | #include "FaceDetect.h" 37 | 38 | // Qt header files 39 | #include 40 | // OpenCV header files 41 | #include 42 | #include 43 | // Header file containing default values 44 | #include "DefaultValues.h" 45 | 46 | ProcessingThread::ProcessingThread(ImageBuffer *imageBuffer, int inputSourceWidth, int inputSourceHeight) 47 | : QThread(), imageBuffer(imageBuffer), inputSourceWidth(inputSourceWidth), 48 | inputSourceHeight(inputSourceHeight) 49 | { 50 | // Create IplImages 51 | currentFrameCopy=cvCreateImage(cvSize(inputSourceWidth,inputSourceHeight),IPL_DEPTH_8U,3); 52 | currentFrameCopyGrayscale=cvCreateImage(cvSize(inputSourceWidth,inputSourceHeight),IPL_DEPTH_8U,1); 53 | // Initialize variables 54 | stopped=false; 55 | sampleNo=0; 56 | fpsSum=0; 57 | avgFPS=0; 58 | fps.clear(); 59 | // Initialize processing flags 60 | grayscaleOn=false; 61 | smoothOn=false; 62 | dilateOn=false; 63 | erodeOn=false; 64 | flipOn=false; 65 | cannyOn=false; 66 | facedetectOn=false; 67 | // Initialize task flags 68 | setROIFlag=false; 69 | resetROIFlag=false; 70 | // Initialize processing settings 71 | smoothType=DEFAULT_SMOOTH_TYPE; 72 | smoothParam1=DEFAULT_SMOOTH_PARAM_1; 73 | smoothParam2=DEFAULT_SMOOTH_PARAM_2; 74 | smoothParam3=DEFAULT_SMOOTH_PARAM_3; 75 | smoothParam4=DEFAULT_SMOOTH_PARAM_4; 76 | dilateNumberOfIterations=DEFAULT_DILATE_ITERATIONS; 77 | erodeNumberOfIterations=DEFAULT_ERODE_ITERATIONS; 78 | flipMode=DEFAULT_FLIP_MODE; 79 | cannyThreshold1=DEFAULT_CANNY_THRESHOLD_1; 80 | cannyThreshold2=DEFAULT_CANNY_THRESHOLD_2; 81 | cannyApertureSize=DEFAULT_CANNY_APERTURE_SIZE; 82 | facedetectScale=DEFAULT_FACEDETECT_SCALE; 83 | facedetectCascadeFile.load(DEFAULT_FACEDETECT_CASCADE_FILENAME); 84 | facedetectNestedCascadeFile.load(DEFAULT_FACEDETECT_NESTED_CASCADE_FILENAME); 85 | // Initialize currentROI variable 86 | currentROI=cvRect(0,0,inputSourceWidth,inputSourceHeight); 87 | // Store original ROI 88 | originalROI=currentROI; 89 | } // ProcessingThread constructor 90 | 91 | ProcessingThread::~ProcessingThread() 92 | { 93 | // Free IplImages (if they exist) 94 | if(currentFrameCopy!=NULL) 95 | cvReleaseImage(¤tFrameCopy); 96 | if(currentFrameCopyGrayscale!=NULL) 97 | cvReleaseImage(¤tFrameCopyGrayscale); 98 | } // ProcessingThread destructor 99 | 100 | void ProcessingThread::run() 101 | { 102 | while(1) 103 | { 104 | ///////////////////////////////// 105 | // Stop thread if stopped=TRUE // 106 | ///////////////////////////////// 107 | stoppedMutex.lock(); 108 | if (stopped) 109 | { 110 | stopped=false; 111 | stoppedMutex.unlock(); 112 | break; 113 | } 114 | stoppedMutex.unlock(); 115 | ///////////////////////////////// 116 | ///////////////////////////////// 117 | // Save processing time 118 | processingTime=t.elapsed(); 119 | // Start timer (used to calculate processing rate) 120 | t.start(); 121 | // Get frame from queue 122 | IplImage* currentFrame = imageBuffer->getFrame(); 123 | // Check that grabbed frame is not a NULL image 124 | if(currentFrame!=NULL) 125 | { 126 | // Set ROI of grabbed frame 127 | cvSetImageROI(currentFrame,currentROI); 128 | // Make copy of current frame (processing will be performed on this copy) 129 | cvCopy(currentFrame,currentFrameCopy); 130 | /////////////////// 131 | // PERFORM TASKS // 132 | /////////////////// 133 | updateMembersMutex.lock(); 134 | if(resetROIFlag) 135 | resetROI(); 136 | else if(setROIFlag) 137 | setROI(); 138 | //////////////////////////////////// 139 | // PERFORM IMAGE PROCESSING BELOW // 140 | //////////////////////////////////// 141 | else 142 | { 143 | // Grayscale conversion 144 | if(grayscaleOn) 145 | cvCvtColor(currentFrameCopy,currentFrameCopyGrayscale,CV_BGR2GRAY); 146 | // Smooth 147 | if(smoothOn) 148 | { 149 | if(grayscaleOn) 150 | cvSmooth(currentFrameCopyGrayscale,currentFrameCopyGrayscale, 151 | smoothType,smoothParam1,smoothParam2,smoothParam3,smoothParam4); 152 | else 153 | cvSmooth(currentFrameCopy,currentFrameCopy, 154 | smoothType,smoothParam1,smoothParam2,smoothParam3,smoothParam4); 155 | } // if 156 | // Dilate 157 | if(dilateOn) 158 | { 159 | if(grayscaleOn) 160 | cvDilate(currentFrameCopyGrayscale,currentFrameCopyGrayscale,NULL, 161 | dilateNumberOfIterations); 162 | else 163 | cvDilate(currentFrameCopy,currentFrameCopy,NULL, 164 | dilateNumberOfIterations); 165 | } // if 166 | // Erode 167 | if(erodeOn) 168 | { 169 | if(grayscaleOn) 170 | cvErode(currentFrameCopyGrayscale,currentFrameCopyGrayscale,NULL, 171 | erodeNumberOfIterations); 172 | else 173 | cvErode(currentFrameCopy,currentFrameCopy,NULL, 174 | erodeNumberOfIterations); 175 | } // if 176 | // Flip 177 | if(flipOn) 178 | { 179 | if(grayscaleOn) 180 | cvFlip(currentFrameCopyGrayscale,NULL,flipMode); 181 | else 182 | cvFlip(currentFrameCopy,NULL,flipMode); 183 | } // if 184 | // Canny edge detection 185 | if(cannyOn) 186 | { 187 | // Frame must be converted to grayscale first if grayscale conversion is OFF 188 | if(!grayscaleOn) 189 | cvCvtColor(currentFrameCopy,currentFrameCopyGrayscale,CV_BGR2GRAY); 190 | 191 | cvCanny(currentFrameCopyGrayscale,currentFrameCopyGrayscale, 192 | cannyThreshold1,cannyThreshold2, 193 | cannyApertureSize); 194 | } // if 195 | // facedetect 196 | if(facedetectOn) 197 | { 198 | if(facedetectCascadeFile.empty()) 199 | qDebug() << "ERROR: cascade file missed."; 200 | if(facedetectNestedCascadeFile.empty()) 201 | qDebug() << "ERROR: nested cascade file missed."; 202 | faceDetect(currentFrameCopy, facedetectCascadeFile, facedetectNestedCascadeFile, facedetectScale); 203 | } // if 204 | } // else 205 | //////////////////////////////////// 206 | // PERFORM IMAGE PROCESSING ABOVE // 207 | //////////////////////////////////// 208 | 209 | //// Convert IplImage to QImage: Show grayscale frame 210 | //// (if either Grayscale or Canny processing modes are ON) 211 | if(grayscaleOn||cannyOn) 212 | frame=IplImageToQImage(currentFrameCopyGrayscale); 213 | //// Convert IplImage to QImage: Show BGR frame 214 | else 215 | frame=IplImageToQImage(currentFrameCopy); 216 | updateMembersMutex.unlock(); 217 | // Update statistics 218 | updateFPS(processingTime); 219 | currentSizeOfBuffer=imageBuffer->getSizeOfImageBuffer(); 220 | // Inform controller of new frame (QImage) 221 | emit newFrame(frame); 222 | // Release IplImage 223 | if(currentFrame!=NULL) 224 | cvReleaseImage(¤tFrame); 225 | } // if 226 | else 227 | qDebug() << "ERROR: Processing thread received a NULL image."; 228 | } // while 229 | qDebug() << "Stopping processing thread..."; 230 | } // run() 231 | 232 | void ProcessingThread::updateFPS(int timeElapsed) 233 | { 234 | // Add instantaneous FPS value to queue 235 | if(timeElapsed>0) 236 | { 237 | fps.enqueue((int)1000/timeElapsed); 238 | // Increment sample number 239 | sampleNo++; 240 | } // if 241 | // Maximum size of queue is 16 242 | if(fps.size() > 16) 243 | fps.dequeue(); 244 | // Update FPS value every 16 samples 245 | if((fps.size()==16)&&(sampleNo==16)) 246 | { 247 | // Empty queue and store sum 248 | while(!fps.empty()) 249 | fpsSum+=fps.dequeue(); 250 | avgFPS=fpsSum/16; // Calculate average FPS 251 | fpsSum=0; // Reset sum 252 | sampleNo=0; // Reset sample number 253 | } // if 254 | } // updateFPS() 255 | 256 | void ProcessingThread::stopProcessingThread() 257 | { 258 | stoppedMutex.lock(); 259 | stopped=true; 260 | stoppedMutex.unlock(); 261 | } // stopProcessingThread() 262 | 263 | void ProcessingThread::setROI() 264 | { 265 | // Set area outside ROI in currentFrameCopy to blue 266 | cvSet(currentFrameCopy, cvScalar(127,0,0)); 267 | // Set area outside ROI in currentFrameCopyGrayscale to gray 268 | cvSet(currentFrameCopyGrayscale, cvScalar(127,0,0)); 269 | // Store new ROI in currentROI variable 270 | currentROI=selectionBox; 271 | // Set new ROIs 272 | cvSetImageROI(currentFrameCopy, currentROI); 273 | cvSetImageROI(currentFrameCopyGrayscale, currentROI); 274 | qDebug() << "ROI successfully SET."; 275 | // Reset setROIOn flag to FALSE 276 | setROIFlag=false; 277 | } // setROI() 278 | 279 | void ProcessingThread::resetROI() 280 | { 281 | // Reset ROIs 282 | cvResetImageROI(currentFrameCopy); 283 | cvResetImageROI(currentFrameCopyGrayscale); 284 | // Set ROI back to original ROI 285 | currentROI=originalROI; 286 | qDebug() << "ROI successfully RESET."; 287 | // Reset resetROIOn flag to FALSE 288 | resetROIFlag=false; 289 | } // resetROI() 290 | 291 | void ProcessingThread::updateProcessingFlags(struct ProcessingFlags processingFlags) 292 | { 293 | QMutexLocker locker(&updateMembersMutex); 294 | this->grayscaleOn=processingFlags.grayscaleOn; 295 | this->smoothOn=processingFlags.smoothOn; 296 | this->dilateOn=processingFlags.dilateOn; 297 | this->erodeOn=processingFlags.erodeOn; 298 | this->flipOn=processingFlags.flipOn; 299 | this->cannyOn=processingFlags.cannyOn; 300 | this->facedetectOn=processingFlags.facedetectOn; 301 | } // updateProcessingFlags() 302 | 303 | void ProcessingThread::updateProcessingSettings(struct ProcessingSettings processingSettings) 304 | { 305 | QMutexLocker locker(&updateMembersMutex); 306 | this->smoothType=processingSettings.smoothType; 307 | this->smoothParam1=processingSettings.smoothParam1; 308 | this->smoothParam2=processingSettings.smoothParam2; 309 | this->smoothParam3=processingSettings.smoothParam3; 310 | this->smoothParam4=processingSettings.smoothParam4; 311 | this->dilateNumberOfIterations=processingSettings.dilateNumberOfIterations; 312 | this->erodeNumberOfIterations=processingSettings.erodeNumberOfIterations; 313 | this->flipMode=processingSettings.flipMode; 314 | this->cannyThreshold1=processingSettings.cannyThreshold1; 315 | this->cannyThreshold2=processingSettings.cannyThreshold2; 316 | this->cannyApertureSize=processingSettings.cannyApertureSize; 317 | this->facedetectScale=processingSettings.facedetectScale; 318 | this->facedetectCascadeFile=processingSettings.facedetectCascadeFile; 319 | this->facedetectNestedCascadeFile=processingSettings.facedetectNestedCascadeFile; 320 | } // updateProcessingSettings() 321 | 322 | void ProcessingThread::updateTaskData(struct TaskData taskData) 323 | { 324 | QMutexLocker locker(&updateMembersMutex); 325 | this->setROIFlag=taskData.setROIFlag; 326 | this->resetROIFlag=taskData.resetROIFlag; 327 | this->selectionBox.x=taskData.selectionBox.left(); 328 | this->selectionBox.y=taskData.selectionBox.top(); 329 | this->selectionBox.width=taskData.selectionBox.width(); 330 | this->selectionBox.height=taskData.selectionBox.height(); 331 | } // updateTaskData() 332 | 333 | int ProcessingThread::getAvgFPS() 334 | { 335 | return avgFPS; 336 | } // getAvgFPS() 337 | 338 | int ProcessingThread::getCurrentSizeOfBuffer() 339 | { 340 | return currentSizeOfBuffer; 341 | } // getCurrentSizeOfBuffer() 342 | 343 | CvRect ProcessingThread::getCurrentROI() 344 | { 345 | return currentROI; 346 | } // getCurrentROI(); 347 | -------------------------------------------------------------------------------- /ProcessingThread.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* ProcessingThead.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef PROCESSINGTHREAD_H 34 | #define PROCESSINGTHREAD_H 35 | 36 | #include "Structures.h" 37 | 38 | // Qt header files 39 | #include 40 | #include 41 | // OpenCV header files 42 | #include 43 | #include 44 | 45 | class ImageBuffer; 46 | 47 | class ProcessingThread : public QThread 48 | { 49 | Q_OBJECT 50 | 51 | public: 52 | ProcessingThread(ImageBuffer *imageBuffer, int inputSourceWidth, int inputSourceHeight); 53 | ~ProcessingThread(); 54 | void stopProcessingThread(); 55 | int getAvgFPS(); 56 | int getCurrentSizeOfBuffer(); 57 | CvRect getCurrentROI(); 58 | private: 59 | void updateFPS(int); 60 | void setROI(); 61 | void resetROI(); 62 | ImageBuffer *imageBuffer; 63 | volatile bool stopped; 64 | int inputSourceWidth; 65 | int inputSourceHeight; 66 | int currentSizeOfBuffer; 67 | IplImage *currentFrameCopy; 68 | IplImage *currentFrameCopyGrayscale; 69 | CvRect originalROI; 70 | CvRect currentROI; 71 | QImage frame; 72 | QTime t; 73 | int processingTime; 74 | QQueue fps; 75 | int fpsSum; 76 | int sampleNo; 77 | int avgFPS; 78 | QMutex stoppedMutex; 79 | QMutex updateMembersMutex; 80 | // Processing flags 81 | bool grayscaleOn; 82 | bool smoothOn; 83 | bool dilateOn; 84 | bool erodeOn; 85 | bool flipOn; 86 | bool cannyOn; 87 | bool facedetectOn; 88 | // Processing settings 89 | int smoothType; 90 | int smoothParam1; 91 | int smoothParam2; 92 | double smoothParam3; 93 | double smoothParam4; 94 | int dilateNumberOfIterations; 95 | int erodeNumberOfIterations; 96 | int flipMode; 97 | double cannyThreshold1; 98 | double cannyThreshold2; 99 | int cannyApertureSize; 100 | double facedetectScale; 101 | cv::CascadeClassifier facedetectCascadeFile; 102 | cv::CascadeClassifier facedetectNestedCascadeFile; 103 | // Task data 104 | bool setROIFlag; 105 | bool resetROIFlag; 106 | CvRect selectionBox; 107 | protected: 108 | void run(); 109 | private slots: 110 | void updateProcessingFlags(struct ProcessingFlags); 111 | void updateProcessingSettings(struct ProcessingSettings); 112 | void updateTaskData(struct TaskData); 113 | signals: 114 | void newFrame(const QImage &frame); 115 | }; 116 | 117 | #endif // PROCESSINGTHREAD_H 118 | -------------------------------------------------------------------------------- /ShowIplImage.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* ShowIplImage.cpp */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #include "ShowIplImage.h" 34 | 35 | QImage IplImageToQImage(const IplImage *iplImage) 36 | { 37 | // Local variables 38 | int height = iplImage->height; 39 | int width = iplImage->width; 40 | // PIXEL DEPTH=8-bits unsigned, NO. OF CHANNELS=1 41 | if(iplImage->depth == IPL_DEPTH_8U && iplImage->nChannels == 1) 42 | { 43 | // Set the color table (used to translate colour indexes to qRgb values) 44 | QVector colorTable; 45 | for (int i=0; i<256; i++) 46 | colorTable.push_back(qRgb(i,i,i)); 47 | // Copy input IplImage 48 | const uchar *qImageBuffer = (const uchar*)iplImage->imageData; 49 | // Create QImage with same dimensions as input IplImage 50 | QImage img(qImageBuffer, width, height, QImage::Format_Indexed8); 51 | img.setColorTable(colorTable); 52 | return img; 53 | } 54 | // PIXEL DEPTH=8-bits unsigned, NO. OF CHANNELS=3 55 | else if(iplImage->depth == IPL_DEPTH_8U && iplImage->nChannels == 3) 56 | { 57 | // Copy input IplImage 58 | const uchar *qImageBuffer = (const uchar*)iplImage->imageData; 59 | // Create QImage with same dimensions as input IplImage 60 | QImage img(qImageBuffer, width, height, QImage::Format_RGB888); 61 | return img.rgbSwapped(); 62 | } 63 | else 64 | { 65 | qDebug() << "ERROR: IplImage could not be converted to QImage."; 66 | return QImage(); 67 | } 68 | } // IplImageToQImage() 69 | -------------------------------------------------------------------------------- /ShowIplImage.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* ShowIplImage.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef SHOWIPLIMAGE_H 34 | #define SHOWIPLIMAGE_H 35 | 36 | // Qt header files 37 | #include 38 | #include 39 | // OpenCV header files 40 | #include 41 | 42 | QImage IplImageToQImage(const IplImage*); 43 | 44 | #endif // SHOWIPLIMAGE_H 45 | -------------------------------------------------------------------------------- /Structures.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* Structures.h */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #ifndef STRUCTURES_H 34 | #define STRUCTURES_H 35 | 36 | // Qt header files 37 | #include 38 | #include 39 | 40 | // ProcessingSettings structure definition 41 | struct ProcessingSettings{ 42 | int smoothType; 43 | int smoothParam1; 44 | int smoothParam2; 45 | double smoothParam3; 46 | double smoothParam4; 47 | int dilateNumberOfIterations; 48 | int erodeNumberOfIterations; 49 | int flipMode; 50 | double cannyThreshold1; 51 | double cannyThreshold2; 52 | int cannyApertureSize; 53 | double facedetectScale; 54 | QString facedetectCascadeFilename; 55 | QString facedetectNestedCascadeFilename; 56 | cv::CascadeClassifier facedetectCascadeFile; 57 | cv::CascadeClassifier facedetectNestedCascadeFile; 58 | }; 59 | 60 | // ProcessingFlags structure definition 61 | struct ProcessingFlags{ 62 | bool grayscaleOn; 63 | bool smoothOn; 64 | bool dilateOn; 65 | bool erodeOn; 66 | bool flipOn; 67 | bool cannyOn; 68 | bool facedetectOn; 69 | }; 70 | 71 | // TaskData structure definition 72 | struct TaskData{ 73 | QRect selectionBox; 74 | bool setROIFlag; 75 | bool resetROIFlag; 76 | }; 77 | 78 | // MouseData structure definition 79 | struct MouseData{ 80 | QRect selectionBox; 81 | bool leftButtonRelease; 82 | bool rightButtonRelease; 83 | }; 84 | 85 | #endif // STRUCTURES_H 86 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /* qt-opencv-multithreaded: */ 3 | /* A multithreaded OpenCV application using the Qt framework. */ 4 | /* */ 5 | /* main.cpp */ 6 | /* */ 7 | /* Nick D'Ademo */ 8 | /* */ 9 | /* Copyright (c) 2011 Nick D'Ademo */ 10 | /* */ 11 | /* Permission is hereby granted, free of charge, to any person */ 12 | /* obtaining a copy of this software and associated documentation */ 13 | /* files (the "Software"), to deal in the Software without restriction, */ 14 | /* including without limitation the rights to use, copy, modify, merge, */ 15 | /* publish, distribute, sublicense, and/or sell copies of the Software, */ 16 | /* and to permit persons to whom the Software is furnished to do so, */ 17 | /* subject to the following conditions: */ 18 | /* */ 19 | /* The above copyright notice and this permission notice shall be */ 20 | /* included in all copies or substantial portions of the Software. */ 21 | /* */ 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 25 | /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ 26 | /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ 27 | /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ 28 | /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ 29 | /* SOFTWARE. */ 30 | /* */ 31 | /************************************************************************/ 32 | 33 | #include "MainWindow.h" 34 | 35 | // Qt header files 36 | #include 37 | 38 | #define X_INITIAL 0 39 | #define Y_INITIAL 0 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | QApplication a(argc, argv); 44 | a.setApplicationVersion(QUOTE(APP_VERSION)); 45 | MainWindow w; 46 | w.show(); 47 | // Set the initial screen position of the main window 48 | w.setGeometry(X_INITIAL, Y_INITIAL, w.width(), w.height()); 49 | return a.exec(); 50 | } // main() 51 | -------------------------------------------------------------------------------- /qt-opencv-multithreaded.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | TARGET = qt-opencv-multithreaded 4 | TEMPLATE = app 5 | 6 | VERSION = 1.12 7 | 8 | DEFINES += APP_VERSION=$$VERSION 9 | 10 | FORMS = CameraConnectDialog.ui MainWindow.ui ProcessingSettingsDialog.ui 11 | 12 | SOURCES += main.cpp\ 13 | MainWindow.cpp \ 14 | CaptureThread.cpp \ 15 | Controller.cpp \ 16 | ImageBuffer.cpp \ 17 | CameraConnectDialog.cpp \ 18 | ProcessingThread.cpp \ 19 | ShowIplImage.cpp \ 20 | FrameLabel.cpp \ 21 | ProcessingSettingsDialog.cpp \ 22 | FaceDetect.cpp 23 | 24 | HEADERS += MainWindow.h \ 25 | CaptureThread.h \ 26 | Controller.h \ 27 | ImageBuffer.h \ 28 | CameraConnectDialog.h \ 29 | DefaultValues.h \ 30 | ProcessingThread.h \ 31 | ShowIplImage.h \ 32 | FrameLabel.h \ 33 | ProcessingSettingsDialog.h \ 34 | Structures.h \ 35 | FaceDetect.h 36 | 37 | LIBS += -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -lopencv_flann 38 | -------------------------------------------------------------------------------- /qt-opencv-multithreaded.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ProjectExplorer.Project.ActiveTarget 5 | 0 6 | 7 | 8 | ProjectExplorer.Project.EditorSettings 9 | 10 | Default 11 | 12 | 13 | 14 | ProjectExplorer.Project.Target.0 15 | 16 | Desktop 17 | 18 | Qt4ProjectManager.Target.DesktopTarget 19 | 0 20 | 0 21 | 0 22 | 23 | 24 | 25 | qmake 26 | 27 | QtProjectManager.QMakeBuildStep 28 | 29 | 30 | 31 | Make 32 | 33 | Qt4ProjectManager.MakeStep 34 | false 35 | 36 | 37 | 38 | 2 39 | Build 40 | 41 | ProjectExplorer.BuildSteps.Build 42 | 43 | 44 | 45 | Make 46 | 47 | Qt4ProjectManager.MakeStep 48 | true 49 | 50 | clean 51 | 52 | 53 | 54 | 1 55 | Clean 56 | 57 | ProjectExplorer.BuildSteps.Clean 58 | 59 | 2 60 | false 61 | 62 | LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH 63 | 64 | Release 65 | 66 | Qt4ProjectManager.Qt4BuildConfiguration 67 | 0 68 | /home/cynic/Projects/facerec/src/qt-opencv-out 69 | 2 70 | 0 71 | true 72 | 73 | 74 | 75 | 76 | qmake 77 | 78 | QtProjectManager.QMakeBuildStep 79 | 80 | 81 | 82 | Make 83 | 84 | Qt4ProjectManager.MakeStep 85 | false 86 | 87 | 88 | 89 | 2 90 | Build 91 | 92 | ProjectExplorer.BuildSteps.Build 93 | 94 | 95 | 96 | Make 97 | 98 | Qt4ProjectManager.MakeStep 99 | true 100 | 101 | clean 102 | 103 | 104 | 105 | 1 106 | Clean 107 | 108 | ProjectExplorer.BuildSteps.Clean 109 | 110 | 2 111 | false 112 | 113 | Debug 114 | 115 | Qt4ProjectManager.Qt4BuildConfiguration 116 | 2 117 | /home/cynic/Projects/facerec/src/qt-opencv-multithreaded-build-desktop 118 | 2 119 | 0 120 | true 121 | 122 | 2 123 | 124 | 125 | 0 126 | Deploy 127 | 128 | ProjectExplorer.BuildSteps.Deploy 129 | 130 | 1 131 | No deployment 132 | 133 | ProjectExplorer.DefaultDeployConfiguration 134 | 135 | 1 136 | 137 | qt-opencv-multithreaded 138 | 139 | Qt4ProjectManager.Qt4RunConfiguration 140 | 2 141 | 142 | qt-opencv-multithreaded.pro 143 | false 144 | false 145 | 146 | false 147 | 148 | 3768 149 | true 150 | false 151 | 152 | 1 153 | 154 | 155 | 156 | ProjectExplorer.Project.TargetCount 157 | 1 158 | 159 | 160 | ProjectExplorer.Project.Updater.EnvironmentId 161 | {535b7ea9-39d7-47f0-85ab-b80952f92244} 162 | 163 | 164 | ProjectExplorer.Project.Updater.FileVersion 165 | 8 166 | 167 | 168 | --------------------------------------------------------------------------------