From dfb4e5038d5bb50662b96a0faf17380e11ac9ce0 Mon Sep 17 00:00:00 2001 From: matlabbe Date: Tue, 28 Aug 2012 20:06:43 +0000 Subject: [PATCH] New features: camera from directory of images, new controls to move across frames of a video or a directory of images. git-svn-id: http://find-object.googlecode.com/svn/trunk/find_object@110 620bd6b2-0a58-f614-fd9a-1bd335dccda9 --- app/CMakeLists.txt | 2 + example/CMakeLists.txt | 2 + src/Camera.cpp | 135 +++- src/Camera.h | 7 +- src/MainWindow.cpp | 174 +++-- src/MainWindow.h | 3 + src/ParametersToolBox.cpp | 2 + src/Settings.h | 5 +- src/resources.qrc | 3 + src/resources/TheWorkingGroup_video_pause.ico | Bin 0 -> 32038 bytes src/resources/TheWorkingGroup_video_play.ico | Bin 0 -> 32038 bytes src/resources/TheWorkingGroup_video_stop.ico | Bin 0 -> 32038 bytes src/ui/mainWindow.ui | 258 +++++--- src/utilite/UDirectory.cpp | 348 ++++++++++ src/utilite/UDirectory.h | 139 ++++ src/utilite/UFile.cpp | 97 +++ src/utilite/UFile.h | 137 ++++ src/utilite/UStl.h | 593 ++++++++++++++++++ 18 files changed, 1753 insertions(+), 152 deletions(-) create mode 100644 src/resources/TheWorkingGroup_video_pause.ico create mode 100644 src/resources/TheWorkingGroup_video_play.ico create mode 100644 src/resources/TheWorkingGroup_video_stop.ico create mode 100644 src/utilite/UDirectory.cpp create mode 100644 src/utilite/UDirectory.h create mode 100644 src/utilite/UFile.cpp create mode 100644 src/utilite/UFile.h create mode 100644 src/utilite/UStl.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 47a991db..3f372b68 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -45,6 +45,8 @@ SET(SRC_FILES ../src/ObjWidget.cpp ../src/AboutDialog.cpp ../src/utilite/UPlot.cpp + ../src/utilite/UDirectory.cpp + ../src/utilite/UFile.cpp ../src/rtabmap/PdfPlot.cpp ${moc_srcs} ${moc_uis} diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 9a4621c5..a93f243b 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -14,6 +14,8 @@ SET(SRC_FILES ../src/QtOpenCV.cpp ../src/Settings.cpp ../src/Camera.cpp + ../src/utilite/UDirectory.cpp + ../src/utilite/UFile.cpp ${moc_srcs} ) diff --git a/src/Camera.cpp b/src/Camera.cpp index 0a82af54..c249e4ab 100644 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -7,9 +7,11 @@ #include #include "Settings.h" #include +#include "utilite/UDirectory.h" Camera::Camera(QObject * parent) : - QObject(parent) + QObject(parent), + currentImageIndex_(0) { qRegisterMetaType("cv::Mat"); connect(&cameraTimer_, SIGNAL(timeout()), this, SLOT(takeImage())); @@ -24,6 +26,8 @@ void Camera::stop() { stopTimer(); capture_.release(); + images_.clear(); + currentImageIndex_ = 0; } void Camera::pause() @@ -31,50 +35,127 @@ void Camera::pause() stopTimer(); } +int Camera::getTotalFrames() +{ + if(images_.size()) + { + return images_.size(); + } + else if(capture_.isOpened()) + { + return (int)capture_.get(CV_CAP_PROP_FRAME_COUNT); + } + return 0; +} + +int Camera::getCurrentFrameIndex() +{ + if(images_.size()) + { + return currentImageIndex_; + } + else if(capture_.isOpened()) + { + return (int)capture_.get(CV_CAP_PROP_POS_FRAMES); + } + return 0; +} + +void Camera::moveToFrame(int frame) +{ + printf("Moved to frame %d.\n", frame); + if(frame < images_.size()) + { + currentImageIndex_ = frame; + } + else if(capture_.isOpened() && frame < (int)capture_.get(CV_CAP_PROP_FRAME_COUNT)) + { + capture_.set(CV_CAP_PROP_POS_FRAMES, frame); + } +} + void Camera::takeImage() { + cv::Mat img; if(capture_.isOpened()) { - cv::Mat img; capture_.read(img);// capture a frame - if(img.empty()) + } + else if(!images_.empty()) + { + if(currentImageIndex_ < images_.size()) { - printf("Camera: Could not grab a frame, the end of the feed may be reached...\n"); + img = cv::imread(images_[currentImageIndex_++]); + } + } + + if(img.empty()) + { + printf("Camera: Could not grab a frame, the end of the feed may be reached...\n"); + } + else + { + //resize + if( Settings::getCamera_2imageWidth() && + Settings::getCamera_3imageHeight() && + Settings::getCamera_2imageWidth() != img.cols && + Settings::getCamera_3imageHeight() != img.rows) + { + cv::Mat resampled; + cv::resize(img, resampled, cv::Size(Settings::getCamera_2imageWidth(), Settings::getCamera_3imageHeight())); + emit imageReceived(resampled); + } + else if(capture_.isOpened()) + { + emit imageReceived(img.clone()); // clone required with VideoCapture::read() } else { - //resize - if( Settings::getCamera_2imageWidth() && - Settings::getCamera_3imageHeight() && - Settings::getCamera_2imageWidth() != img.cols && - Settings::getCamera_3imageHeight() != img.rows) - { - cv::Mat resampled; - cv::resize(img, resampled, cv::Size(Settings::getCamera_2imageWidth(), Settings::getCamera_3imageHeight())); - emit imageReceived(resampled); - } - else - { - emit imageReceived(img.clone()); // clone required - } + emit imageReceived(img); // clone not required with cv::imread() } } } bool Camera::start() { - if(!capture_.isOpened()) + if(!capture_.isOpened() && images_.empty()) { - QString videoFile = Settings::getCamera_5videoFilePath(); - if(!videoFile.isEmpty()) + QString path = Settings::getCamera_5mediaPath(); + if(UDirectory::exists(path.toStdString())) { - capture_.open(videoFile.toStdString().c_str()); - if(!capture_.isOpened()) + //Images directory + QString ext = Settings::getGeneral_imageFormats(); + ext.remove('*'); + ext.remove('.'); + UDirectory dir(path.toStdString(), ext.toStdString()); // this will load fileNames matching the extensions (in natural order) + const std::list & fileNames = dir.getFileNames(); + currentImageIndex_ = 0; + images_.clear(); + // Modify to have full path + for(std::list::const_iterator iter = fileNames.begin(); iter!=fileNames.end(); ++iter) { - printf("WARNING: Cannot open file \"%s\". If you want to disable loading automatically this video file, clear the Camera/videoFilePath parameter. By default, webcam will be used instead of the file.\n", videoFile.toStdString().c_str()); + images_.append(path.toStdString() + UDirectory::separator() + *iter); + } + printf("Loaded %d filenames.\n", (int)images_.size()); + if(images_.isEmpty()) + { + printf("WARNING: Directory \"%s\" is empty (no images matching the \"%s\" extensions). " + "If you want to disable loading automatically this directory, " + "clear the Camera/mediaPath parameter. By default, webcam will be used instead of the directory.\n", + path.toStdString().c_str(), + ext.toStdString().c_str()); } } - if(!capture_.isOpened()) + else if(!path.isEmpty()) + { + //Video file + capture_.open(path.toStdString().c_str()); + if(!capture_.isOpened()) + { + printf("WARNING: Cannot open file \"%s\". If you want to disable loading automatically this video file, clear the Camera/mediaPath parameter. By default, webcam will be used instead of the file.\n", path.toStdString().c_str()); + } + } + if(!capture_.isOpened() && images_.empty()) { //set camera device capture_.open(Settings::getCamera_1deviceId()); @@ -85,7 +166,7 @@ bool Camera::start() } } } - if(!capture_.isOpened()) + if(!capture_.isOpened() && images_.empty()) { printf("Failed to open a capture object!\n"); return false; @@ -110,7 +191,7 @@ void Camera::updateImageRate() { if(Settings::getCamera_4imageRate()) { - cameraTimer_.setInterval(1000/Settings::getCamera_4imageRate()); + cameraTimer_.setInterval((int)(1000.0/Settings::getCamera_4imageRate())); } else { diff --git a/src/Camera.h b/src/Camera.h index 326bb24a..1d1367a5 100644 --- a/src/Camera.h +++ b/src/Camera.h @@ -20,14 +20,15 @@ public: virtual bool isRunning() {return cameraTimer_.isActive();} void pause(); + int getTotalFrames(); + int getCurrentFrameIndex(); + void moveToFrame(int frame); signals: void imageReceived(const cv::Mat & image); public slots: virtual void updateImageRate(); - -private slots: virtual void takeImage(); protected: @@ -37,6 +38,8 @@ protected: private: cv::VideoCapture capture_; QTimer cameraTimer_; + QList images_; + unsigned int currentImageIndex_; }; #endif /* CAMERA_H_ */ diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 4860cb68..57a10080 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -33,6 +33,8 @@ #include #include +#include "utilite/UDirectory.h" + // Camera ownership transferred MainWindow::MainWindow(Camera * camera, QWidget * parent) : QMainWindow(parent), @@ -61,6 +63,7 @@ MainWindow::MainWindow(Camera * camera, QWidget * parent) : ui_->dockWidget_parameters->setVisible(false); ui_->dockWidget_plot->setVisible(false); + ui_->widget_controls->setVisible(false); QByteArray geometry; QByteArray state; @@ -69,7 +72,7 @@ MainWindow::MainWindow(Camera * camera, QWidget * parent) : this->restoreState(state); ui_->toolBox->setupUi(); - connect((QSpinBox*)ui_->toolBox->getParameterWidget(Settings::kCamera_4imageRate()), + connect((QDoubleSpinBox*)ui_->toolBox->getParameterWidget(Settings::kCamera_4imageRate()), SIGNAL(editingFinished()), camera_, SLOT(updateImageRate())); @@ -86,6 +89,12 @@ MainWindow::MainWindow(Camera * camera, QWidget * parent) : this, SLOT(updateMirrorView())); + ui_->widget_controls->setVisible(Settings::getGeneral_controlsShown()); + connect((QCheckBox*)ui_->toolBox->getParameterWidget(Settings::kGeneral_controlsShown()), + SIGNAL(stateChanged(int)), + this, + SLOT(showHideControls())); + //buttons connect(ui_->pushButton_restoreDefaults, SIGNAL(clicked()), ui_->toolBox, SLOT(resetCurrentPage())); connect(ui_->pushButton_updateObjects, SIGNAL(clicked()), this, SLOT(updateObjects())); @@ -106,10 +115,21 @@ MainWindow::MainWindow(Camera * camera, QWidget * parent) : connect(ui_->actionSave_objects, SIGNAL(triggered()), this, SLOT(saveObjects())); connect(ui_->actionLoad_objects, SIGNAL(triggered()), this, SLOT(loadObjects())); connect(ui_->actionCamera_from_video_file, SIGNAL(triggered()), this, SLOT(setupCameraFromVideoFile())); + connect(ui_->actionCamera_from_directory_of_images, SIGNAL(triggered()), this, SLOT(setupCameraFromImagesDirectory())); connect(ui_->actionAbout, SIGNAL(triggered()), aboutDialog_ , SLOT(exec())); connect(ui_->actionRestore_all_default_settings, SIGNAL(triggered()), ui_->toolBox, SLOT(resetAllPages())); connect(ui_->actionRemove_all_objects, SIGNAL(triggered()), this, SLOT(removeAllObjects())); + connect(ui_->pushButton_play, SIGNAL(clicked()), this, SLOT(startProcessing())); + connect(ui_->pushButton_stop, SIGNAL(clicked()), this, SLOT(stopProcessing())); + connect(ui_->pushButton_pause, SIGNAL(clicked()), this, SLOT(pauseProcessing())); + connect(ui_->horizontalSlider_frames, SIGNAL(valueChanged(int)), this, SLOT(moveCameraFrame(int))); + connect(ui_->horizontalSlider_frames, SIGNAL(valueChanged(int)), ui_->label_frame, SLOT(setNum(int))); + ui_->pushButton_play->setVisible(true); + ui_->pushButton_pause->setVisible(false); + ui_->pushButton_stop->setEnabled(true); + ui_->horizontalSlider_frames->setEnabled(false); + ui_->objects_area->addAction(ui_->actionAdd_object_from_scene); ui_->objects_area->addAction(ui_->actionAdd_objects_from_files); ui_->objects_area->setContextMenuPolicy(Qt::ActionsContextMenu); @@ -117,8 +137,8 @@ MainWindow::MainWindow(Camera * camera, QWidget * parent) : ui_->actionStart_camera->setShortcut(Qt::Key_Space); ui_->actionPause_camera->setShortcut(Qt::Key_Space); - ui_->actionCamera_from_video_file->setCheckable(true); - ui_->actionCamera_from_video_file->setChecked(!Settings::getCamera_5videoFilePath().isEmpty()); + ui_->actionCamera_from_video_file->setChecked(!Settings::getCamera_5mediaPath().isEmpty() && !UDirectory::exists(Settings::getCamera_5mediaPath().toStdString())); + ui_->actionCamera_from_directory_of_images->setChecked(!Settings::getCamera_5mediaPath().isEmpty() && UDirectory::exists(Settings::getCamera_5mediaPath().toStdString())); if(Settings::getGeneral_autoStartCamera()) { @@ -294,6 +314,11 @@ void MainWindow::updateMirrorView() } } +void MainWindow::showHideControls() +{ + ui_->widget_controls->setVisible(Settings::getGeneral_controlsShown()); +} + void MainWindow::addObjectFromScene() { disconnect(camera_, SIGNAL(imageReceived(const cv::Mat &)), this, SLOT(update(const cv::Mat &))); @@ -407,24 +432,54 @@ void MainWindow::setupCameraFromVideoFile() { if(!ui_->actionCamera_from_video_file->isChecked()) { - Settings::setCamera_5videoFilePath(""); - ui_->toolBox->updateParameter(Settings::kCamera_5videoFilePath()); + Settings::setCamera_5mediaPath(""); + ui_->toolBox->updateParameter(Settings::kCamera_5mediaPath()); } else { QString fileName = QFileDialog::getOpenFileName(this, tr("Setup camera from video file..."), Settings::workingDirectory(), tr("Video Files (%1)").arg(Settings::getGeneral_videoFormats())); if(!fileName.isEmpty()) { - Settings::setCamera_5videoFilePath(fileName); - ui_->toolBox->updateParameter(Settings::kCamera_5videoFilePath()); + Settings::setCamera_5mediaPath(fileName); + ui_->toolBox->updateParameter(Settings::kCamera_5mediaPath()); if(camera_->isRunning()) { this->stopProcessing(); this->startProcessing(); } + Settings::setGeneral_controlsShown(true); + ui_->toolBox->updateParameter(Settings::kGeneral_controlsShown()); } } - ui_->actionCamera_from_video_file->setChecked(!Settings::getCamera_5videoFilePath().isEmpty()); + ui_->actionCamera_from_video_file->setChecked(!Settings::getCamera_5mediaPath().isEmpty()); + ui_->actionCamera_from_directory_of_images->setChecked(false); +} + +void MainWindow::setupCameraFromImagesDirectory() +{ + if(!ui_->actionCamera_from_directory_of_images->isChecked()) + { + Settings::setCamera_5mediaPath(""); + ui_->toolBox->updateParameter(Settings::kCamera_5mediaPath()); + } + else + { + QString directory = QFileDialog::getExistingDirectory(this, tr("Setup camera from directory of images..."), Settings::workingDirectory()); + if(!directory.isEmpty()) + { + Settings::setCamera_5mediaPath(directory); + ui_->toolBox->updateParameter(Settings::kCamera_5mediaPath()); + if(camera_->isRunning()) + { + this->stopProcessing(); + this->startProcessing(); + } + Settings::setGeneral_controlsShown(true); + ui_->toolBox->updateParameter(Settings::kGeneral_controlsShown()); + } + } + ui_->actionCamera_from_directory_of_images->setChecked(!Settings::getCamera_5mediaPath().isEmpty()); + ui_->actionCamera_from_video_file->setChecked(false); } void MainWindow::showObject(ObjWidget * obj) @@ -543,33 +598,36 @@ void MainWindow::updateData() // Get the total size and verify descriptors for(int i=0; i= 0 && objects_.at(i)->descriptors().cols != dim) + if(!objects_.at(i)->descriptors().empty()) { - if(this->isVisible()) + if(dim >= 0 && objects_.at(i)->descriptors().cols != dim) { - QMessageBox::critical(this, tr("Error"), tr("Descriptors of the objects are not all the same size!\nObjects opened must have all the same size (and from the same descriptor extractor).")); + if(this->isVisible()) + { + QMessageBox::critical(this, tr("Error"), tr("Descriptors of the objects are not all the same size!\nObjects opened must have all the same size (and from the same descriptor extractor).")); + } + else + { + printf("ERROR: Descriptors of the objects are not all the same size! Objects opened must have all the same size (and from the same descriptor extractor).\n"); + } + return; } - else + dim = objects_.at(i)->descriptors().cols; + if(type >= 0 && objects_.at(i)->descriptors().type() != type) { - printf("ERROR: Descriptors of the objects are not all the same size! Objects opened must have all the same size (and from the same descriptor extractor).\n"); + if(this->isVisible()) + { + QMessageBox::critical(this, tr("Error"), tr("Descriptors of the objects are not all the same type!\nObjects opened must have been processed by the same descriptor extractor.")); + } + else + { + printf("ERROR: Descriptors of the objects are not all the same type! Objects opened must have been processed by the same descriptor extractor.\n"); + } + return; } - return; + type = objects_.at(i)->descriptors().type(); + count += objects_.at(i)->descriptors().rows; } - dim = objects_.at(i)->descriptors().cols; - if(type >= 0 && objects_.at(i)->descriptors().type() != type) - { - if(this->isVisible()) - { - QMessageBox::critical(this, tr("Error"), tr("Descriptors of the objects are not all the same type!\nObjects opened must have been processed by the same descriptor extractor.")); - } - else - { - printf("ERROR: Descriptors of the objects are not all the same type! Objects opened must have been processed by the same descriptor extractor.\n"); - } - return; - } - type = objects_.at(i)->descriptors().type(); - count += objects_.at(i)->descriptors().rows; } // Copy data @@ -619,6 +677,19 @@ void MainWindow::startProcessing() ui_->actionStart_camera->setEnabled(false); ui_->actionLoad_scene_from_file->setEnabled(false); ui_->label_timeRefreshRate->setVisible(true); + + //update control bar + ui_->pushButton_play->setVisible(false); + ui_->pushButton_pause->setVisible(true); + ui_->pushButton_stop->setEnabled(true); + int totalFrames = camera_->getTotalFrames(); + if(totalFrames) + { + ui_->label_frame->setVisible(true); + ui_->horizontalSlider_frames->setEnabled(true); + ui_->horizontalSlider_frames->setMaximum(totalFrames-1); + } + if(updateStatusMessage) { this->statusBar()->showMessage(tr("Camera started."), 2000); @@ -652,6 +723,12 @@ void MainWindow::stopProcessing() ui_->actionPause_camera->setEnabled(false); ui_->actionStart_camera->setEnabled(true); ui_->actionLoad_scene_from_file->setEnabled(true); + ui_->pushButton_play->setVisible(true); + ui_->pushButton_pause->setVisible(false); + ui_->pushButton_stop->setEnabled(false); + ui_->horizontalSlider_frames->setEnabled(false); + ui_->horizontalSlider_frames->setValue(0); + ui_->label_frame->setVisible(false); } void MainWindow::pauseProcessing() @@ -661,17 +738,34 @@ void MainWindow::pauseProcessing() ui_->actionStart_camera->setEnabled(false); if(camera_->isRunning()) { + ui_->pushButton_play->setVisible(true); + ui_->pushButton_pause->setVisible(false); camera_->pause(); } else { + ui_->pushButton_play->setVisible(false); + ui_->pushButton_pause->setVisible(true); camera_->start(); } } +void MainWindow::moveCameraFrame(int frame) +{ + if(ui_->horizontalSlider_frames->isEnabled()) + { + camera_->moveToFrame(frame); + if(!camera_->isRunning()) + { + camera_->takeImage(); + } + } +} + void MainWindow::update(const cv::Mat & image) { - updateRate_.start(); + QTime totalTime; + totalTime.start(); // reset objects color for(int i=0; ilabel_detectorDescriptorType->setText(QString("%1/%2").arg(Settings::currentDetectorType()).arg(Settings::currentDescriptorType())); - int ms = updateRate_.restart(); - ui_->label_timeTotal->setNum(ms); - int refreshRate = qRound(1000.0f/float(ms)); + //update slider + if(ui_->horizontalSlider_frames->isEnabled()) + { + ui_->horizontalSlider_frames->blockSignals(true); + ui_->horizontalSlider_frames->setValue(camera_->getCurrentFrameIndex()-1); + ui_->label_frame->setNum(camera_->getCurrentFrameIndex()-1); + ui_->horizontalSlider_frames->blockSignals(false); + } + + ui_->label_timeTotal->setNum(totalTime.elapsed()); + int refreshRate = qRound(1000.0f/float(updateRate_.restart())); if(refreshRate > 0 && refreshRate < lowestRefreshRate_) { lowestRefreshRate_ = refreshRate; @@ -1000,7 +1102,7 @@ void MainWindow::update(const cv::Mat & image) // Refresh the label only after each 1000 ms if(refreshStartTime_.elapsed() > 1000) { - if(Settings::getCamera_4imageRate()>0) + if(Settings::getCamera_4imageRate()>0.0) { ui_->label_timeRefreshRate->setText(QString("(%1 Hz - %2 Hz)").arg(QString::number(Settings::getCamera_4imageRate())).arg(QString::number(lowestRefreshRate_))); } @@ -1030,5 +1132,7 @@ void MainWindow::notifyParametersChanged() ui_->label_timeRefreshRate->setVisible(false); } - ui_->actionCamera_from_video_file->setChecked(!Settings::getCamera_5videoFilePath().isEmpty()); + ui_->actionCamera_from_video_file->setChecked(!Settings::getCamera_5mediaPath().isEmpty() && !UDirectory::exists(Settings::getCamera_5mediaPath().toStdString())); + ui_->actionCamera_from_directory_of_images->setChecked(!Settings::getCamera_5mediaPath().isEmpty() && UDirectory::exists(Settings::getCamera_5mediaPath().toStdString())); + } diff --git a/src/MainWindow.h b/src/MainWindow.h index 048dea48..054ff1a7 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -57,13 +57,16 @@ private slots: void addObjectsFromFiles(); void loadSceneFromFile(); void setupCameraFromVideoFile(); + void setupCameraFromImagesDirectory(); void removeObject(ObjWidget * object); void removeAllObjects(); void updateObjectsSize(); void updateMirrorView(); + void showHideControls(); void update(const cv::Mat & image); void updateObjects(); void notifyParametersChanged(); + void moveCameraFrame(int frame); signals: void objectsFound(const QMap > &); diff --git a/src/ParametersToolBox.cpp b/src/ParametersToolBox.cpp index eb407229..39b1d875 100644 --- a/src/ParametersToolBox.cpp +++ b/src/ParametersToolBox.cpp @@ -104,6 +104,8 @@ void ParametersToolBox::setupUi() currentItem->setObjectName(group); QVBoxLayout * layout = new QVBoxLayout(currentItem); currentItem->setLayout(layout); + layout->setContentsMargins(0,0,0,0); + layout->setSpacing(0); layout->addSpacerItem(new QSpacerItem(0,0, QSizePolicy::Minimum, QSizePolicy::Expanding)); addParameter(layout, iter.key(), iter.value()); diff --git a/src/Settings.h b/src/Settings.h index a1b1bda8..e3628d55 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -55,8 +55,8 @@ class Settings PARAMETER(Camera, 1deviceId, int, 0); PARAMETER(Camera, 2imageWidth, int, 640); PARAMETER(Camera, 3imageHeight, int, 480); - PARAMETER(Camera, 4imageRate, int, 2); // Hz - PARAMETER(Camera, 5videoFilePath, QString, ""); + PARAMETER(Camera, 4imageRate, double, 2.0); // Hz + PARAMETER(Camera, 5mediaPath, QString, ""); //List format : [Index:item0;item1;item3;...] PARAMETER(Detector_Descriptor, 1Detector, QString, "7:Dense;Fast;GFTT;MSER;ORB;SIFT;Star;SURF"); @@ -155,6 +155,7 @@ class Settings PARAMETER(General, videoFormats, QString, "*.avi *.m4v *.mp4"); PARAMETER(General, mirrorView, bool, true); PARAMETER(General, invertedSearch, bool, false); + PARAMETER(General, controlsShown, bool, false); PARAMETER(Homography, homographyComputed, bool, true); PARAMETER(Homography, ransacReprojThr, double, 1.0); diff --git a/src/resources.qrc b/src/resources.qrc index 225f507a..579bf5b0 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -1,5 +1,8 @@ resources/Find-Object.png + resources/TheWorkingGroup_video_pause.ico + resources/TheWorkingGroup_video_play.ico + resources/TheWorkingGroup_video_stop.ico diff --git a/src/resources/TheWorkingGroup_video_pause.ico b/src/resources/TheWorkingGroup_video_pause.ico new file mode 100644 index 0000000000000000000000000000000000000000..17accbfa0822682f9da0f99a7c48d1fe8bfd82d6 GIT binary patch literal 32038 zcmeI4J#rLD5QR$-8~_Y_$=C=??6ssd_6XSE?JWjQz%|xdTe7&>_Exp#V~d>5&Sd7H zR)=aLn%DJ{@5?G>mxe*2l&kWpynbEk>$?2)s+2$5-SuPp@7n)Q?R)?J*#51Q4{uAk zy?t!I`=gY9e=p@-Z8nSRdR@(b);TrKzNTrqdU$yFRIhL5`r5{h<6q5KoBOF7Kh*YQ zu5aCVn{USt-S~(<-Jh|4|JUEBpVRv2pP#dz-%_UOlB=CF*Y&!s7w639`RuA4-HT_v zX*~vzx3 z`o8MP&j0>BTz{Wfo11@ITOxjKZ&J@Mj6U!Fo^eOr{Hw>4=I`XUwm+kO*54n!g!(z0 zSvPZCwHlwC^S_Pt&(Rt8nf+hQKfzqh|B}6_u@~nLe`OuNEdR>P!mhed>K^Kc{tDug~@3=d?=womTs@U$@cz{=2&K_r3aT$TYjRN+w=eHuH#6D&CPQ znRrD^J5HQZEyHUonRt0Dub()jdMw+oWa4ERQJXlWMoh+)OuX>UDsf8P1DhO`>&6T3 zNSUwHh-t@_Y`iSPYcpS|9?R=jvhng*wx9V*wT!5(WaAYv8E3vy@y@D}jn^L7->be&#FHGNQJUjaS5EocT({JF7}I zUVC7ZBRMM-??{zQydtI@Cr+uB;kA`aygZiIPn=RcmhD$E@v@AlO`K9ACgVybUU+Af zIHm4^O^(WSyta~wm&fw@iBqb_vi(XXUX~HHiBoFCWL(L_ z3-7EFr_?>L$x*p(yzq{c`AUtLc3jEE%QCz+^OfqcynZDcFOOyWnXgpKh}udvUJ;XV z<|`HNtSZ@f?SV~>pI!aZ2@AwqMD_%QB)iaY~Jt zj4PRV;hk0Dl)48tIV#tU7v7OFU#St(jw{)CS%%kUzEVAw*RN#b<*{r(^Ob5DQCrEz pD`GOve5K-@RV5p*J+R4v|rW^{0EeY%>DoX literal 0 HcmV?d00001 diff --git a/src/resources/TheWorkingGroup_video_play.ico b/src/resources/TheWorkingGroup_video_play.ico new file mode 100644 index 0000000000000000000000000000000000000000..1bdf4b6a35dcc4038b9b38ecb2b40e755b8d0588 GIT binary patch literal 32038 zcmeHPO=w+36u!ZVxR6w&3z707rL>`oR=OxC@=`^M6v;wxQzUj#6iNxjMG+}!7p|lP zaUoqu5jTS9L$YXs$fJmexOfW@7a~Era3K@Vs38x`S5c^ z@z2vmaTt$OF$0;}`WJ1`ulyMfhf|cbwY5daKJo0DqHiDa2jq-v-;sUxAC6=N=@Tw` z&|dCOJsXg7wmKC31(vT+_hgkGLx1Y|3vvPSfKE?Ee}Uy2w3}7wuTYKJtgX^Qpx@%^2?BitNO_GqyD#% zJ};Ns=F#swBG#EJTWc2zq>r#CQeb@+QhU7-dg`XIy#(QU z^-5hGP5O=Oi+SC{^Zq9KT>F;n69?DJ1y?-%G6KmC2@D=V1Rcw6&gBvJF$-!anEKf=Ne{x(fSz&kuSA*4XE~x&)~` zuWWsyu>T{<8l7ouZL?j;zVrLKi!D{#k^S25`zoC-Ww6ipZ|D007aMY0=_(*emiH9A zGJPE~zNf(5Y55~#mhySlnMfSgDEAzyl9=>g`GkRkB%p5i*B z6U(*_JHWezAE`Ja|Azb`_;}yjeBdqXP~azzdytR8;RMpG=LPVU{l7I1z|K97cfA+N zoO62C;YYcMC#GLQo&l#?@8lu*TH+^%b;xDN|Gr}giLXkx4nKT7_P><>8|^t3*54mg z*>75}!;kVYentLIlwF1Fhg5!t(iEeqKkO^#FUn2$McoS8orWZv7dre>%y4fLc+2@s z^uLYzcT;iD;Yaxxvt|B!w0j9$tnbQ9aba8M5kL8IEZ&E7Z0$E~r^62nWB=Rap+~gm zzSoDGf&`!2u+e1x3e2kX9&}#^_X8n$1jN6^3HWcp#u>Pg)k@1t$2FBwfq+ZS-I{b2M*yN!{A1 zwE$_fccXvI_)+n>3I7}cj#}^D8Q>=;-qG>?ze;;~y*WTzX?24W38{+>J z{ojTJk8>S2%(e0PA9>p|*L}3*Z(LqL+GzjR;j%3UhLbXGIgdIOpSvjMx_HFaM#y%= zufbWy&a(@@k2w_*kE?F@dyL=Ud!Es60DH9GG1&3|rmFbicNXV>Kg;hUi62sq6+ZLK z#l2|O))y(-0iO#0?jHnuA<{h~H@y_?y=9M>Tf4 zW!rztEBt`D#`m;&@x0Sga2Mx=9`ecFJyQ8y;!i*9xL7Fhmt&!mYD{9<)$kXwuox3d z3R?#LA{P2+(@B9XhD{6p6CDed{3kXR9Qg}BEX9b;7&dD1rymB8?Cx+}eb#{gM8tvz z{;iG$Py9tJEJI(b&d{Fu(+}&AuIoHZ)jk0KR>eX<{;i0G!2Gk1g-HDAhb-T%Bk~uq z(1Xov_J{=hvx!b;%759{y4W)Q>%iOf#hrRu#6QS;V+;6i z0OP#RF_(2^&c6?Q9T~6he8&8vyc1@~-}@eKikZy#d)wDcoaMSq_5pZnTT8~wSrslk64eX`%zZ2j)QpKIK_t=_h@v*h2Kq%oJrrh-4md_itM zX?X*GzN2?0jc=KchW}Ez-K0L3_z&V_%5TpPXgck-O%Ie_LK zL2_s3hGSSbxs*-0EBE(Bu5I~!SIQ5Kw&VRD8UHI|kB=|+UrYJN8tuJ89-KPtV>Z1MV7zVS{c-kIJ5{y3Xom{?zY?%43#4@;{!vEPr#?k$>{98kno2 z?0V{t`lJ4M{<8itcOCtQ{zLzv|IGD~?0WMbWbZx-fQ0%vg??oEOIrP$LOwg4UPz9X z%6&W@_tFm9L^HM5c*SjR^}pZ_{oOBf>%2&uJwt(YhYbF}zO}v!&u#E4m&T{{7tTMo z&IW%JtFJ8*NB2$4OW{xCnalIJ^$mXI()hG~MOb?^H29-feQl9Ax^H4$3V$L`kGmzt z8vM$o@oD{vu=eV0@JF%w+9Gju-^9EW{zRT0cT0>l_?1iJ)A|)*?bX}hk7D(;MdIkb ziFqmfi99{-mKbaBE0@Nn^((^KtGB@)#p-K|#L;~d^HTT|d3xL}G1lN$E{#v?SA?}! zZ-YOI)z=n@qx&Z2rSK>6^tfAMtii8b8lTp$2y3t227eT*uPqWs_f5<@i{Il)?Azn& z5@Qv=U_7iC=egP|e&M^~zY^}XrY?Sc4p&k`#ZUb}-czdld;L>CANDM|{9no0rT^sK z|2_A+C^LRD`nh)h@8S37*vIOxD`{0fJ^YH%$WE&tbG0kiEw*ariqux=wH(w2#I%cj3Oi zzcH-fyFOVA4yJp4Lv2pJ1 zK;~rq?fFGM3q)={e?EV&0fYvTIeqOKBe5WIvwog`uK|PxkvVYx7aHGt3{GN-Sd{!jl$Y7vo}`ltVU4Ing#%;{^V|I`1G zT14cg{^|c-0|*TwbNbrp|MY*P77@9rfBL`I078SvoW6GYKm8x6MMQ4upZ@PPfY2Z^ zr>~v1(I|)BllLMC7La>Hl5>2n`~0`r7IL?OB*|!~5Ii NXZrsDc>lQ=_zwXpb=d#_ literal 0 HcmV?d00001 diff --git a/src/ui/mainWindow.ui b/src/ui/mainWindow.ui index 547d0e80..09ca75c2 100644 --- a/src/ui/mainWindow.ui +++ b/src/ui/mainWindow.ui @@ -18,7 +18,7 @@ :/images/resources/Find-Object.png:/images/resources/Find-Object.png - + 0 @@ -26,101 +26,169 @@ 0 - - - 0 - + - - - - - - 75 - true - - - - Camera - - - - - - - (0 Hz - 0 Hz) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - features - - - - + + + + 75 + true + + + + Camera + + - - - QFrame::StyledPanel + + + (0 Hz - 0 Hz) - - QFrame::Raised + + + + + + Qt::Horizontal - + + + 40 + 20 + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + features + + + + + + + + + + + + + - 0 + -1 0 - + + + + 0 + 0 + + + + + 24 + 24 + + + + + + + + :/images/resources/TheWorkingGroup_video_play.ico:/images/resources/TheWorkingGroup_video_play.ico + + + + + + + + 24 + 24 + + + + + + + + :/images/resources/TheWorkingGroup_video_pause.ico:/images/resources/TheWorkingGroup_video_pause.ico + + + + + + + + 24 + 24 + + + + + + + + :/images/resources/TheWorkingGroup_video_stop.ico:/images/resources/TheWorkingGroup_video_stop.ico + + + + + + + Qt::ClickFocus + + + 0 + + + Qt::Horizontal + + + + + + + 0 + + @@ -160,6 +228,7 @@ + @@ -444,7 +513,7 @@ 0 0 - 265 + 222 557 @@ -492,6 +561,9 @@ 0 + + Qt::ClickFocus + 100 @@ -535,6 +607,9 @@ + + true + Add object from scene... @@ -585,6 +660,9 @@ + + true + Camera from video file... @@ -594,6 +672,14 @@ Remove all objects + + + true + + + Camera from directory of images... + + diff --git a/src/utilite/UDirectory.cpp b/src/utilite/UDirectory.cpp new file mode 100644 index 00000000..2e4b1dcf --- /dev/null +++ b/src/utilite/UDirectory.cpp @@ -0,0 +1,348 @@ +// Taken from UtiLite library r185 [www.utilite.googlecode.com] + +/* +* utilite is a cross-platform library with +* useful utilities for fast and small developing. +* Copyright (C) 2010 Mathieu Labbe +* +* utilite is free library: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* utilite is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +*/ + +#include "utilite/UDirectory.h" + +#ifdef WIN32 + #include + #include + #include + #include +#else + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +#include "utilite/UStl.h" +#include "utilite/UFile.h" +#include "utilite/UDirectory.h" + +#ifdef WIN32 + +bool sortCallback(const std::string & a, const std::string & b) +{ + return uStrNumCmp(a,b) < 0; +} +#elif __APPLE__ +int sortCallback(const void * aa, const void * bb) +{ + const struct dirent ** a = (const struct dirent **)aa; + const struct dirent ** b = (const struct dirent **)bb; + + return uStrNumCmp((*a)->d_name, (*b)->d_name); +} +#else +int sortCallback( const dirent ** a, const dirent ** b) +{ + return uStrNumCmp((*a)->d_name, (*b)->d_name); +} +#endif + +UDirectory::UDirectory(const std::string & path, const std::string & extensions) +{ + extensions_ = uListToVector(uSplit(extensions, ' ')); + path_ = path; + iFileName_ = fileNames_.begin(); + this->update(); +} + +UDirectory::UDirectory(const UDirectory & dir) +{ + *this = dir; +} + +UDirectory & UDirectory::operator=(const UDirectory & dir) +{ + extensions_ = dir.extensions_; + path_ = dir.path_; + fileNames_ = dir.fileNames_; + for(iFileName_=fileNames_.begin(); iFileName_!=fileNames_.end(); ++iFileName_) + { + if(iFileName_->compare(*dir.iFileName_) == 0) + { + break; + } + } + return *this; +} + +UDirectory::~UDirectory() +{ +} + +void UDirectory::setPath(const std::string & path, const std::string & extensions) +{ + extensions_ = uListToVector(uSplit(extensions, ' ')); + path_ = path; + fileNames_.clear(); + iFileName_ = fileNames_.begin(); + this->update(); +} + +void UDirectory::update() +{ + if(exists(path_)) + { + std::string lastName; + bool endOfDir = false; + if(iFileName_ != fileNames_.end()) + { + //Record the last file name + lastName = *iFileName_; + } + else if(fileNames_.size()) + { + lastName = *fileNames_.rbegin(); + endOfDir = true; + } + fileNames_.clear(); +#ifdef WIN32 + WIN32_FIND_DATA fileInformation; + HANDLE hFile = ::FindFirstFile((path_+"\\*").c_str(), &fileInformation); + if(hFile != INVALID_HANDLE_VALUE) + { + do + { + fileNames_.push_back(fileInformation.cFileName); + } while(::FindNextFile(hFile, &fileInformation) == TRUE); + ::FindClose(hFile); + std::vector vFileNames = uListToVector(fileNames_); + std::sort(vFileNames.begin(), vFileNames.end(), sortCallback); + fileNames_ = uVectorToList(vFileNames); + } +#else + int nameListSize; + struct dirent ** nameList = 0; + nameListSize = scandir(path_.c_str(), &nameList, 0, sortCallback); + if(nameList && nameListSize>0) + { + for (int i=0;id_name); + free(nameList[i]); + } + free(nameList); + } +#endif + + //filter extensions... + std::list::iterator iter = fileNames_.begin(); + bool valid; + while(iter!=fileNames_.end()) + { + valid = false; + if(extensions_.size() == 0 && + iter->compare(".") != 0 && + iter->compare("..") != 0) + { + valid = true; + } + for(unsigned int i=0; i::iterator iter=fileNames_.begin(); iter!=fileNames_.end(); ++iter) + { + if(lastName.compare(*iter) == 0) + { + found = true; + iFileName_ = iter; + break; + } + } + if(endOfDir && found) + { + ++iFileName_; + } + else if(endOfDir && fileNames_.size()) + { + iFileName_ = --fileNames_.end(); + } + } + } +} + +bool UDirectory::isValid() +{ + return exists(path_); +} + +std::string UDirectory::getNextFileName() +{ + std::string fileName; + if(iFileName_ != fileNames_.end()) + { + fileName = *iFileName_; + ++iFileName_; + } + return fileName; +} + +void UDirectory::rewind() +{ + iFileName_ = fileNames_.begin(); +} + + +bool UDirectory::exists(const std::string & dirPath) +{ + bool r = false; +#if WIN32 + DWORD dwAttrib = GetFileAttributes(dirPath.c_str()); + r = (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +#else + DIR *dp; + if((dp = opendir(dirPath.c_str())) != NULL) + { + r = true; + closedir(dp); + } +#endif + return r; +} + +// return the directory path of the file +std::string UDirectory::getDir(const std::string & filePath) +{ + std::string dir = filePath; + int i=dir.size()-1; + for(; i>=0; --i) + { + if(dir[i] == '/' || dir[i] == '\\') + { + //remove separators... + dir[i] = 0; + --i; + while(i>=0 && (dir[i] == '/' || dir[i] == '\\')) + { + dir[i] = 0; + --i; + } + break; + } + else + { + dir[i] = 0; + } + } + + if(i<0) + { + dir = "."; + } + else + { + dir.resize(i+1); + } + + return dir; +} + +std::string UDirectory::currentDir(bool trailingSeparator) +{ + std::string dir; + char * buffer; + +#ifdef WIN32 + buffer = _getcwd(NULL, 0); +#else + buffer = getcwd(NULL, MAXPATHLEN); +#endif + + if( buffer != NULL ) + { + dir = buffer; + free(buffer); + if(trailingSeparator) + { + dir += separator(); + } + } + + return dir; +} + +bool UDirectory::makeDir(const std::string & dirPath) +{ + int status; +#if WIN32 + status = _mkdir(dirPath.c_str()); +#else + status = mkdir(dirPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +#endif + return status==0; +} + +bool UDirectory::removeDir(const std::string & dirPath) +{ + int status; +#if WIN32 + status = _rmdir(dirPath.c_str()); +#else + status = rmdir(dirPath.c_str()); +#endif + return status==0; +} + +std::string UDirectory::homeDir() +{ + std::string path; +#if WIN32 + char profilePath[250]; + ExpandEnvironmentStrings("%userprofile%",profilePath,250); + path = profilePath; +#else + path = getenv("HOME"); +#endif + return path; +} + +std::string UDirectory::separator() +{ +#ifdef WIN32 + return "\\"; +#else + return "/"; +#endif +} diff --git a/src/utilite/UDirectory.h b/src/utilite/UDirectory.h new file mode 100644 index 00000000..0711cdd6 --- /dev/null +++ b/src/utilite/UDirectory.h @@ -0,0 +1,139 @@ +// Taken from UtiLite library r185 [www.utilite.googlecode.com] + +/* +* utilite is a cross-platform library with +* useful utilities for fast and small developing. +* Copyright (C) 2010 Mathieu Labbe +* +* utilite is free library: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* utilite is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +*/ + +#ifndef UDIRECTORY_H +#define UDIRECTORY_H + +//#include "utilite/UtiLiteExp.h" // DLL export/import defines + +#include +#include +#include + +/** + * Class UDirectory. + * + * This class can be used to get file names in a directory. + */ +class UDirectory +{ +public: + /** + * Check if a directory exists. + * @param dirPath the directory path + * @return true if the directory exists + */ + static bool exists(const std::string & dirPath); + + /** + * Get the directory path of a file path. + * @param filePath the file path + * @return the directory path of the file + */ + static std::string getDir(const std::string & filePath); + + /** + * Get the current directory. + * @param trailingSeparator If true, a '/' is added to the path. + * @return the current directory + */ + static std::string currentDir(bool trailingSeparator = false); + + /** + * Make a directory. + * @param dirPath the directory path + * @return true on success, false otherwise. + */ + static bool makeDir(const std::string & dirPath); + + /** + * Remove a directory. + * @param dirPath the directory path + * @return true on success, false otherwise. + */ + static bool removeDir(const std::string & dirPath); + + /** + * Return the "home" directory. + * @return the directory path. + */ + static std::string homeDir(); + + /** + * Return \ (Win32) or / (Unix) depending of the platform. + */ + static std::string separator(); + +public: + /** + * Create a UDirectory object with path initialized to an existing "path" and with filter "extensions". + * @param path the path to an existing directory + * @param extensions filter to get only file names with the extensions specified, format is a + * list of extensions separated by a space: "jpg bmp" get only file names finishing by jpg or bmp. + */ + UDirectory(const std::string & path = "", const std::string & extensions = ""); + UDirectory(const UDirectory & dir); + UDirectory & operator=(const UDirectory & dir); + ~UDirectory(); + + /** + * Set path of the directory. + * @param path the new directory path. + */ + void setPath(const std::string & path, const std::string & extensions = ""); + + /** + * Update indexed file names (if the directory changed). + */ + void update(); + + /** + * Check is the directory exists. + * @return if directory exists. + */ + bool isValid(); + + /** + * Get the next file name. + * @return the next file name + */ + std::string getNextFileName(); + + /** + * Get all file names. + * @see UDirectory() + * @return all the file names in directory matching the set extensions. + */ + const std::list & getFileNames() const {return fileNames_;} + + /** + * Return the pointer of file names to beginning. + */ + void rewind(); + +private: + std::string path_; + std::vector extensions_; + std::list fileNames_; + std::list::iterator iFileName_; +}; + +#endif /* UDIRECTORY_H */ diff --git a/src/utilite/UFile.cpp b/src/utilite/UFile.cpp new file mode 100644 index 00000000..3f9a395f --- /dev/null +++ b/src/utilite/UFile.cpp @@ -0,0 +1,97 @@ +// Taken from UtiLite library r185 [www.utilite.googlecode.com] + +/* +* utilite is a cross-platform library with +* useful utilities for fast and small developing. +* Copyright (C) 2010 Mathieu Labbe +* +* utilite is free library: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* utilite is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +*/ + +#include "utilite/UFile.h" + +#include +#include "utilite/UStl.h" + +bool UFile::exists(const std::string &filePath) +{ + bool fileExists = false; + std::ifstream in(filePath.c_str(), std::ios::in); + if (in.is_open()) + { + fileExists = true; + in.close(); + } + return fileExists; +} + +long UFile::length(const std::string &filePath) +{ + long fileSize = 0; + FILE* fp = 0; +#ifdef _MSC_VER + fopen_s(&fp, filePath.c_str(), "rb"); +#else + fp = fopen(filePath.c_str(), "rb"); +#endif + if(fp == NULL) + { + return 0; + } + + fseek(fp , 0 , SEEK_END); + fileSize = ftell(fp); + fclose(fp); + + return fileSize; +} + +int UFile::erase(const std::string &filePath) +{ + return remove(filePath.c_str()); +} + +int UFile::rename(const std::string &oldFilePath, + const std::string &newFilePath) +{ + return rename(oldFilePath.c_str(), newFilePath.c_str()); +} + +std::string UFile::getName(const std::string & filePath) +{ + std::string fullPath = filePath; + std::string name; + for(int i=fullPath.size()-1; i>=0; --i) + { + if(fullPath[i] == '/' || fullPath[i] == '\\') + { + break; + } + else + { + name.insert(name.begin(), fullPath[i]); + } + } + return name; +} + +std::string UFile::getExtension(const std::string &filePath) +{ + std::list list = uSplit(filePath, '.'); + if(list.size()) + { + return list.back(); + } + return ""; +} diff --git a/src/utilite/UFile.h b/src/utilite/UFile.h new file mode 100644 index 00000000..9ed8f7ec --- /dev/null +++ b/src/utilite/UFile.h @@ -0,0 +1,137 @@ +// Taken from UtiLite library r185 [www.utilite.googlecode.com] + +/* +* utilite is a cross-platform library with +* useful utilities for fast and small developing. +* Copyright (C) 2010 Mathieu Labbe +* +* utilite is free library: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* utilite is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +*/ + +#ifndef FILE_H +#define FILE_H + +//#include "utilite/UtiLiteExp.h" // DLL export/import defines + +#include "utilite/UDirectory.h" +#include + +/** + * Class UFile. + * + * This class can be used to modify/erase files on hard drive. + */ +class UFile +{ +public: + /** + * Check if a file exists. + * @param filePath the file path + * @return true if the file exists, otherwise false. + */ + static bool exists(const std::string &filePath); + + /** + * Get the file length. + * @param filePath the file path + * @return long the length of the file in bytes. Return -1 if the file doesn't exist. + */ + static long length(const std::string &filePath); + + /** + * Erase a file. + * @param filePath the file path + * @return 0 if success. + */ + static int erase(const std::string &filePath); + + /** + * Rename a file. + * @param oldFilePath the old file path + * @param newFilePath the new file path + * @return 0 if success. + */ + static int rename(const std::string &oldFilePath, + const std::string &newFilePath); + + /** + * Get the file name from a file path (with extension). + * @param filePath the file path + * @return the file name. + */ + static std::string getName(const std::string & filePath); + + static std::string getExtension(const std::string &filePath); + +public: + /** + * Create a UFile object with path initialized to an existing file . + * @param path the path to an existing file + */ + UFile(const std::string & path) : path_(path) {} + ~UFile() {} + + /** + * Check if the file exists. Same as exists(). + * @return true if the path exits + */ + bool isValid() {return exists(path_);} + + /** + * Check if the file exists. + * @return true if the path exits + */ + bool exists() {return exists(path_);} + + /** + * Get the length of the file. + * @return long the length of the file in bytes. Return -1 if the file doesn't exist. + */ + long length() {return length(path_);} + + /** + * Rename the file name. The path stays the same. + * @param the new name + */ + int rename(const std::string &newName) + { + std::string ext = this->getExtension(); + std::string newPath = UDirectory::getDir(path_) + std::string("/") + newName; + if(ext.size()) + { + newPath += std::string(".") + getExtension(path_); + } + int result = rename(path_, newPath); + if(result == 0) + { + path_ = newPath; + } + return result; + } + /** + * Get the file name without the path. + * @return the file name + */ + std::string getName() {return getName(path_);} + /** + * Get the file extension. + * @return the file extension + */ + std::string getExtension() {return getExtension(path_);} + +private: + std::string path_; +}; + +#endif diff --git a/src/utilite/UStl.h b/src/utilite/UStl.h new file mode 100644 index 00000000..ceccb6fc --- /dev/null +++ b/src/utilite/UStl.h @@ -0,0 +1,593 @@ +// Taken from UtiLite library r185 [www.utilite.googlecode.com] + +/* +* utilite is a cross-platform library with +* useful utilities for fast and small developing. +* Copyright (C) 2010 Mathieu Labbe +* +* utilite is free library: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* utilite is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +*/ + +#ifndef USTL_H +#define USTL_H + +#include +#include +#include +#include +#include +#include + +/** + * \file UStl.h + * \brief Wrappers of STL for convenient functions. + * + * All functions you will find here are here + * for the use of STL in a more convenient way. + */ + + +/** + * Get unique keys from a std::multimap. + * @param mm the multimap + * @return the list which contains unique keys + */ +template +inline std::list uUniqueKeys(const std::multimap & mm) +{ + std::list l; + typename std::list::reverse_iterator lastValue; + for(typename std::multimap::const_iterator iter = mm.begin(); iter!=mm.end(); ++iter) + { + if(iter == mm.begin() || (iter != mm.begin() && *lastValue != iter->first)) + { + l.push_back(iter->first); + lastValue = l.rbegin(); + } + } + return l; +} + +/** + * Get all keys from a std::multimap. + * @param mm the multimap + * @return the list which contains all keys (may contains duplicated keys) + */ +template +inline std::list uKeys(const std::multimap & mm) +{ + std::list l; + for(typename std::multimap::const_iterator iter = mm.begin(); iter!=mm.end(); ++iter) + { + l.push_back(iter->first); + } + return l; +} + +/** + * Get all values from a std::multimap. + * @param mm the multimap + * @return the list which contains all values (contains values from duplicated keys) + */ +template +inline std::list uValues(const std::multimap & mm) +{ + std::list l; + for(typename std::multimap::const_iterator iter = mm.begin(); iter!=mm.end(); ++iter) + { + l.push_back(iter->second); + } + return l; +} + +/** + * Get values for a specified key from a std::multimap. + * @param mm the multimap + * @param key the key + * @return the list which contains the values of the key + */ +template +inline std::list uValues(const std::multimap & mm, const K & key) +{ + std::list l; + std::pair::const_iterator, typename std::multimap::const_iterator> range; + range = mm.equal_range(key); + for(typename std::multimap::const_iterator iter = range.first; iter!=range.second; ++iter) + { + l.push_back(iter->second); + } + return l; +} + +/** + * Get all keys from a std::map. + * @param m the map + * @return the vector of keys + */ +template +inline std::vector uKeys(const std::map & m) +{ + std::vector v(m.size()); + int i=0; + for(typename std::map::const_iterator iter = m.begin(); iter!=m.end(); ++iter) + { + v[i] = iter->first; + ++i; + } + return v; +} + +/** + * Get all keys from a std::map. + * @param m the map + * @return the list of keys + */ +template +inline std::list uKeysList(const std::map & m) +{ + std::list l; + for(typename std::map::const_iterator iter = m.begin(); iter!=m.end(); ++iter) + { + l.push_back(iter->first); + } + return l; +} + +/** + * Get all keys from a std::map. + * @param m the map + * @return the set of keys + */ +template +inline std::set uKeysSet(const std::map & m) +{ + std::set s; + int i=0; + for(typename std::map::const_iterator iter = m.begin(); iter!=m.end(); ++iter) + { + s.insert(s.end(), iter->first); + ++i; + } + return s; +} + +/** + * Get all values from a std::map. + * @param m the map + * @return the vector of values + */ +template +inline std::vector uValues(const std::map & m) +{ + std::vector v(m.size()); + int i=0; + for(typename std::map::const_iterator iter = m.begin(); iter!=m.end(); ++iter) + { + v[i] = iter->second; + ++i; + } + return v; +} + +/** + * Get all values from a std::map. + * @param m the map + * @return the list of values + */ +template +inline std::list uValuesList(const std::map & m) +{ + std::list l; + for(typename std::map::const_iterator iter = m.begin(); iter!=m.end(); ++iter) + { + l.push_back(iter->second); + } + return l; +} + +/** + * Get the value of a specified key from a std::map. + * @param m the map + * @param key the key + * @param defaultValue the default value used if the key is not found + * @return the value + */ +template +inline V uValue(const std::map & m, const K & key, const V & defaultValue = V()) +{ + V v = defaultValue; + typename std::map::const_iterator i = m.find(key); + if(i != m.end()) + { + v = i->second; + } + return v; +} + +/** + * Get the value of a specified key from a std::map. This will + * remove the value from the map; + * @param m the map + * @param key the key + * @param defaultValue the default value used if the key is not found + * @return the value + */ +template +inline V uTake(std::map & m, const K & key, const V & defaultValue = V()) +{ + V v; + typename std::map::iterator i = m.find(key); + if(i != m.end()) + { + v = i->second; + m.erase(i); + } + else + { + v = defaultValue; + } + return v; +} + +/** + * Get the iterator at a specified position in a std::list. If the position + * is out of range, the result is the end iterator of the list. + * @param list the list + * @param pos the index position in the list + * @return the iterator at the specified index + */ +template +inline typename std::list::iterator uIteratorAt(std::list & list, const unsigned int & pos) +{ + typename std::list::iterator iter = list.begin(); + for(unsigned int i = 0; i +inline typename std::list::const_iterator uIteratorAt(const std::list & list, const unsigned int & pos) +{ + typename std::list::const_iterator iter = list.begin(); + for(unsigned int i = 0; i +inline typename std::vector::iterator uIteratorAt(std::vector & v, const unsigned int & pos) +{ + return v.begin() + pos; +} + +/** + * Get the value at a specified position in a std::list. If the position + * is out of range, the result is undefined. + * @param list the list + * @param pos the index position in the list + * @return the value at the specified index + */ +template +inline V & uValueAt(std::list & list, const unsigned int & pos) +{ + typename std::list::iterator iter = uIteratorAt(list, pos); + return *iter; +} + +/** + * Get the value at a specified position in a std::list. If the position + * is out of range, the result is undefined. + * @param list the list + * @param pos the index position in the list + * @return the value at the specified index + */ +template +inline const V & uValueAt(const std::list & list, const unsigned int & pos) +{ + typename std::list::const_iterator iter = uIteratorAt(list, pos); + return *iter; +} + +/** + * Check if the list contains the specified value. + * @param list the list + * @param value the value + * @return true if the value is found in the list, otherwise false + */ +template +inline bool uContains(const std::list & list, const V & value) +{ + return std::find(list.begin(), list.end(), value) != list.end(); +} + +/** + * Check if the map contains the specified key. + * @param map the map + * @param key the key + * @return true if the value is found in the map, otherwise false + */ +template +inline bool uContains(const std::map & map, const K & key) +{ + return map.find(key) != map.end(); +} + +/** + * Check if the multimap contains the specified key. + * @param map the map + * @param key the key + * @return true if the value is found in the map, otherwise false + */ +template +inline bool uContains(const std::multimap & map, const K & key) +{ + return map.find(key) != map.end(); +} + +/** + * Insert an item in the map. Contrary to the insert in the STL, + * if the key already exists, the value will be replaced by the new one. + */ +template +inline void uInsert(std::map & map, const std::pair & pair) +{ + std::pair::iterator, bool> inserted = map.insert(pair); + if(inserted.second == false) + { + inserted.first->second = pair.second; + } +} + +/** + * Convert a std::list to a std::vector. + * @param list the list + * @return the vector + */ +template +inline std::vector uListToVector(const std::list & list) +{ + return std::vector(list.begin(), list.end()); +} + +/** + * Convert a std::vector to a std::list. + * @param v the vector + * @return the list + */ +template +inline std::list uVectorToList(const std::vector & v) +{ + return std::list(v.begin(), v.end()); +} + +/** + * Append a list to another list. + * @param list the list on which the other list will be appended + * @param newItems the list of items to be appended + */ +template +inline void uAppend(std::list & list, const std::list & newItems) +{ + list.insert(list.end(), newItems.begin(), newItems.end()); +} + +/** + * Get the index in the list of the specified value. S negative index is returned + * if the value is not found. + * @param list the list + * @param value the value + * @return the index of the value in the list + */ +template +inline int uIndexOf(const std::vector & list, const V & value) +{ + int index=-1; + int i=0; + for(typename std::vector::const_iterator iter = list.begin(); iter!=list.end(); ++iter) + { + if(*iter == value) + { + index = i; + break; + } + ++i; + } + return index; +} + +/** + * Split a string into multiple string around the specified separator. + * Example: + * @code + * std::list v = split("Hello the world!", ' '); + * @endcode + * The list v will contain {"Hello", "the", "world!"} + * @param str the string + * @param separator the separator character + * @return the list of strings + */ +inline std::list uSplit(const std::string & str, char separator = ' ') +{ + std::list v; + std::string buf; + for(unsigned int i=0; i= '0' && c <= '9') + */ +inline bool uIsDigit(const char c) +{ + return c >= '0' && c <= '9'; +} + +/** + * Split a string into number and character strings. + * Example: + * @code + * std::list v = uSplit("Hello 03 my 65 world!"); + * @endcode + * The list v will contain {"Hello ", "03", " my ", "65", " world!"} + * @param str the string + * @return the list of strings + */ +inline std::list uSplitNumChar(const std::string & str) +{ + std::list list; + std::string buf; + bool num = false; + for(unsigned int i=0; ib + */ +inline int uStrNumCmp(const std::string & a, const std::string & b) +{ + std::vector listA; + std::vector listB; + + listA = uListToVector(uSplitNumChar(a)); + listB = uListToVector(uSplitNumChar(b)); + + unsigned int i; + int result = 0; + for(i=0; i listA[i].size()) + { + result = -1; + } + else + { + result = listA[i].compare(listB[i]); + } + } + else if(uIsDigit(listA[i].at(0))) + { + result = -1; + } + else if(uIsDigit(listB[i].at(0))) + { + result = 1; + } + else + { + result = listA[i].compare(listB[i]); + } + + if(result != 0) + { + break; + } + } + + return result; +} + +#endif /* USTL_H */