/************************************************************************/ /* qt-opencv-opencl-opengl-multithreaded: */ /* A multithreaded OpenCV application using the Qt framework. */ /* */ /* MainWindow.cpp */ /* */ /* Nick D'Ademo */ /* */ /* Copyright (c) 2012-2013 Nick D'Ademo */ /* */ /* Permission is hereby granted, free of charge, to any person */ /* obtaining a copy of this software and associated documentation */ /* files (the "Software"), to deal in the Software without restriction, */ /* including without limitation the rights to use, copy, modify, merge, */ /* publish, distribute, sublicense, and/or sell copies of the Software, */ /* and to permit persons to whom the Software is furnished to do so, */ /* subject to the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ /* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ /* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ /* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ /* SOFTWARE. */ /* */ /************************************************************************/ #include "MainWindow.h" #include "ui_MainWindow.h" // Qt #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { // Setup UI ui->setupUi(this); // Set start tab as blank QLabel *newTab = new QLabel(ui->tabWidget); newTab->setText("No camera connected at the moment. After connecting to a camera,\nyou can right-click on Camera View to get the list of image processing options:\nflip, erode, dilute, smooth, Canny edge and Hand Gesture detection."); newTab->setAlignment(Qt::AlignCenter); ui->tabWidget->addTab(newTab, ""); ui->tabWidget->setTabsClosable(false); // Add "Connect to Camera" button to tab connectToCameraButton = new QPushButton(); connectToCameraButton->setText("Connect to Camera..."); ui->tabWidget->setCornerWidget(connectToCameraButton, Qt::TopLeftCorner); connect(connectToCameraButton,SIGNAL(released()),this, SLOT(connectToCamera())); connect(ui->tabWidget,SIGNAL(tabCloseRequested(int)),this, SLOT(disconnectCamera(int))); // Set focus on button connectToCameraButton->setFocus(); // Connect other signals/slots connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAboutDialog())); connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(close())); connect(ui->actionFullScreen, SIGNAL(toggled(bool)), this, SLOT(setFullScreen(bool))); // Create SharedImageBuffer object sharedImageBuffer = new SharedImageBuffer(); setAttribute(Qt::WA_DeleteOnClose); } MainWindow::~MainWindow() { delete ui; } void MainWindow::closeEvent(QCloseEvent *event) { //delete cameraViewMap[0]; //QMainWindow::closeEvent(event); } void MainWindow::connectToCamera() { // We cannot connect to a camera if devices are already connected and stream synchronization is in progress if(ui->actionSynchronizeStreams->isChecked() && deviceNumberMap.size()>0 && sharedImageBuffer->getSyncEnabled()) { // Prompt user QMessageBox::warning(this, tr("qt-opencv-opencl-opengl-multithreaded"), tr("Stream synchronization is in progress.\n\n" "Please close all currently open streams before attempting to open a new stream."), QMessageBox::Ok); } // Attempt to connect to camera else { // Get next tab index int nextTabIndex = (deviceNumberMap.size()==0) ? 0 : ui->tabWidget->count(); // Show dialog CameraConnectDialog *cameraConnectDialog = new CameraConnectDialog(this, ui->actionSynchronizeStreams->isChecked()); if(cameraConnectDialog->exec()==QDialog::Accepted) { // Save user-defined device number int deviceNumber = cameraConnectDialog->getDeviceNumber(); // Check if this camera is already connected if(!deviceNumberMap.contains(deviceNumber)) { // Create ImageBuffer with user-defined size Buffer *imageBuffer = new Buffer(cameraConnectDialog->getImageBufferSize()); // Add created ImageBuffer to SharedImageBuffer object sharedImageBuffer->add(deviceNumber, imageBuffer, ui->actionSynchronizeStreams->isChecked()); // Create CameraView cameraViewMap[deviceNumber] = new CameraView(ui->tabWidget, deviceNumber, sharedImageBuffer); // Check if stream synchronization is enabled if(ui->actionSynchronizeStreams->isChecked()) { // Prompt user int ret = QMessageBox::question(this, tr("qt-opencv-opencl-opengl-multithreaded"), tr("Stream synchronization is enabled.\n\n" "Do you want to start processing?\n\n" "Choose 'No' if you would like to open additional streams."), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); // Start processing if(ret==QMessageBox::Yes) sharedImageBuffer->setSyncEnabled(true); // Defer processing else sharedImageBuffer->setSyncEnabled(false); } // Attempt to connect to camera if(cameraViewMap[deviceNumber]->connectToCamera(cameraConnectDialog->getDropFrameCheckBoxState(), cameraConnectDialog->getCaptureThreadPrio(), cameraConnectDialog->getProcessingThreadPrio(), cameraConnectDialog->getEnableFrameProcessingCheckBoxState(), cameraConnectDialog->getResolutionWidth(), cameraConnectDialog->getResolutionHeight())) { // Add to map deviceNumberMap[deviceNumber] = nextTabIndex; // Save tab label QString tabLabel = cameraConnectDialog->getTabLabel(); // Allow tabs to be closed ui->tabWidget->setTabsClosable(true); // If start tab, remove if(nextTabIndex==0) ui->tabWidget->removeTab(0); // Add tab ui->tabWidget->addTab(cameraViewMap[deviceNumber], tabLabel + " [" + QString::number(deviceNumber) + "]"); ui->tabWidget->setCurrentWidget(cameraViewMap[deviceNumber]); // Set tooltips setTabCloseToolTips(ui->tabWidget, "Disconnect Camera"); // Prevent user from enabling/disabling stream synchronization after a camera has been connected ui->actionSynchronizeStreams->setEnabled(false); } // Could not connect to camera else { // Display error message QMessageBox::warning(this,"ERROR:","Could not connect to camera. Please check device number."); // Explicitly delete widget delete cameraViewMap[deviceNumber]; cameraViewMap.remove(deviceNumber); // Remove from shared buffer sharedImageBuffer->removeByDeviceNumber(deviceNumber); // Explicitly delete ImageBuffer object delete imageBuffer; } } // Display error message else QMessageBox::warning(this,"ERROR:","Could not connect to camera. Already connected."); } // Delete dialog delete cameraConnectDialog; } } void MainWindow::disconnectCamera(int index) { // Local variable(s) bool doDisconnect=true; // Check if stream synchronization is enabled, more than 1 camera connected, and frame processing is not in progress if(ui->actionSynchronizeStreams->isChecked() && cameraViewMap.size()>1 && !sharedImageBuffer->getSyncEnabled()) { // Prompt user int ret = QMessageBox::question(this, tr("qt-opencv-opencl-opengl-multithreaded"), tr("Stream synchronization is enabled.\n\n" "Disconnecting this camera will cause frame processing to begin on other streams.\n\n" "Do you wish to proceed?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); // Disconnect if(ret==QMessageBox::Yes) doDisconnect=true; // Do not disconnect else doDisconnect=false; } // Disconnect camera if(doDisconnect) { // Save number of tabs int nTabs = ui->tabWidget->count(); // Close tab ui->tabWidget->removeTab(index); // Delete widget (CameraView) contained in tab delete cameraViewMap[deviceNumberMap.key(index)]; cameraViewMap.remove(deviceNumberMap.key(index)); // Remove from map removeFromMapByTabIndex(deviceNumberMap, index); // Update map (if tab closed is not last) if(index!=(nTabs-1)) updateMapValues(deviceNumberMap, index); // If start tab, set tab as blank if(nTabs==1) { QLabel *newTab = new QLabel(ui->tabWidget); newTab->setText("No camera connected at the moment. After connecting to a camera,\nyou can right-click on Camera View to get the list of image processing options:\nflip, erode, dilute, smooth, Canny edge and Hand Gesture detection."); newTab->setAlignment(Qt::AlignCenter); ui->tabWidget->addTab(newTab, ""); ui->tabWidget->setTabsClosable(false); ui->actionSynchronizeStreams->setEnabled(true); } } } void MainWindow::showAboutDialog() { QMessageBox::information(this, "About", QString("Created by Nick D'Ademo\n\nContact: nickdademo@gmail.com\nWebsite: www.nickdademo.com\n\nVersion: %1").arg(APP_VERSION)); } bool MainWindow::removeFromMapByTabIndex(QMap &map, int tabIndex) { QMutableMapIterator i(map); while (i.hasNext()) { i.next(); if(i.value()==tabIndex) { i.remove(); return true; } } return false; } void MainWindow::updateMapValues(QMap &map, int tabIndex) { QMutableMapIterator i(map); while (i.hasNext()) { i.next(); if(i.value()>tabIndex) i.setValue(i.value()-1); } } void MainWindow::setTabCloseToolTips(QTabWidget *tabs, QString tooltip) { QList allPButtons = tabs->findChildren(); for (int ind = 0; ind < allPButtons.size(); ind++) { QAbstractButton* item = allPButtons.at(ind); if (item->inherits("CloseButton")) item->setToolTip(tooltip); } } void MainWindow::setFullScreen(bool input) { if(input) this->showFullScreen(); else this->showNormal(); }