/************************************************************************/
/* qt-opencv-opencl-opengl-multithreaded: */
/* A multithreaded OpenCV application using the Qt framework. */
/* */
/* MainWindow.cpp */
/* */
/* Nick D'Ademo <nickdademo@gmail.com> */
/* */
/* 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 <QLabel>
#include <QMessageBox>
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<Mat> *imageBuffer = new Buffer<Mat>(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<int, int> &map, int tabIndex)
{
QMutableMapIterator<int, int> i(map);
while (i.hasNext())
{
i.next();
if(i.value()==tabIndex)
{
i.remove();
return true;
}
}
return false;
}
void MainWindow::updateMapValues(QMap<int, int> &map, int tabIndex)
{
QMutableMapIterator<int, int> i(map);
while (i.hasNext())
{
i.next();
if(i.value()>tabIndex)
i.setValue(i.value()-1);
}
}
void MainWindow::setTabCloseToolTips(QTabWidget *tabs, QString tooltip)
{
QList<QAbstractButton*> allPButtons = tabs->findChildren<QAbstractButton*>();
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();
}