#include #include #include #include #include #include #include #include #include "MainWindow.h" #include "NewProjectDialog.h" #include "CompareImageDialog.h" #include "SpkDiarizationDialog.h" #include "GetFileDialog.h" #include "VideoFrame.h" #include "EditSimShotDialog.h" using namespace arma; ///////////////// // constructor // ///////////////// MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) { setWindowTitle("TV Series Processing Tool"); createActions(); createMenus(); // connecting action signals to slots connect(m_newProAct, SIGNAL(triggered()), this, SLOT(newProject())); connect(m_proOpenProAct, SIGNAL(triggered()), this, SLOT(openProject())); connect(m_saveProAct, SIGNAL(triggered()), this, SLOT(saveProject())); connect(m_closeProAct, SIGNAL(triggered()), this, SLOT(closeProject())); connect(m_appendProAct, SIGNAL(triggered()), this, SLOT(appendProject())); connect(m_addSubAct, SIGNAL(triggered()), this, SLOT(addSubtitles())); connect(m_quitAct, SIGNAL(triggered()), this, SLOT(quitTool())); connect(m_histoAct, SIGNAL(triggered()), this, SLOT(showHisto())); connect(m_autShotAct, SIGNAL(triggered()), this, SLOT(extractShots())); connect(m_simShotDetectAct, SIGNAL(triggered()), this, SLOT(detectSimShots())); connect(m_spkDiarAct, SIGNAL(triggered()), this, SLOT(spkDiar())); connect(m_vFrameLevelAct, SIGNAL(triggered()), this, SLOT(selectVideoFrameLevel())); connect(m_shotLevelAct, SIGNAL(triggered()), this, SLOT(selectShotLevel())); connect(m_sceneLevelAct, SIGNAL(triggered()), this, SLOT(selectSceneLevel())); connect(m_manShotAct, SIGNAL(triggered(bool)), this, SLOT(shotAnnotation(bool))); connect(m_manShotSimAct, SIGNAL(triggered(bool)), this, SLOT(shotSimAnnotation(bool))); connect(m_exportSubAct, SIGNAL(triggered()), this, SLOT(exportSubtitles())); connect(m_viewLocSpkDiarAct, SIGNAL(triggered(bool)), this, SLOT(viewLocSpkDiar(bool))); // enabling/disabling actions m_proOpen = false; m_proModified = false; m_histoDisp = false; updateActions(); // initializing model/view m_project = new ProjectModel(this); m_modelView = new ModelView(m_project); // initializing video player m_videoPlayer = new VideoPlayer; m_videoPlayer->showVignette(false); // initializing central area QHBoxLayout *viewLayout = new QHBoxLayout; viewLayout->addWidget(m_videoPlayer); viewLayout->addWidget(m_modelView); QWidget *centralWidget = new QWidget; centralWidget->setLayout(viewLayout); setCentralWidget(centralWidget); // connecting model view signals to player slots connect(m_modelView, SIGNAL(setPlayer(const QString &, const QSize &)), m_videoPlayer, SLOT(setPlayer(const QString &, const QSize &))); connect(m_modelView, SIGNAL(setPlayerPosition(qint64)), m_videoPlayer, SLOT(setPlayerPosition(qint64))); connect(m_modelView, SIGNAL(currentShot(QList)), m_videoPlayer, SLOT(currentShot(QList))); connect(this, SIGNAL(showVignette(bool)), m_videoPlayer, SLOT(showVignette(bool))); connect(m_modelView, SIGNAL(displaySubtitle(const QString &)), m_videoPlayer, SLOT(displaySubtitle(const QString &))); connect(m_viewSpeakersAct, SIGNAL(triggered(bool)), m_project, SLOT(retrieveSpeakers(bool))); connect(m_viewSpeakersAct, SIGNAL(triggered(bool)), m_videoPlayer, SLOT(viewSpeakers(bool))); connect(m_project, SIGNAL(playSegments(QList>)), m_videoPlayer, SLOT(playSegments(QList>))); // possibly connecting model view signal to model slot connect(m_modelView, SIGNAL(insertShot(Segment *)), this, SLOT(addShot(Segment *))); connect(m_modelView, SIGNAL(removeShot(Segment *)), this, SLOT(delShot(Segment *))); connect(m_modelView, SIGNAL(editSimShots(Segment *)), this, SLOT(editSimShots(Segment *))); connect(this, SIGNAL(insertShot(Segment *, Segment::Source)), m_project, SLOT(insertShot(Segment *, Segment::Source))); connect(this, SIGNAL(removeShot(Segment *, Segment::Source)), m_project, SLOT(removeShot(Segment *, Segment::Source))); connect(m_modelView, SIGNAL(setPlayerPosition(qint64)), m_project, SLOT(retrieveShotSub(qint64))); // connecting player signal to model view slot connect(m_videoPlayer, SIGNAL(positionUpdated(qint64)), m_modelView, SLOT(positionChanged(qint64))); connect(m_videoPlayer, SIGNAL(playerPaused(bool)), m_modelView, SLOT(playerPaused(bool))); // connecting player signal to model slots connect(m_videoPlayer, SIGNAL(newSpeaker(qint64, qint64, const QString &, VideoFrame::SpeakerSource)), m_project, SLOT(setSpeaker(qint64, qint64, const QString &, VideoFrame::SpeakerSource))); connect(m_videoPlayer, SIGNAL(renewSpeaker(qint64, qint64, qint64, qint64, bool, VideoFrame::SpeakerSource)), m_project, SLOT(resetSpeaker(qint64, qint64, qint64, qint64, bool, VideoFrame::SpeakerSource))); connect(m_videoPlayer, SIGNAL(playSub(QList)), m_project, SLOT(playSubtitle(QList))); connect(m_videoPlayer, SIGNAL(positionUpdated(qint64)), m_project, SLOT(retrieveShotSub(qint64))); connect(m_videoPlayer, SIGNAL(positionUpdated(qint64)), m_project, SLOT(currentSub(qint64))); // connecting view actions to monitoring widget connect(this, SIGNAL(activeHisto(bool)), m_videoPlayer, SLOT(activeHisto(bool))); connect(this, SIGNAL(viewUtteranceTree(bool)), m_videoPlayer, SLOT(viewUtteranceTree(bool))); connect(m_project, SIGNAL(getCurrentPattern(const QList> &)), m_videoPlayer, SLOT(getCurrentPattern(const QList> &))); connect(m_project, SIGNAL(getPatternFirstShot(const QList> &)), m_videoPlayer, SLOT(getPatternFirstShot(const QList> &))); connect(m_project, SIGNAL(getPatternSecondShot(const QList> &)), m_videoPlayer, SLOT(getPatternSecondShot(const QList> &))); connect(this, SIGNAL(setDiarData(const arma::mat &, const arma::mat &, const arma::mat &)), m_videoPlayer, SLOT(setDiarData(const arma::mat &, const arma::mat &, const arma::mat &))); connect(m_project, SIGNAL(setDiarData(const arma::mat &, const arma::mat &, const arma::mat &)), m_videoPlayer, SLOT(setDiarData(const arma::mat &, const arma::mat &, const arma::mat &))); // indirectly connecting annotation tools actions to model slots connect(m_manShotAct, SIGNAL(triggered(bool)), m_modelView, SLOT(initShotAnnot(bool))); connect(m_modelView, SIGNAL(initShotLevel(Segment *)), m_project, SLOT(initShotLevel(Segment *))); // connecting model signals to main window slots connect(m_project, SIGNAL(modelChanged()), this, SLOT(modelChanged())); // emitting appropriate signal when segmentation view/annotation action is triggered connect(m_viewSegmentAct, SIGNAL(triggered()), this, SLOT(viewSegmentation())); connect(m_speechSegAct, SIGNAL(triggered()), this, SLOT(viewSegmentation())); connect(this, SIGNAL(processSegmentation(bool, bool)), m_project, SLOT(processSegmentation(bool, bool))); // spoken frames coming from model sent to player for monitoring purpose; end signal connect(m_project, SIGNAL(getSpokenFrame(qint64, const QString &, const QString &)), m_videoPlayer, SLOT(getSpokenFrame(qint64, const QString &, const QString &))); connect(m_project, SIGNAL(getShot(Segment *)), m_videoPlayer, SLOT(getShot(Segment *))); connect(m_project, SIGNAL(segmentationRetrieved()), m_videoPlayer, SLOT(segmentationRetrieved())); connect(m_project, SIGNAL(viewSegmentation(bool, bool)), m_videoPlayer, SLOT(showSegmentation(bool, bool))); // connecting model signals to view and player slots connect(m_project, SIGNAL(positionChanged(qint64)), m_modelView, SLOT(positionChanged(qint64))); connect(m_project, SIGNAL(speakersRetrieved(QList)), m_videoPlayer, SLOT(speakersRetrieved(QList))); connect(m_project, SIGNAL(currentSubtitle(int)), m_videoPlayer, SLOT(currentSubtitle(int))); // miscellaneous connect(this, SIGNAL(extractSubtitles(const QString &)), m_project, SLOT(exportSubtitles(const QString &))); connect(this, SIGNAL(extractIVectors(bool, const QString &)), m_project, SLOT(extractIVectors(bool, const QString &))); connect(this, SIGNAL(extractSpkIVectors(const QString &, bool)), m_project, SLOT(extractSpkIVectors(const QString &, bool))); } //////////////// // destructor // //////////////// MainWindow::~MainWindow() { } ////////////////////////////////////////// // slots called when triggering actions // ////////////////////////////////////////// bool MainWindow::newProject() { NewProjectDialog dialog(this); if (dialog.exec() == QDialog::Accepted) { ////////////////////////////// // initializing new project // ////////////////////////////// m_project->setModel(dialog.getProjectName(), dialog.getSeriesName(), dialog.getSeasNbr(), dialog.getEpNbr(), dialog.getEpName(), dialog.getEpFName()); setWindowTitle("TV Series Processing Tool - " + m_project->getName()); m_modelView->setDepth(m_project->getDepth()); m_modelView->initPlayer(); m_proOpen = true; m_proModified = true; updateActions(); return true; } return false; } bool MainWindow::openProject() { QString fName = QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("Project (*.json)")); // QString fName = QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("Project (*.dat)")); if (!fName.isEmpty() && m_project->load(fName)) { m_modelView->setDepth(m_project->getDepth()); m_modelView->initPlayer(); setWindowTitle("TV Series Processing Tool - " + m_project->getName()); selectDefaultLevel(); m_proOpen = true; updateActions(); return true; } return false; } bool MainWindow::saveProject() { QString fName = QFileDialog::getSaveFileName(this, tr("Save File"), ("./projects/" + m_project->getName()), tr("Project (*.json)")); if (m_project->save(fName)) { m_proModified = false; updateActions(); return true; } return false; } bool MainWindow::closeProject() { int ans = 0; if (m_proModified) ans = QMessageBox::question(this, tr("Close project"), tr("Current project has been modified, save changes ?"), QMessageBox::Yes | QMessageBox::No); if (ans == QMessageBox::Yes) saveProject(); setWindowTitle("TV Series Processing Tool"); m_project->reset(); m_videoPlayer->reset(); m_proModified = false; m_proOpen = false; updateActions(); return true; } bool MainWindow::appendProject() { NewProjectDialog dialog(this, m_project->getName(), m_project->getSeriesName()); if (dialog.exec() == QDialog::Accepted) { if (m_project->appendModel(dialog.getSeasNbr(), dialog.getEpNbr(), dialog.getEpName(), dialog.getEpFName())) { m_modelView->setDepth(m_project->getDepth()); m_proModified = true; updateActions(); return true; } else { QString errMsg = "Impossible to add episode "; errMsg += dialog.getEpNbr(); errMsg += " of Season "; errMsg += dialog.getSeasNbr(); errMsg += ": episode already included in project."; QMessageBox::critical(this, tr("Append project"), errMsg); } } return false; } bool MainWindow::addSubtitles() { GetFileDialog dialog(tr("Subtitles File"), tr("Subtitles Files (*.json)"), this); if (dialog.exec() == QDialog::Accepted) { m_project->insertSubtitles(dialog.getFName()); m_proModified = true; updateActions(); return true; } return false; } bool MainWindow::quitTool() { int ans = 0; if (m_proModified) ans = QMessageBox::question(this, tr("Quit"), tr("Current project has been modified, save changes?"), QMessageBox::Yes | QMessageBox::No); if (ans == QMessageBox::Yes) saveProject(); QCoreApplication::quit(); return true; } bool MainWindow::showHisto() { if (m_proOpen && !m_histoDisp) { m_histoDisp = true; } else m_histoDisp = false; emit activeHisto(m_histoDisp); updateActions(); return true; } bool MainWindow::extractShots() { selectVideoFrameLevel(); CompareImageDialog dialog(tr("Shot extraction"), 64, 24, 8, 30, 20, tr("High threshold:"), tr("Low threshold:"), this); if (dialog.exec() == QDialog::Accepted) { m_project->extractShots(m_modelView->getCurrentEpisodeFName(), dialog.getHistoType(), dialog.getNVBins(), dialog.getNHBins(), dialog.getNSBins(), dialog.getMetrics(), dialog.getThreshold1(), dialog.getThreshold2(), dialog.getNVBlock(), dialog.getNHBlock(), dialog.getIterate()); selectShotLevel(); m_proModified = true; updateActions(); return true; } return false; } bool MainWindow::detectSimShots() { selectVideoFrameLevel(); CompareImageDialog dialog(tr("Shot Similarity Detection..."), 64, 24, 8, 40, 30, tr("Max distance:"), tr("Window size:"), this); if (dialog.exec() == QDialog::Accepted) { m_project->labelSimilarShots(m_modelView->getCurrentEpisodeFName(), dialog.getHistoType(), dialog.getNVBins(), dialog.getNHBins(), dialog.getNSBins(), dialog.getMetrics(), dialog.getThreshold1(), dialog.getThreshold2(), dialog.getNVBlock(), dialog.getNHBlock(), dialog.getIterate()); selectShotLevel(); m_proModified = true; updateActions(); return true; } return false; } bool MainWindow::spkDiar() { SpkDiarizationDialog dialog(tr("Global speaker diarization"), false, false, this); if (dialog.exec() == QDialog::Accepted) { m_project->setSpkDiar(m_modelView->getCurrentEpisodeFName()); emit extractIVectors(dialog.getUbm(), m_modelView->getCurrentEpisodeFName()); if (!dialog.getRefSpk()) m_project->localSpkDiar(dialog.getBase(), dialog.getDist(), dialog.getNorm(), dialog.getAgrCrit(), dialog.getPartMeth(), dialog.getWeight(), dialog.getSigma()); emit extractSpkIVectors(m_modelView->getCurrentEpisodeFName(), dialog.getRefSpk()); m_project->globalSpkDiar(); return true; } return false; } void MainWindow::selectVideoFrameLevel() { m_vFrameLevelAct->setChecked(true); m_modelView->setDepth(m_project->getDepth()); emit showVignette(false); } void MainWindow::selectShotLevel() { m_shotLevelAct->setChecked(true); m_modelView->setDepth(m_project->getDepth()-1); emit showVignette(true); } void MainWindow::selectSceneLevel() { m_sceneLevelAct->setChecked(true); m_modelView->setDepth(m_project->getDepth()-2); emit showVignette(true); } void MainWindow::addShot(Segment *segment) { if (m_manShotAct->isChecked()) emit insertShot(segment, Segment::Manual); } void MainWindow::delShot(Segment *segment) { if (m_manShotAct->isChecked()) emit removeShot(segment, Segment::Manual); } void MainWindow::shotAnnotation(bool checked) { if (checked) { m_shotLevelAct->setEnabled(false); m_sceneLevelAct->setEnabled(false); selectVideoFrameLevel(); } else { selectDefaultLevel(); updateActions(); } } void MainWindow::editSimShots(Segment *segment) { if (m_manShotSimAct->isChecked()) { QList shotPositions; int segIdx = m_project->retrieveShotPrevPositions(segment->getPosition(), shotPositions); EditSimShotDialog annotSimDialog(m_modelView->getCurrentEpisodeFName(), segIdx, shotPositions, 6, 1000, this); connect(&annotSimDialog, SIGNAL(labelSimShot(qint64, int, Segment::Source)), m_project, SLOT(labelSimShot(qint64, int, Segment::Source))); annotSimDialog.exec(); disconnect(&annotSimDialog, SIGNAL(labelSimShot(qint64, int, Segment::Source)), m_project, SLOT(labelSimShot(qint64, int, Segment::Source))); m_proModified = true; updateActions(); } } void MainWindow::shotSimAnnotation(bool checked) { if (checked) { m_vFrameLevelAct->setEnabled(false); m_sceneLevelAct->setEnabled(false); selectShotLevel(); } else { selectDefaultLevel(); updateActions(); } } void MainWindow::modelChanged() { m_proModified = true; m_modelView->setDepth(m_project->getDepth()); updateActions(); } void MainWindow::viewSegmentation() { emit processSegmentation(m_viewSegmentAct->isChecked(), m_speechSegAct->isChecked()); if (m_speechSegAct->isChecked()) { m_proModified = true; updateActions(); } } void MainWindow::viewLocSpkDiar(bool checked) { if (checked) { m_project->setSpkDiar(m_modelView->getCurrentEpisodeFName()); emit extractIVectors(false, m_modelView->getCurrentEpisodeFName()); emit viewUtteranceTree(checked); } updateActions(); } void MainWindow::exportSubtitles() { QString fName = QFileDialog::getSaveFileName(this, tr("Export subtitles"), tr("/home/xavier/Dropbox/tv_series_proc_tool/tools/process_sub/"), tr("Subtitle file (*.csv)")); if (!fName.isEmpty()) emit extractSubtitles(fName); } /////////////////////////////////// // auxiliary methods called when // // constructing main window // /////////////////////////////////// void MainWindow::createActions() { // project menu actions m_newProAct = new QAction(tr("&New..."), this); m_proOpenProAct = new QAction(tr("&Open..."), this); m_saveProAct = new QAction(tr("&Save as..."), this); m_closeProAct = new QAction(tr("&Close"), this); m_quitAct = new QAction(tr("&Quit"), this); // edit menu actions m_appendProAct = new QAction(tr("&Append project..."), this); m_addSubAct = new QAction(tr("Add &subtitles..."), this); // view menu actions m_histoAct = new QAction(tr("&HSV histograms"), this); m_histoAct->setCheckable(true); m_viewSegmentAct = new QAction(tr("Se&gmentation"), this); m_viewSegmentAct->setCheckable(true); m_viewSpeakersAct = new QAction(tr("S&peakers"), this); m_viewSpeakersAct->setCheckable(true); m_viewLocSpkDiarAct = new QAction(tr("&Local speaker diarization"), this); m_viewLocSpkDiarAct->setCheckable(true); m_vFrameLevelAct = new QAction(tr("&Video Frame level"), this); m_shotLevelAct = new QAction(tr("&Shot level"), this); m_sceneLevelAct = new QAction(tr("S&cene level"), this); m_vFrameLevelAct->setCheckable(true); m_shotLevelAct->setCheckable(true); m_sceneLevelAct->setCheckable(true); // tools menu actions m_manShotAct = new QAction(tr("&Shot Insertion"), this); m_manShotSimAct = new QAction(tr("Shot Si&milarity"), this); m_manShotAct->setCheckable(true); m_manShotSimAct->setCheckable(true); m_speechSegAct = new QAction(tr("S&peech Segments"), this); m_speechSegAct->setCheckable(true); m_autShotAct = new QAction(tr("Shot E&xtraction..."), this); m_simShotDetectAct = new QAction(tr("&Shot Similarity Detection..."), this); m_spkDiarAct = new QAction(tr("&Speaker Diarization..."), this); m_exportSubAct = new QAction(tr("Export subtitles..."), this); // set icon actions m_proOpenProAct->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton)); m_saveProAct->setIcon(style()->standardIcon(QStyle::SP_DialogSaveButton)); m_closeProAct->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton)); } void MainWindow::createMenus() { // project menu QMenu *projectMenu = menuBar()->addMenu(tr("&Project")); projectMenu->addAction(m_newProAct); projectMenu->addAction(m_proOpenProAct); projectMenu->addSeparator(); projectMenu->addAction(m_saveProAct); projectMenu->addAction(m_closeProAct); projectMenu->addSeparator(); projectMenu->addAction(m_quitAct); // edit menu QMenu *editMenu = menuBar()->addMenu(tr("&Edit")); editMenu->addAction(m_appendProAct); editMenu->addAction(m_addSubAct); // view menu QMenu *viewMenu = menuBar()->addMenu(tr("&View")); viewMenu->addAction(m_histoAct); viewMenu->addAction(m_viewSegmentAct); viewMenu->addAction(m_viewSpeakersAct); viewMenu->addAction(m_viewLocSpkDiarAct); viewMenu->addSeparator()->setText(tr("Depth")); m_granularityGroup = new QActionGroup(this); m_granularityGroup->addAction(m_vFrameLevelAct); m_granularityGroup->addAction(m_shotLevelAct); m_granularityGroup->addAction(m_sceneLevelAct); viewMenu->addAction(m_vFrameLevelAct); viewMenu->addAction(m_shotLevelAct); viewMenu->addAction(m_sceneLevelAct); // tools menu QMenu *toolsMenu = menuBar()->addMenu(tr("&Tools")); m_annotationsMenu = toolsMenu->addMenu(tr("&Annotations")); m_annotationsMenu->addAction(m_manShotAct); m_annotationsMenu->addAction(m_manShotSimAct); m_annotationsMenu->addSeparator(); m_annotationsMenu->addAction(m_speechSegAct); toolsMenu->addAction(m_spkDiarAct); toolsMenu->addAction(m_autShotAct); toolsMenu->addAction(m_simShotDetectAct); toolsMenu->addAction(m_exportSubAct); } /////////////////////////////// // auxiliary method called // // to enable/disable actions // /////////////////////////////// void MainWindow::updateActions() { m_newProAct->setEnabled(!m_proOpen); m_proOpenProAct->setEnabled(!m_proOpen); m_saveProAct->setEnabled(m_proModified); m_granularityGroup->setEnabled(m_proOpen); m_histoAct->setEnabled(m_proOpen); m_histoAct->setChecked(m_histoDisp); m_viewSegmentAct->setEnabled(m_proOpen); m_viewSpeakersAct->setEnabled(m_proOpen); m_viewLocSpkDiarAct->setEnabled(m_proOpen); m_closeProAct->setEnabled(m_proOpen); m_appendProAct->setEnabled(m_proOpen); m_addSubAct->setEnabled(m_proOpen); m_annotationsMenu->setEnabled(m_proOpen); m_autShotAct->setEnabled(m_proOpen); m_simShotDetectAct->setEnabled(m_proOpen); m_spkDiarAct->setEnabled(m_proOpen); m_exportSubAct->setEnabled(m_proOpen); if (m_proOpen) switch (m_project->getDepth()) { case 2: case 3: m_vFrameLevelAct->setEnabled(true); m_shotLevelAct->setEnabled(false); m_manShotSimAct->setEnabled(false); m_sceneLevelAct->setEnabled(false); break; case 4: m_vFrameLevelAct->setEnabled(true); m_shotLevelAct->setEnabled(true); m_manShotSimAct->setEnabled(true); m_sceneLevelAct->setEnabled(false); break; case 5: m_vFrameLevelAct->setEnabled(true); m_shotLevelAct->setEnabled(true); m_manShotSimAct->setEnabled(true); m_sceneLevelAct->setEnabled(true); break; } } void MainWindow::selectDefaultLevel() { // scene and/of shots level(s) already created if (m_project->getDepth() >= 4) selectShotLevel(); else selectVideoFrameLevel(); }