commit e78b7ca029bb44dee04a356216a67f3713983f48 Author: matlabbe Date: Tue Oct 25 15:48:19 2011 +0000 reverted eclipse project name to find_object git-svn-id: http://find-object.googlecode.com/svn/trunk/find_object@11 620bd6b2-0a58-f614-fd9a-1bd335dccda9 diff --git a/.cproject b/.cproject new file mode 100644 index 00000000..ae283df8 --- /dev/null +++ b/.cproject @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cmake + -E chdir build/ cmake -G "MinGW Makefiles" -D CMAKE_BUILD_TYPE=Debug ../ + + true + false + true + + + cmake + -E chdir build/ cmake -G "MinGW Makefiles" -D CMAKE_BUILD_TYPE=Release ../ + + true + false + true + + + cmake + -E chdir build/ cmake -G "Unix Makefiles" -D CMAKE_BUILD_TYPE=Debug ../ + + true + false + true + + + cmake + -E chdir build/ cmake -G "Unix Makefiles" -D CMAKE_BUILD_TYPE=Release ../ + + true + false + true + + + + + + + diff --git a/.project b/.project new file mode 100644 index 00000000..8c1ffa4b --- /dev/null +++ b/.project @@ -0,0 +1,79 @@ + + + find_object + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.autoBuildTarget + all + + + org.eclipse.cdt.make.core.buildArguments + -C ${ProjDirPath}/build VERBOSE=true + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.cleanBuildTarget + clean + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.fullBuildTarget + all + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + false + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..ca13749b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,17 @@ +# Top-Level CmakeLists.txt +cmake_minimum_required(VERSION 2.8.2) +PROJECT( FindObject ) + +ADD_DEFINITIONS(-DPROJECT_NAME="${PROJECT_NAME}") + +####### OUTPUT DIR ####### +SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) +SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib) + +####### DEPENDENCIES ####### +FIND_PACKAGE(OpenCV REQUIRED) # tested on 2.3.1 +FIND_PACKAGE(Qt4 COMPONENTS QtCore QtGui) # tested on Qt4.7 + +####### SOURCES (Projects) ####### +ADD_SUBDIRECTORY( src ) diff --git a/README b/README new file mode 100644 index 00000000..8a321199 --- /dev/null +++ b/README @@ -0,0 +1,13 @@ + +Requirements : +-Cmake (tested on 2.8.2) +-Qt4 (tested on 4.7) +-OpenCV (tested on 2.3.1) + +Build from source: + $ cd find_object/build + $ cmake .. + $ make + $ cd ../bin + $ ./find_object + (enjoy!) \ No newline at end of file diff --git a/doc/Add_object.png b/doc/Add_object.png new file mode 100644 index 00000000..3c6d0a56 Binary files /dev/null and b/doc/Add_object.png differ diff --git a/doc/Find_object.png b/doc/Find_object.png new file mode 100644 index 00000000..59d1ba5e Binary files /dev/null and b/doc/Find_object.png differ diff --git a/doc/Parameters.png b/doc/Parameters.png new file mode 100644 index 00000000..4efd14dc Binary files /dev/null and b/doc/Parameters.png differ diff --git a/src/AddObjectDialog.cpp b/src/AddObjectDialog.cpp new file mode 100644 index 00000000..a684bb2c --- /dev/null +++ b/src/AddObjectDialog.cpp @@ -0,0 +1,276 @@ + +#include "AddObjectDialog.h" +#include "ui_addObjectDialog.h" +#include "Object.h" +#include "KeypointItem.h" +#include "Camera.h" +#include "qtipl.h" + +#include + +#include +#include +#include + +#include +#include + +AddObjectDialog::AddObjectDialog(QList * objects, QWidget * parent, Qt::WindowFlags f) : + QDialog(parent, f), + camera_(0), + objects_(objects), + cvImage_(0) +{ + ui_ = new Ui_addObjectDialog(); + ui_->setupUi(this); + + camera_ = Settings::createCamera(); + + connect(&cameraTimer_, SIGNAL(timeout()), this, SLOT(update())); + + connect(ui_->pushButton_cancel, SIGNAL(clicked()), this, SLOT(cancel())); + connect(ui_->pushButton_back, SIGNAL(clicked()), this, SLOT(back())); + connect(ui_->pushButton_next, SIGNAL(clicked()), this, SLOT(next())); + connect(ui_->pushButton_takePicture, SIGNAL(clicked()), this, SLOT(takePicture())); + + connect(ui_->cameraView->scene(), SIGNAL(selectionChanged()), this, SLOT(updateNextButton())); + + this->setState(kTakePicture); +} + +AddObjectDialog::~AddObjectDialog() +{ + if(cvImage_) + { + cvReleaseImage(&cvImage_); + } + if(camera_) + { + delete camera_; + } + delete ui_; +} + +void AddObjectDialog::closeEvent(QCloseEvent* event) +{ + QDialog::closeEvent(event); +} + +void AddObjectDialog::next() +{ + setState(state_+1); +} +void AddObjectDialog::back() +{ + setState(state_-1); +} +void AddObjectDialog::cancel() +{ + this->reject(); +} +void AddObjectDialog::takePicture() +{ + next(); +} + +void AddObjectDialog::updateNextButton() +{ + if(state_ == kSelectFeatures) + { + if(ui_->cameraView->scene()->selectedItems().size() > 0) + { + ui_->pushButton_next->setEnabled(true); + } + else + { + ui_->pushButton_next->setEnabled(false); + } + } +} + +void AddObjectDialog::setState(int state) +{ + state_ = state; + if(state == kTakePicture) + { + ui_->pushButton_cancel->setEnabled(true); + ui_->pushButton_back->setEnabled(false); + ui_->pushButton_next->setEnabled(false); + ui_->pushButton_takePicture->setEnabled(true); + ui_->label_instruction->setText(tr("Place the object in front of the camera and click \"Take picture\".")); + ui_->pushButton_next->setText(tr("Next")); + ui_->cameraView->setVisible(true); + ui_->objectView->setVisible(false); + ui_->cameraView->setGraphicsViewMode(false); + if(!camera_->init()) + { + QMessageBox::critical(this, tr("Camera error"), tr("Camera initialization failed! (with device %1)").arg(Settings::getCamera_deviceId().toInt())); + ui_->pushButton_takePicture->setEnabled(false); + } + else + { + cameraTimer_.start(1000/Settings::getCamera_imageRate().toInt()); + } + } + else if(state == kSelectFeatures) + { + cameraTimer_.stop(); + camera_->close(); + + ui_->pushButton_cancel->setEnabled(true); + ui_->pushButton_back->setEnabled(true); + ui_->pushButton_next->setEnabled(false); + ui_->pushButton_takePicture->setEnabled(false); + ui_->label_instruction->setText(tr("Select features representing the object.")); + ui_->pushButton_next->setText(tr("Next")); + ui_->cameraView->setVisible(true); + ui_->objectView->setVisible(false); + ui_->cameraView->setGraphicsViewMode(true); + } + else if(state == kVerifySelection) + { + cameraTimer_.stop(); + camera_->close(); + + ui_->pushButton_cancel->setEnabled(true); + ui_->pushButton_back->setEnabled(true); + ui_->pushButton_takePicture->setEnabled(false); + ui_->pushButton_next->setText(tr("End")); + ui_->cameraView->setVisible(true); + ui_->objectView->setVisible(true); + ui_->cameraView->setGraphicsViewMode(true); + + std::vector selectedKeypoints = ui_->cameraView->selectedKeypoints(); + + // Select keypoints + if(selectedKeypoints.size() && cvImage_) + { + CvRect roi = computeROI(selectedKeypoints); + cvSetImageROI(cvImage_, roi); + if(roi.x != 0 || roi.y != 0) + { + for(unsigned int i=0; iobjectView->setData(selectedKeypoints, cv::Mat(), cvImage_); + cvResetImageROI(cvImage_); + ui_->pushButton_next->setEnabled(true); + } + else + { + printf("Please select items\n"); + ui_->pushButton_next->setEnabled(false); + } + ui_->label_instruction->setText(tr("Selection : %1 features").arg(selectedKeypoints.size())); + } + else if(state == kClosing) + { + std::vector selectedKeypoints = ui_->cameraView->selectedKeypoints(); + if(selectedKeypoints.size()) + { + // Extract descriptors + cv::Mat descriptors; + cv::DescriptorExtractor * extractor = Settings::createDescriptorsExtractor(); + extractor->compute(cvImage_, selectedKeypoints, descriptors); + delete extractor; + if(selectedKeypoints.size() != descriptors.rows) + { + printf("ERROR : keypoints=%lu != descriptors=%d\n", selectedKeypoints.size(), descriptors.rows); + } + + CvRect roi = computeROI(selectedKeypoints); + cvSetImageROI(cvImage_, roi); + if(roi.x != 0 || roi.y != 0) + { + for(unsigned int i=0; iappend(new Object(0, selectedKeypoints, descriptors, cvImage_, Settings::currentDetectorType(), Settings::currentDescriptorType())); + cvResetImageROI(cvImage_); + + + + this->accept(); + } + } +} + +void AddObjectDialog::update() +{ + if(cvImage_) + { + cvReleaseImage(&cvImage_); + cvImage_ = 0; + } + cvImage_ = camera_->takeImage(); + if(cvImage_) + { + // convert to grayscale + if(cvImage_->nChannels != 1 || cvImage_->depth != IPL_DEPTH_8U) + { + IplImage * imageGrayScale = cvCreateImage(cvSize(cvImage_->width, cvImage_->height), IPL_DEPTH_8U, 1); + cvCvtColor(cvImage_, imageGrayScale, CV_BGR2GRAY); + cvReleaseImage(&cvImage_); + cvImage_ = imageGrayScale; + } + + // Extract keypoints + cv::FeatureDetector * detector = Settings::createFeaturesDetector(); + cv::vector keypoints; + detector->detect(cvImage_, keypoints); + delete detector; + + ui_->cameraView->setData(keypoints, cv::Mat(), cvImage_); + ui_->cameraView->update(); + } +} + +CvRect AddObjectDialog::computeROI(const std::vector & kpts) +{ + CvRect roi; + int x1,x2,h1,h2; + for(unsigned int i=0; i int(kpts.at(i).pt.x - radius)) + { + x1 = int(kpts.at(i).pt.x - radius); + } + else if(x2 < int(kpts.at(i).pt.x + radius)) + { + x2 = int(kpts.at(i).pt.x + radius); + } + if(h1 > int(kpts.at(i).pt.y - radius)) + { + h1 = int(kpts.at(i).pt.y - radius); + } + else if(h2 < int(kpts.at(i).pt.y + radius)) + { + h2 = int(kpts.at(i).pt.y + radius); + } + } + roi.x = x1; + roi.y = h1; + roi.width = x2-x1; + roi.height = h2-h1; + printf("ptx=%d, pty=%d\n", (int)kpts.at(i).pt.x, (int)kpts.at(i).pt.y); + printf("x=%d, y=%d, w=%d, h=%d\n", roi.x, roi.y, roi.width, roi.height); + } + + return roi; +} diff --git a/src/AddObjectDialog.h b/src/AddObjectDialog.h new file mode 100644 index 00000000..097aa21a --- /dev/null +++ b/src/AddObjectDialog.h @@ -0,0 +1,47 @@ +#ifndef ADDOBJECTDIALOG_H_ +#define ADDOBJECTDIALOG_H_ + +#include +#include +#include +#include + +class Ui_addObjectDialog; +class Object; +class Camera; +class KeypointItem; + +class AddObjectDialog : public QDialog { + + Q_OBJECT + +public: + AddObjectDialog(QList * objects, QWidget * parent = 0, Qt::WindowFlags f = 0); + virtual ~AddObjectDialog(); + +private slots: + void update(); + void next(); + void back(); + void cancel(); + void takePicture(); + void updateNextButton(); + +protected: + virtual void closeEvent(QCloseEvent* event); + +private: + void setState(int state); + CvRect computeROI(const std::vector & kpts); +private: + Ui_addObjectDialog * ui_; + Camera * camera_; + QTimer cameraTimer_; + QList * objects_; + IplImage * cvImage_; + + enum State{kTakePicture, kSelectFeatures, kVerifySelection, kClosing}; + int state_; +}; + +#endif /* ADDOBJECTDIALOG_H_ */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..1f12054c --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,69 @@ + + +### Qt Gui stuff ### +SET(headers_ui + ./MainWindow.h + ./AddObjectDialog.h + ./Object.h + ./Camera.h + ./ParametersToolBox.h +) + +SET(uis + ./ui/mainWindow.ui + ./ui/addObjectDialog.ui +) + +#SET(qrc +# ./GuiLib.qrc +#) + +# generate rules for building source files from the resources +#QT4_ADD_RESOURCES(srcs_qrc ${qrc}) + +#Generate .h files from the .ui files +QT4_WRAP_UI(moc_uis ${uis}) + +#This will generate moc_* for Qt +QT4_WRAP_CPP(moc_srcs ${headers_ui}) +### Qt Gui stuff end### + + + + +SET(SRC_FILES + ./MainWindow.cpp + ./AddObjectDialog.cpp + ./KeypointItem.cpp + ./qtipl.cpp + ./main.cpp + ./Camera.cpp + ./ParametersToolBox.cpp + ./Settings.cpp + ./Object.cpp + ${moc_srcs} + ${moc_uis} + #${srcs_qrc} +) + +SET(INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR} + ${OpenCV_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} # for qt ui generated in binary dir +) + +INCLUDE(${QT_USE_FILE}) + +SET(LIBRARIES + ${QT_LIBRARIES} + ${OpenCV_LIBS} +) + +#include files +INCLUDE_DIRECTORIES(${INCLUDE_DIRS}) + +# create an executable file +ADD_EXECUTABLE(find_object ${SRC_FILES}) +# Linking with Qt libraries +TARGET_LINK_LIBRARIES(find_object ${LIBRARIES}) + diff --git a/src/Camera.cpp b/src/Camera.cpp new file mode 100644 index 00000000..167654ed --- /dev/null +++ b/src/Camera.cpp @@ -0,0 +1,95 @@ +/* + * Camera.cpp + * + * Created on: 2011-10-21 + * Author: matlab + */ + +#include "Camera.h" +#include +#include + +Camera::Camera(int deviceId, + int imageWidth, + int imageHeight, + QObject * parent) : + QObject(parent), + capture_(0), + deviceId_(deviceId), + imageWidth_(imageWidth), + imageHeight_(imageHeight) +{ +} + +Camera::~Camera() +{ + this->close(); +} + +bool Camera::init() +{ + if(!capture_) + { + capture_ = cvCaptureFromCAM(deviceId_); + if(capture_) + { + cvSetCaptureProperty(capture_, CV_CAP_PROP_FRAME_WIDTH, double(imageWidth_)); + cvSetCaptureProperty(capture_, CV_CAP_PROP_FRAME_HEIGHT, double(imageHeight_)); + } + } + if(!capture_) + { + printf("Failed to create a capture object!\n"); + return false; + } + return true; +} + +void Camera::close() +{ + if(capture_) + { + cvReleaseCapture(&capture_); + capture_ = 0; + } +} + +IplImage * Camera::takeImage() +{ + IplImage * img = 0; + if(capture_) + { + if(cvGrabFrame(capture_)) // capture a frame + { + img = cvRetrieveFrame(capture_); // retrieve the captured frame + } + else + { + printf("CameraVideo: Could not grab a frame, the end of the feed may be reached...\n"); + } + } + + //resize + if(img && + imageWidth_ && + imageHeight_ && + imageWidth_ != (unsigned int)img->width && + imageHeight_ != (unsigned int)img->height) + { + // declare a destination IplImage object with correct size, depth and channels + IplImage * resampledImg = cvCreateImage( cvSize(imageWidth_, imageHeight_), + img->depth, + img->nChannels ); + + //use cvResize to resize source to a destination image (linear interpolation) + cvResize(img, resampledImg); + img = resampledImg; + } + else if(img) + { + img = cvCloneImage(img); + } + + return img; +} + diff --git a/src/Camera.h b/src/Camera.h new file mode 100644 index 00000000..c884f32c --- /dev/null +++ b/src/Camera.h @@ -0,0 +1,47 @@ +/* + * Camera.h + * + * Created on: 2011-10-21 + * Author: matlab + */ + +#ifndef CAMERA_H_ +#define CAMERA_H_ + +#include +#include +#include "Settings.h" + +class Camera : public QObject { + Q_OBJECT +public: + Camera(int deviceId = Settings::defaultCamera_deviceId(), + int width = Settings::defaultCamera_imageWidth(), + int height = Settings::defaultCamera_imageHeight(), + QObject * parent = 0); + virtual ~Camera(); + + void setDeviceId(int deviceId) {deviceId_=deviceId;} + void setImageWidth(int imageWidth) {imageWidth_=imageWidth;} + void setImageHeight(int imageHeight) {imageHeight_=imageHeight;} + + int getDeviceId() const {return deviceId_;} + int getImageWidth() const {return imageWidth_;} + int getImageHeight() const {return imageHeight_;} + +signals: + void ready(); + +public: + bool init(); + void close(); + IplImage * takeImage(); + +private: + CvCapture * capture_; + int deviceId_; + int imageWidth_; + int imageHeight_; +}; + +#endif /* CAMERA_H_ */ diff --git a/src/KeypointItem.cpp b/src/KeypointItem.cpp new file mode 100644 index 00000000..bdc9443c --- /dev/null +++ b/src/KeypointItem.cpp @@ -0,0 +1,109 @@ + + +#include "KeypointItem.h" + +#include +#include +#include + +KeypointItem::KeypointItem(int id, qreal x, qreal y, int r, const QString & info, const QColor & color, QGraphicsItem * parent) : + QGraphicsEllipseItem(x, y, r, r, parent), + _info(info), + _placeHolder(0), + _id(id) +{ + this->setPen(QPen(color)); + this->setBrush(QBrush(color)); + this->setAcceptsHoverEvents(true); + this->setFlag(QGraphicsItem::ItemIsFocusable, true); + this->setFlag(QGraphicsItem::ItemIsSelectable, true); + _width = pen().width(); +} + +KeypointItem::~KeypointItem() +{ + /*if(_placeHolder) + { + delete _placeHolder; + }*/ +} + +void KeypointItem::setColor(const QColor & color) +{ + this->setPen(QPen(color)); + this->setBrush(QBrush(color)); + if(_placeHolder) + { + QList items = _placeHolder->children(); + if(items.size()) + { + ((QGraphicsTextItem *)items.front())->setDefaultTextColor(this->pen().color().rgb()); + } + } +} + +void KeypointItem::showDescription() +{ + if(!_placeHolder) + { + _placeHolder = new QGraphicsRectItem(); + _placeHolder->setVisible(false); + this->scene()->addItem(_placeHolder); + _placeHolder->setBrush(QBrush(QColor ( 0, 0, 0, 170 ))); // Black transparent background + QGraphicsTextItem * text = new QGraphicsTextItem(_placeHolder); + text->setDefaultTextColor(this->pen().color().rgb()); + text->setPlainText(_info); + _placeHolder->setRect(text->boundingRect()); + } + + + QPen pen = this->pen(); + this->setPen(QPen(pen.color(), _width+2)); + _placeHolder->setZValue(this->zValue()+1); + _placeHolder->setPos(this->mapToScene(0,0)); + _placeHolder->setVisible(true); +} + +void KeypointItem::hideDescription() +{ + if(_placeHolder) + { + _placeHolder->setVisible(false); + } + this->setPen(QPen(pen().color(), _width)); +} + +void KeypointItem::hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) +{ + QGraphicsScene * scene = this->scene(); + if(scene && scene->focusItem() == 0) + { + this->showDescription(); + } + else + { + this->setPen(QPen(pen().color(), _width+2)); + } + QGraphicsEllipseItem::hoverEnterEvent(event); +} + +void KeypointItem::hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ) +{ + if(!this->hasFocus()) + { + this->hideDescription(); + } + QGraphicsEllipseItem::hoverEnterEvent(event); +} + +void KeypointItem::focusInEvent ( QFocusEvent * event ) +{ + this->showDescription(); + QGraphicsEllipseItem::focusInEvent(event); +} + +void KeypointItem::focusOutEvent ( QFocusEvent * event ) +{ + this->hideDescription(); + QGraphicsEllipseItem::focusOutEvent(event); +} diff --git a/src/KeypointItem.h b/src/KeypointItem.h new file mode 100644 index 00000000..b3aae07d --- /dev/null +++ b/src/KeypointItem.h @@ -0,0 +1,37 @@ + +#ifndef KEYPOINTITEM_H_ +#define KEYPOINTITEM_H_ + +#include +#include +#include +#include + +class KeypointItem : public QGraphicsEllipseItem +{ +public: + KeypointItem(int id, qreal x, qreal y, int r, const QString & info, const QColor & color = Qt::green, QGraphicsItem * parent = 0); + virtual ~KeypointItem(); + + void setColor(const QColor & color); + int id() const {return _id;} + +protected: + virtual void hoverEnterEvent ( QGraphicsSceneHoverEvent * event ); + virtual void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ); + virtual void focusInEvent ( QFocusEvent * event ); + virtual void focusOutEvent ( QFocusEvent * event ); + +private: + void showDescription(); + void hideDescription(); + +private: + QString _info; + QGraphicsRectItem * _placeHolder; + int _width; + int _id; +}; + + +#endif /* KEYPOINTITEM_H_ */ diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp new file mode 100644 index 00000000..77064999 --- /dev/null +++ b/src/MainWindow.cpp @@ -0,0 +1,476 @@ + +#include "MainWindow.h" +#include "AddObjectDialog.h" +#include "ui_mainWindow.h" +#include "qtipl.h" +#include "KeypointItem.h" +#include "Object.h" +#include "Camera.h" +#include "Settings.h" +#include "ParametersToolBox.h" + +#include +#include + +#include "opencv2/calib3d/calib3d.hpp" + +#include +#include + +#include +#include +#include + +MainWindow::MainWindow(QWidget * parent) : + QMainWindow(parent), + camera_(0) +{ + ui_ = new Ui_mainWindow(); + ui_->setupUi(this); + + connect(&cameraTimer_, SIGNAL(timeout()), this, SLOT(update())); + + QByteArray geometry; + Settings::loadSettings(Settings::iniDefaultFileName, &geometry); + this->restoreGeometry(geometry); + + ui_->toolBox->setupUi(); + ui_->dockWidget_parameters->hide(); + ui_->menuView->addAction(ui_->dockWidget_parameters->toggleViewAction()); + ui_->menuView->addAction(ui_->dockWidget_objects->toggleViewAction()); + + ui_->imageView_source->setGraphicsViewMode(false); + + //reset button + connect(ui_->pushButton_restoreDefaults, SIGNAL(clicked()), ui_->toolBox, SLOT(resetCurrentPage())); + + ui_->actionStop_camera->setEnabled(false); + ui_->actionSave_objects->setEnabled(false); + + // Actions + connect(ui_->actionAdd_object, SIGNAL(triggered()), this, SLOT(addObject())); + connect(ui_->actionStart_camera, SIGNAL(triggered()), this, SLOT(startCamera())); + connect(ui_->actionStop_camera, SIGNAL(triggered()), this, SLOT(stopCamera())); + connect(ui_->actionExit, SIGNAL(triggered()), this, SLOT(close())); + connect(ui_->actionSave_objects, SIGNAL(triggered()), this, SLOT(saveObjects())); + connect(ui_->actionLoad_objects, SIGNAL(triggered()), this, SLOT(loadObjects())); +} + +MainWindow::~MainWindow() +{ + this->stopCamera(); + if(camera_) + { + delete camera_; + camera_ = 0; + } + dataTree_ = cv::Mat(); + qDeleteAll(objects_.begin(), objects_.end()); + objects_.clear(); + delete ui_; +} + +void MainWindow::closeEvent(QCloseEvent * event) +{ + Settings::saveSettings(Settings::iniDefaultFileName, this->saveGeometry()); + QMainWindow::closeEvent(event); +} + +void MainWindow::loadObjects() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Load objects..."), "", "*.obj"); + if(!fileName.isEmpty()) + { + QFile file(fileName); + file.open(QIODevice::ReadOnly); + QDataStream in(&file); + while(!in.atEnd()) + { + Object * obj = new Object(); + obj->load(in); + bool alreadyLoaded = false; + for(int i=0; iid() == obj->id()) + { + alreadyLoaded = true; + break; + } + } + if(!alreadyLoaded) + { + objects_.append(obj); + showObject(obj); + } + else + { + delete obj; + } + } + file.close(); + } +} +void MainWindow::saveObjects() +{ + QString fileName = QFileDialog::getSaveFileName(this, tr("Save objects..."), Settings::currentDetectorType()+Settings::currentDescriptorType()+QString("%1.obj").arg(objects_.size()), "*.obj"); + if(!fileName.isEmpty()) + { + if(!fileName.endsWith(".obj")) + { + fileName.append(".obj");//default + } + + QFile file(fileName); + file.open(QIODevice::WriteOnly); + QDataStream out(&file); + for(int i=0; isave(out); + } + file.close(); + } +} + +void MainWindow::removeObject(Object * object) +{ + if(object) + { + objects_.removeOne(object); + object->deleteLater(); + this->updateData(); + } +} + +void MainWindow::addObject() +{ + this->stopCamera(); + AddObjectDialog dialog(&objects_, this); + if(dialog.exec() == QDialog::Accepted) + { + showObject(objects_.last()); + } +} + +void MainWindow::showObject(Object * obj) +{ + if(obj) + { + obj->setGraphicsViewMode(false); + QList objs = ui_->objects_area->findChildren(); + QVBoxLayout * vLayout = new QVBoxLayout(); + int id = Settings::getGeneral_nextObjID().toInt(); + if(obj->id() == 0) + { + obj->setId(id++); + Settings::setGeneral_nextObjID(id); + } + else if(obj->id() > id) + { + id = obj->id()+1; + Settings::setGeneral_nextObjID(id); + } + + QLabel * title = new QLabel(QString("%1 (%2)").arg(obj->id()).arg(QString::number(obj->keypoints().size())), this); + QLabel * detectedLabel = new QLabel(this); + QLabel * detectorDescriptorType = new QLabel(QString("%1/%2").arg(obj->detectorType()).arg(obj->descriptorType()), this); + detectedLabel->setObjectName(QString("%1detection").arg(obj->id())); + QHBoxLayout * hLayout = new QHBoxLayout(); + hLayout->addWidget(title); + hLayout->addWidget(detectorDescriptorType); + hLayout->addWidget(detectedLabel); + hLayout->addStretch(1); + vLayout->addLayout(hLayout); + vLayout->addWidget(obj); + objects_.last()->setDeletable(true); + connect(obj, SIGNAL(removalTriggered(Object*)), this, SLOT(removeObject(Object*))); + connect(obj, SIGNAL(destroyed(QObject *)), title, SLOT(deleteLater())); + connect(obj, SIGNAL(destroyed(QObject *)), detectedLabel, SLOT(deleteLater())); + connect(obj, SIGNAL(destroyed(QObject *)), detectorDescriptorType, SLOT(deleteLater())); + connect(obj, SIGNAL(destroyed(QObject *)), vLayout, SLOT(deleteLater())); + ui_->verticalLayout_objects->insertLayout(ui_->verticalLayout_objects->count()-1, vLayout); + + this->updateData(); + } +} + +void MainWindow::updateData() +{ + if(objects_.size()) + { + ui_->actionSave_objects->setEnabled(true); + } + else + { + ui_->actionSave_objects->setEnabled(false); + } + + dataTree_ = cv::Mat(); + dataRange_.clear(); + int count = 0; + int dim = -1; + int type = -1; + // Get the total size and verify descriptors + for(int i=0; i= 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).")); + return; + } + dim = objects_.at(i)->descriptors().cols; + if(type >= 0 && objects_.at(i)->descriptors().type() != type) + { + 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.")); + return; + } + type = objects_.at(i)->descriptors().type(); + count += objects_.at(i)->descriptors().rows; + } + + // Copy data + if(count) + { + cv::Mat data(count, dim, type); + printf("Total descriptors=%d, dim=%d, type=%d\n",count, dim, type); + int row = 0; + for(int i=0; idescriptors().rows)); + objects_.at(i)->descriptors().copyTo(dest); + row += objects_.at(i)->descriptors().rows; + dataRange_.append(row); + } + data.convertTo(dataTree_, CV_32F); + } +} + +void MainWindow::startCamera() +{ + if(camera_) + { + camera_->close(); + delete camera_; + } + camera_ = Settings::createCamera(); + connect(camera_, SIGNAL(ready()), this, SLOT(update())); + if(camera_->init()) + { + cameraTimer_.start(1000/Settings::getCamera_imageRate().toInt()); + ui_->actionStop_camera->setEnabled(true); + ui_->actionStart_camera->setEnabled(false); + } + else + { + QMessageBox::critical(this, tr("Camera error"), tr("Camera initialization failed! (with device %1)").arg(Settings::getCamera_deviceId().toInt())); + } +} + +void MainWindow::stopCamera() +{ + if(camera_) + { + cameraTimer_.stop(); + camera_->close(); + delete camera_; + camera_ = 0; + } + ui_->actionStop_camera->setEnabled(false); + ui_->actionStart_camera->setEnabled(true); +} + +void MainWindow::update() +{ + // reset objects color + for(int i=0; iresetKptsColor(); + } + + if(camera_) + { + IplImage * cvImage = camera_->takeImage(); + if(cvImage) + { + QTime time; + + //Convert to grayscale + IplImage * imageGrayScale = 0; + if(cvImage->nChannels != 1 || cvImage->depth != IPL_DEPTH_8U) + { + imageGrayScale = cvCreateImage(cvSize(cvImage->width,cvImage->height), IPL_DEPTH_8U, 1); + cvCvtColor(cvImage, imageGrayScale, CV_BGR2GRAY); + } + cv::Mat img; + if(imageGrayScale) + { + img = cv::Mat(imageGrayScale); + } + else + { + img = cv::Mat(cvImage); + } + + // EXTRACT KEYPOINTS + time.start(); + cv::FeatureDetector * detector = Settings::createFeaturesDetector(); + std::vector keypoints; + detector->detect(img, keypoints); + delete detector; + ui_->label_timeDetection->setText(QString::number(time.elapsed())); + + // EXTRACT DESCRIPTORS + time.start(); + cv::Mat descriptors; + cv::DescriptorExtractor * extractor = Settings::createDescriptorsExtractor(); + extractor->compute(img, keypoints, descriptors); + delete extractor; + if(keypoints.size() != descriptors.rows) + { + printf("ERROR : kpt=%lu != descriptors=%d\n", keypoints.size(), descriptors.rows); + } + if(imageGrayScale) + { + cvReleaseImage(&imageGrayScale); + } + ui_->label_timeExtraction->setText(QString::number(time.elapsed())); + + // COMPARE + int alpha = 20*255/100; + if(!dataTree_.empty()) + { + // CREATE INDEX + time.start(); + cv::Mat environment(descriptors.rows, descriptors.cols, CV_32F); + descriptors.convertTo(environment, CV_32F); + cv::flann::Index treeFlannIndex(environment, cv::flann::KDTreeIndexParams()); + ui_->label_timeIndexing->setText(QString::number(time.elapsed())); + + // DO NEAREST NEIGHBOR + time.start(); + int k = 2; + int emax = 64; + cv::Mat results(dataTree_.rows, k, CV_32SC1); // results index + cv::Mat dists(dataTree_.rows, k, CV_32FC1); // Distance results are CV_32FC1 + treeFlannIndex.knnSearch(dataTree_, results, dists, k, cv::flann::SearchParams(emax) ); // maximum number of leafs checked + ui_->label_timeMatching->setText(QString::number(time.elapsed())); + + + // PROCESS RESULTS + time.start(); + ui_->imageView_source->setData(keypoints, cv::Mat(), cvImage); + int j=0; + std::vector mpts_1, mpts_2; + std::vector indexes_1, indexes_2; + std::vector outlier_mask; + for(unsigned int i=0; i(i,0) <= Settings::getNN_nndrRatio().toFloat() * dists.at(i,1)) + { + if(j>0) + { + mpts_1.push_back(objects_.at(j)->keypoints().at(i-dataRange_.at(j-1)).pt); + indexes_1.push_back(i-dataRange_.at(j-1)); + } + else + { + mpts_1.push_back(objects_.at(j)->keypoints().at(i).pt); + indexes_1.push_back(i); + } + mpts_2.push_back(ui_->imageView_source->keypoints().at(results.at(i,0)).pt); + indexes_2.push_back(results.at(i,0)); + } + + if(i+1 >= dataRange_.at(j)) + { + QLabel * label = ui_->dockWidget_objects->findChild(QString("%1detection").arg(objects_.at(j)->id())); + if(mpts_1.size() >= Settings::getHomography_minimumInliers().toInt()) + { + cv::Mat H = findHomography(mpts_1, + mpts_2, + cv::RANSAC, + Settings::getHomography_ransacReprojThr().toDouble(), + outlier_mask); + int inliers=0, outliers=0; + QColor color((Qt::GlobalColor)(j % 12 + 7 )); + color.setAlpha(alpha); + for(int k=0; k= Settings::getHomography_minimumInliers().toInt()) + { + for(int k=0; ksetKptColor(indexes_1.at(k), color); + ui_->imageView_source->setKptColor(indexes_2.at(k), color); + } + else + { + objects_.at(j)->setKptColor(indexes_1.at(k), QColor(0,0,0,alpha)); + } + } + + label->setText(QString("%1 in %2 out").arg(inliers).arg(outliers)); + QTransform hTransform( + H.at(0,0), H.at(1,0), H.at(2,0), + H.at(0,1), H.at(1,1), H.at(2,1), + H.at(0,2), H.at(1,2), H.at(2,2)); + QPen rectPen(color); + rectPen.setWidth(4); + QGraphicsRectItem * rectItem = ui_->imageView_source->scene()->addRect(objects_.at(j)->image().rect(), rectPen); + rectItem->setTransform(hTransform); + } + else + { + label->setText(QString("Too low inliers (%1)").arg(inliers)); + } + } + else + { + label->setText(QString("Too low matches (%1)").arg(mpts_1.size())); + } + mpts_1.clear(); + mpts_2.clear(); + indexes_1.clear(); + indexes_2.clear(); + outlier_mask.clear(); + ++j; + } + } + } + else + { + ui_->imageView_source->setData(keypoints, cv::Mat(), cvImage); + } + + //Update object pictures + for(int i=0; iupdate(); + } + + ui_->label_nfeatures->setText(QString::number(keypoints.size())); + ui_->imageView_source->update(); + ui_->label_timeGui->setText(QString::number(time.elapsed())); + + cvReleaseImage(&cvImage); + } + } + ui_->label_detectorDescriptorType->setText(QString("%1/%2").arg(Settings::currentDetectorType()).arg(Settings::currentDescriptorType())); + ui_->label_timeRefreshRate->setText(QString("(%1 Hz - %2 Hz)").arg(QString::number(1000/cameraTimer_.interval())).arg(QString::number(int(1000.0f/(float)(updateRate_.elapsed()))))); + //printf("GUI refresh rate %f Hz\n", 1000.0f/(float)(updateRate_.elapsed())); + updateRate_.start(); +} diff --git a/src/MainWindow.h b/src/MainWindow.h new file mode 100644 index 00000000..ce8a0add --- /dev/null +++ b/src/MainWindow.h @@ -0,0 +1,56 @@ + + +#ifndef MAINWINDOW_H_ +#define MAINWINDOW_H_ + +#include +#include +#include +#include + +#include +#include +#include + +class Ui_mainWindow; +class Object; +class Camera; +class ParametersToolBox; +class QLabel; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget * parent = 0); + virtual ~MainWindow(); + +protected: + virtual void closeEvent(QCloseEvent * event); + +private slots: + void addObject(); + void startCamera(); + void stopCamera(); + void loadObjects(); + void saveObjects(); + void update(); + void updateData(); + void removeObject(Object * object); + +private: + void showObject(Object * obj); + +private: + Ui_mainWindow * ui_; + Camera * camera_; + QList objects_; + QTimer cameraTimer_; + cv::Mat dataTree_; + QList dataRange_; + QTime updateRate_; + +}; + +#endif /* MainWindow_H_ */ diff --git a/src/Object.cpp b/src/Object.cpp new file mode 100644 index 00000000..7ff154c3 --- /dev/null +++ b/src/Object.cpp @@ -0,0 +1,517 @@ +/* + * Object.cpp + * + * Created on: 2011-10-23 + * Author: matlab + */ + + +/* + * VisualObject.h + * + * Created on: 2011-10-21 + * Author: matlab + */ + +#include "Object.h" +#include "KeypointItem.h" +#include "qtipl.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +Object::Object(QWidget * parent) : + QWidget(parent), + iplImage_(0), + graphicsView_(0), + id_(0), + graphicsViewMode_(true), + detectorType_("NA"), + descriptorType_("NA") +{ + setupUi(); +} +Object::Object(int id, + const std::vector & keypoints, + const cv::Mat & descriptors, + const IplImage * iplImage, + const QString & detectorType, + const QString & descriptorType, + QWidget * parent) : + QWidget(parent), + iplImage_(0), + graphicsView_(0), + id_(id), + graphicsViewMode_(true), + detectorType_(detectorType), + descriptorType_(descriptorType) +{ + setupUi(); + this->setData(keypoints, descriptors, iplImage); +} +Object::~Object() +{ + if(iplImage_) + { + cvReleaseImage(&iplImage_); + } +} + +void Object::setupUi() +{ + graphicsView_ = new QGraphicsView(this); + graphicsView_->setVisible(true); + graphicsView_->setTransformationAnchor(QGraphicsView::AnchorUnderMouse); + graphicsView_->setScene(new QGraphicsScene(graphicsView_)); + + this->setLayout(new QVBoxLayout(graphicsView_)); + this->layout()->addWidget(graphicsView_); + this->layout()->setContentsMargins(0,0,0,0); + + _menu = new QMenu(tr(""), this); + _showImage = _menu->addAction(tr("Show image")); + _showImage->setCheckable(true); + _showImage->setChecked(true); + _showFeatures = _menu->addAction(tr("Show features")); + _showFeatures->setCheckable(true); + _showFeatures->setChecked(true); + _mirrorView = _menu->addAction(tr("Mirror view")); + _mirrorView->setCheckable(true); + _mirrorView->setChecked(false); + _plainView = _menu->addAction(tr("Plain view")); + _plainView->setCheckable(true); + _plainView->setChecked(!graphicsViewMode_); + _menu->addSeparator(); + _saveImage = _menu->addAction(tr("Save picture...")); + _menu->addSeparator(); + _delete = _menu->addAction(tr("Delete")); + _delete->setEnabled(false); + + this->setId(id_); + + graphicsView_->setRubberBandSelectionMode(Qt::ContainsItemShape); + graphicsView_->setDragMode(QGraphicsView::RubberBandDrag); +} + +void Object::setId(int id) +{ + id_=id; + if(id_) + { + _savedFileName = QString("object_%1.png").arg(id_); + } +} + +void Object::setGraphicsViewMode(bool on) +{ + graphicsViewMode_ = on; + graphicsView_->setVisible(on); + //update items' color + if(on) + { + if(keypointItems_.size() == 0) + { + this->setupGraphicsView(); + } + else + { + for(int i=0; isetColor(kptColors_.at(i)); + } + } + } + graphicsView_->fitInView(graphicsView_->sceneRect(), Qt::KeepAspectRatio); + _plainView->setChecked(!on); + this->update(); +} + +// ownership transferred +void Object::setData(const std::vector & keypoints, const cv::Mat & descriptors, const IplImage * image) +{ + keypoints_ = keypoints; + descriptors_ = descriptors; + kptColors_ = QVector(keypoints.size(), defaultColor()); + keypointItems_.clear(); + if(iplImage_) + { + cvReleaseImage(&iplImage_); + iplImage_ = 0; + } + if(image) + { + /* create destination image + Note that cvGetSize will return the width and the height of ROI */ + iplImage_ = cvCreateImage(cvGetSize(image), + image->depth, + image->nChannels); + + /* copy subimage */ + cvCopy(image, iplImage_, NULL); + + image_ = QPixmap::fromImage(Ipl2QImage(iplImage_)); + this->setMinimumSize(image_.size()); + } + if(graphicsViewMode_) + { + this->setupGraphicsView(); + } +} + +void Object::resetKptsColor() +{ + for(int i=0; isetColor(this->defaultColor()); + } + } +} + +void Object::setKptColor(unsigned int index, const QColor & color) +{ + if(index < kptColors_.size()) + { + kptColors_[index] = color; + } + + if(graphicsViewMode_) + { + if(index < keypointItems_.size()) + { + keypointItems_.at(index)->setColor(color); + } + } +} + +bool Object::isImageShown() const +{ + return _showImage->isChecked(); +} + +bool Object::isFeaturesShown() const +{ + return _showFeatures->isChecked(); +} + +bool Object::isMirrorView() const +{ + return _mirrorView->isChecked(); +} + +QGraphicsScene * Object::scene() const +{ + return graphicsView_->scene(); +} + +void Object::setDeletable(bool deletable) +{ + _delete->setEnabled(deletable); +} + +void Object::save(QDataStream & streamPtr) const +{ + streamPtr << id_ << detectorType_ << descriptorType_; + streamPtr << (int)keypoints_.size(); + for(int j=0; j kpts; + cv::Mat descriptors; + + int nKpts; + streamPtr >> id_ >> detectorType_ >> descriptorType_ >> nKpts; + for(int i=0;i> + kpt.angle >> + kpt.class_id >> + kpt.octave >> + kpt.pt.x >> + kpt.pt.y >> + kpt.response >> + kpt.size; + kpts.push_back(kpt); + } + + int rows,cols,type; + qint64 dataSize; + streamPtr >> rows >> cols >> type >> dataSize; + QByteArray data; + streamPtr >> data; + descriptors = cv::Mat(rows, cols, type, data.data()).clone(); + streamPtr >> image_; + this->setData(kpts, descriptors, 0); + this->setMinimumSize(image_.size()); +} + +void Object::paintEvent(QPaintEvent *event) +{ + if(graphicsViewMode_) + { + QWidget::paintEvent(event); + } + else + { + if(!image_.isNull()) + { + //Scale + float w = image_.width(); + float h = image_.height(); + float widthRatio = this->rect().width() / w; + float heightRatio = this->rect().height() / h; + float ratio = 1.0f; + //printf("w=%f, h=%f, wR=%f, hR=%f, sW=%f, sH=%f\n", w, h, widthRatio, heightRatio, sceneRect.width(), sceneRect.height()); + if(widthRatio < heightRatio) + { + ratio = widthRatio; + } + else + { + ratio = heightRatio; + } + + //printf("ratio=%f\n",ratio); + + w *= ratio; + h *= ratio; + + float offsetX = 0.0f; + float offsetY = 0.0f; + if(w < this->rect().width()) + { + offsetX = (this->rect().width() - w)/2.0f; + } + if(h < this->rect().height()) + { + offsetY = (this->rect().height() - h)/2.0f; + } + QPainter painter(this); + + + if(_mirrorView->isChecked()) + { + painter.translate(offsetX+w, offsetY); + painter.scale(-ratio, ratio); + } + else + { + painter.translate(offsetX, offsetY); + painter.scale(ratio, ratio); + } + + if(_showImage->isChecked()) + { + painter.drawPixmap(QPoint(0,0), image_); + } + if(_showFeatures->isChecked()) + { + drawKeypoints(&painter); + } + } + } +} + +void Object::resizeEvent(QResizeEvent* event) +{ + if(graphicsViewMode_) + { + graphicsView_->fitInView(graphicsView_->sceneRect(), Qt::KeepAspectRatio); + } + QWidget::resizeEvent(event); +} + +void Object::contextMenuEvent(QContextMenuEvent * event) +{ + QAction * action = _menu->exec(event->globalPos()); + if(action == _saveImage) + { + QString text; + text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), _savedFileName, "*.png *.xpm *.jpg *.pdf"); + if(!text.isEmpty()) + { + if(!text.endsWith(".png") && !text.endsWith(".png") && !text.endsWith(".png") && !text.endsWith(".png")) + { + text.append(".png");//default + } + _savedFileName = text; + getSceneAsPixmap().save(text); + } + } + else if(action == _showFeatures || action == _showImage) + { + if(graphicsViewMode_) + { + this->updateItemsShown(); + } + else + { + this->update(); + } + } + else if(action == _mirrorView) + { + graphicsView_->setTransform(QTransform().scale(this->isMirrorView()?-1.0:1.0, 1.0)); + if(graphicsViewMode_) + { + graphicsView_->fitInView(graphicsView_->sceneRect(), Qt::KeepAspectRatio); + } + else + { + this->update(); + } + } + else if(action == _delete) + { + emit removalTriggered(this); + } + else if(action == _plainView) + { + this->setGraphicsViewMode(!_plainView->isChecked()); + } + QWidget::contextMenuEvent(event); +} + +QPixmap Object::getSceneAsPixmap() +{ + if(graphicsViewMode_) + { + QPixmap img(graphicsView_->sceneRect().width(), graphicsView_->sceneRect().height()); + QPainter p(&img); + graphicsView_->scene()->render(&p, graphicsView_->sceneRect(), graphicsView_->sceneRect()); + return img; + } + else + { + return QPixmap::grabWidget(this); + } +} + +void Object::updateItemsShown() +{ + QList items = graphicsView_->scene()->items(); + for(int i=0; i(items.at(i))) + { + items.at(i)->setVisible(_showFeatures->isChecked()); + } + else if(qgraphicsitem_cast(items.at(i))) + { + items.at(i)->setVisible(_showImage->isChecked()); + } + } +} + +void Object::drawKeypoints(QPainter * painter) +{ + QList items; + KeypointItem * item = 0; + + int i = 0; + for(std::vector::const_iterator iter = keypoints_.begin(); iter != keypoints_.end(); ++iter, ++i ) + { + const cv::KeyPoint & r = *iter; + float radius = 14*1.2/9.*2;//r.size*1.2/9.*2; + if(graphicsViewMode_) + { + QString info = QString( "ID = %1\n" + "Response = %2\n" + "Angle = %3\n" + "X = %4\n" + "Y = %5\n" + "Size = %6").arg(i+1).arg(r.response).arg(r.angle).arg(r.pt.x).arg(r.pt.y).arg(r.size); + // YELLOW = NEW and multiple times + item = new KeypointItem(i+1, r.pt.x-radius, r.pt.y-radius, radius*2, info, kptColors_.at(i)); + item->setVisible(this->isFeaturesShown()); + item->setZValue(1); + graphicsView_->scene()->addItem(item); + keypointItems_.append(item); + } + + if(painter) + { + painter->save(); + painter->setPen(kptColors_.at(i)); + painter->setBrush(kptColors_.at(i)); + painter->drawEllipse(r.pt.x-radius, r.pt.y-radius, radius*2, radius*2); + painter->restore(); + } + } +} + +QColor Object::defaultColor() const +{ + int alpha = 20*255/100; + return QColor(255, 255, 0, alpha); +} + +std::vector Object::selectedKeypoints() const +{ + std::vector selected; + if(graphicsViewMode_) + { + QList items = graphicsView_->scene()->selectedItems(); + for(int i=0; i(items.at(i))) + { + selected.push_back(keypoints_.at(((KeypointItem*)items.at(i))->id()-1)); // ids start at 1 + } + } + } + return selected; +} + +void Object::setupGraphicsView() +{ + graphicsView_->scene()->clear(); + graphicsView_->scene()->setSceneRect(image_.rect()); + QList items; + if(image_.width() > 0 && image_.height() > 0) + { + QRectF sceneRect = graphicsView_->sceneRect(); + + QGraphicsPixmapItem * pixmapItem = graphicsView_->scene()->addPixmap(image_); + pixmapItem->setVisible(this->isImageShown()); + this->drawKeypoints(); + + graphicsView_->fitInView(sceneRect, Qt::KeepAspectRatio); + } +} + diff --git a/src/Object.h b/src/Object.h new file mode 100644 index 00000000..d2cc0707 --- /dev/null +++ b/src/Object.h @@ -0,0 +1,103 @@ +/* + * VisualObject.h + * + * Created on: 2011-10-21 + * Author: matlab + */ + +#ifndef OBJECT_H_ +#define OBJECT_H_ + +#include +#include + +class KeypointItem; +class ImageKptsView; +class QAction; +class QMenu; +class QGraphicsView; +class QGraphicsScene; + +class Object : public QWidget +{ + Q_OBJECT + +public: + Object(QWidget * parent = 0); + Object(int id, + const std::vector & keypoints, + const cv::Mat & descriptors, + const IplImage * image, + const QString & detectorType = "NA", + const QString & descriptorType = "NA", + QWidget * parent = 0); + virtual ~Object(); + + void setId(int id); + void setData(const std::vector & keypoints, + const cv::Mat & descriptors, + const IplImage * image); + void resetKptsColor(); + void setKptColor(unsigned int index, const QColor & color); + void setGraphicsViewMode(bool on); + void setDeletable(bool deletable); + + const std::vector & keypoints() const {return keypoints_;} + const cv::Mat & descriptors() const {return descriptors_;} + const QPixmap & image() const {return image_;} + const IplImage * iplImage() const {return iplImage_;} + int id() const {return id_;} + QColor defaultColor() const; + bool isImageShown() const; + bool isFeaturesShown() const; + bool isMirrorView() const; + QGraphicsScene * scene() const; + std::vector selectedKeypoints() const; + const QString & detectorType() const {return detectorType_;} + const QString & descriptorType() const {return descriptorType_;} + + QPixmap getSceneAsPixmap(); + + void save(QDataStream & streamPtr) const; + void load(QDataStream & streamPtr); + +protected: + virtual void paintEvent(QPaintEvent *event); + virtual void contextMenuEvent(QContextMenuEvent * event); + virtual void resizeEvent(QResizeEvent* event); + +signals: + void removalTriggered(Object *); + +private: + void setupGraphicsView(); + void drawKeypoints(QPainter * painter = 0); + void setupUi(); + void updateItemsShown(); + +private: + std::vector keypoints_; + cv::Mat descriptors_; + QPixmap image_; + IplImage * iplImage_; + QList keypointItems_; + QGraphicsView * graphicsView_; + int id_; + bool graphicsViewMode_; + QVector kptColors_; + QString detectorType_; + QString descriptorType_; + + // menu stuff + QString _savedFileName; + QMenu * _menu; + QAction * _showImage; + QAction * _showFeatures; + QAction * _saveImage; + QAction * _mirrorView; + QAction * _delete; + QAction * _plainView; +}; + + +#endif /* OBJECT_H_ */ diff --git a/src/ParametersToolBox.cpp b/src/ParametersToolBox.cpp new file mode 100644 index 00000000..26eade44 --- /dev/null +++ b/src/ParametersToolBox.cpp @@ -0,0 +1,256 @@ +/* + * ParametersToolbox.cpp + * + * Created on: 2011-10-22 + * Author: matlab + */ + +#include "ParametersToolBox.h" +#include "Settings.h" +#include +#include +#include +#include +#include +#include +#include +#include + +ParametersToolBox::ParametersToolBox(QWidget *parent) : + QToolBox(parent) +{ +} + +ParametersToolBox::~ParametersToolBox() +{ +} + +void ParametersToolBox::resetCurrentPage() +{ + const QObjectList & children = this->widget(this->currentIndex())->children(); + for(int j=0; jobjectName(); + QVariant value = Settings::getDefaultParameters().value(key, QVariant()); + if(value.isValid()) + { + if(qobject_cast(children.at(j))) + { + ((QComboBox*)children.at(j))->setCurrentIndex(value.toString().split(':').first().toInt()); + } + else if(qobject_cast(children.at(j))) + { + ((QSpinBox*)children.at(j))->setValue(value.toInt()); + } + else if(qobject_cast(children.at(j))) + { + ((QDoubleSpinBox*)children.at(j))->setValue(value.toDouble()); + } + else if(qobject_cast(children.at(j))) + { + ((QCheckBox*)children.at(j))->setChecked(value.toBool()); + } + Settings::setParameter(key, value); + } + } +} + +void ParametersToolBox::setupUi() +{ + QWidget * currentItem = 0; + const ParametersMap & parameters = Settings::getParameters(); + for(ParametersMap::const_iterator iter=parameters.constBegin(); + iter!=parameters.constEnd(); + ++iter) + { + QStringList splitted = iter.key().split('/'); + QString group = splitted.first(); + QString name = splitted.last(); + if(currentItem == 0 || currentItem->objectName().compare(group) != 0) + { + currentItem = new QWidget(this); + int index = this->addItem(currentItem, group); + currentItem->setObjectName(group); + QVBoxLayout * layout = new QVBoxLayout(currentItem); + currentItem->setLayout(layout); + layout->addSpacerItem(new QSpacerItem(0,0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + + addParameter(layout, iter.key(), iter.value()); + } + else + { + addParameter((QVBoxLayout*)currentItem->layout(), iter.key(), iter.value()); + } + } +} + +void ParametersToolBox::addParameter(QVBoxLayout * layout, + const QString & key, + const QVariant & value) +{ + QString type = Settings::getParametersType().value(key); + if(type.compare("QString") == 0) + { + addParameter(layout, key, value.toString()); + } + else if(type.compare("int") == 0) + { + addParameter(layout, key, value.toInt()); + } + else if(type.compare("unsigned int") == 0) + { + addParameter(layout, key, value.toInt()); + } + else if(type.compare("double") == 0) + { + addParameter(layout, key, value.toDouble()); + } + else if(type.compare("float") == 0) + { + addParameter(layout, key, value.toDouble()); + } + else if(type.compare("bool") == 0) + { + addParameter(layout, key, value.toBool()); + } +} + +void ParametersToolBox::addParameter(QVBoxLayout * layout, + const QString & key, + const QString & value) +{ + if(value.contains(';')) + { + QComboBox * widget = new QComboBox(this); + widget->setObjectName(key); + QStringList splitted = value.split(':'); + widget->addItems(splitted.last().split(';')); + widget->setCurrentIndex(splitted.first().toInt()); + connect(widget, SIGNAL(currentIndexChanged(int)), this, SLOT(changeParameter(int))); + addParameter(layout, key.split('/').last(), widget); + } + else + { + QLineEdit * widget = new QLineEdit(value, this); + widget->setObjectName(key); + connect(widget, SIGNAL(textChanged(const QString &)), this, SLOT(changeParameter(const QString &))); + addParameter(layout, key.split('/').last(), widget); + } +} + +void ParametersToolBox::addParameter(QVBoxLayout * layout, + const QString & key, + const double & value) +{ + QDoubleSpinBox * widget = new QDoubleSpinBox(this); + double def = Settings::getDefaultParameters().value(key).toDouble(); + if(def<0.001) + { + widget->setDecimals(4); + } + else if(def<0.01) + { + widget->setDecimals(3); + } + + if(def>0.0) + { + widget->setMaximum(def*10.0); + } + else if(def<0.0) + { + widget->setMinimum(def*10.0); + widget->setMaximum(0.0); + } + widget->setValue(value); + widget->setObjectName(key); + connect(widget, SIGNAL(editingFinished()), this, SLOT(changeParameter())); + addParameter(layout, key.split('/').last(), widget); +} + +void ParametersToolBox::addParameter(QVBoxLayout * layout, + const QString & key, + const int & value) +{ + QSpinBox * widget = new QSpinBox(this); + int def = Settings::getDefaultParameters().value(key).toInt(); + + if(def>0) + { + widget->setMaximum(def*10); + } + else if(def<0) + { + widget->setMinimum(def*10); + widget->setMaximum(0); + } + widget->setValue(value); + widget->setObjectName(key); + connect(widget, SIGNAL(editingFinished()), this, SLOT(changeParameter())); + addParameter(layout, key.split('/').last(), widget); +} + +void ParametersToolBox::addParameter(QVBoxLayout * layout, + const QString & key, + const bool & value) +{ + QCheckBox * widget = new QCheckBox(this); + widget->setChecked(value); + widget->setObjectName(key); + connect(widget, SIGNAL(stateChanged(int)), this, SLOT(changeParameter(int))); + addParameter(layout, key.split('/').last(), widget); +} + +void ParametersToolBox::addParameter(QVBoxLayout * layout, const QString & name, QWidget * widget) +{ + QHBoxLayout * hLayout = new QHBoxLayout(); + layout->insertLayout(layout->count()-1, hLayout); + hLayout->addWidget(new QLabel(name, this)); + hLayout->addWidget(widget); +} + +void ParametersToolBox::changeParameter(const QString & value) +{ + if(sender()) + { + Settings::setParameter(sender()->objectName(), value); + } +} +void ParametersToolBox::changeParameter() +{ + if(sender()) + { + QDoubleSpinBox * doubleSpinBox = qobject_cast(sender()); + QSpinBox * spinBox = qobject_cast(sender()); + if(doubleSpinBox) + { + Settings::setParameter(sender()->objectName(), doubleSpinBox->value()); + } + else if(spinBox) + { + Settings::setParameter(sender()->objectName(), spinBox->value()); + } + } +} +void ParametersToolBox::changeParameter(const int & value) +{ + if(sender()) + { + QComboBox * comboBox = qobject_cast(sender()); + QCheckBox * checkBox = qobject_cast(sender()); + if(comboBox) + { + QStringList items; + for(int i=0; icount(); ++i) + { + items.append(comboBox->itemText(i)); + } + QString merged = QString::number(value) + QString(":") + items.join(";"); + Settings::setParameter(sender()->objectName(), merged); + } + else if(checkBox) + { + Settings::setParameter(sender()->objectName(), value==Qt::Checked?true:false); + } + } +} diff --git a/src/ParametersToolBox.h b/src/ParametersToolBox.h new file mode 100644 index 00000000..2f89732b --- /dev/null +++ b/src/ParametersToolBox.h @@ -0,0 +1,42 @@ +/* + * ParametersToolbox.h + * + * Created on: 2011-10-22 + * Author: matlab + */ + +#ifndef PARAMETERSTOOLBOX_H_ +#define PARAMETERSTOOLBOX_H_ + +#include + +class QVBoxLayout; +class QAbstractButton; + +class ParametersToolBox: public QToolBox +{ + Q_OBJECT + +public: + ParametersToolBox(QWidget *parent = 0); + virtual ~ParametersToolBox(); + + void setupUi(); + +private: + void addParameter(QVBoxLayout * layout, const QString & key, const QVariant & value); + void addParameter(QVBoxLayout * layout, const QString & key, const QString & value); + void addParameter(QVBoxLayout * layout, const QString & key, const int & value); + void addParameter(QVBoxLayout * layout, const QString & key, const double & value); + void addParameter(QVBoxLayout * layout, const QString & key, const bool & value); + void addParameter(QVBoxLayout * layout, const QString & name, QWidget * widget); + +private slots: + void changeParameter(); + void changeParameter(const QString & value); + void changeParameter(const int & value); + void resetCurrentPage(); + +}; + +#endif /* PARAMETERSTOOLBOX_H_ */ diff --git a/src/Settings.cpp b/src/Settings.cpp new file mode 100644 index 00000000..0acc2bdf --- /dev/null +++ b/src/Settings.cpp @@ -0,0 +1,285 @@ +/* + * Settings.cpp + * + * Created on: 2011-10-22 + * Author: matlab + */ + + +#include "Settings.h" +#include "Camera.h" +#include +#include +#include + +ParametersMap Settings::defaultParameters_; +ParametersMap Settings::parameters_; +ParametersType Settings::parametersType_; +Settings Settings::dummyInit_; +const char * Settings::iniDefaultFileName = "./" PROJECT_NAME ".ini"; + +void Settings::loadSettings(const QString & fileName, QByteArray * windowGeometry) +{ + QSettings ini(fileName, QSettings::IniFormat); + for(ParametersMap::const_iterator iter = defaultParameters_.begin(); iter!=defaultParameters_.end(); ++iter) + { + const QString & key = iter.key(); + QVariant value = ini.value(key, QVariant()); + if(value.isValid()) + { + setParameter(key, value); + } + } + + if(windowGeometry) + { + QVariant value = ini.value("windowGeometry", QVariant()); + if(value.isValid()) + { + *windowGeometry = value.toByteArray(); + } + } + + printf("Settings loaded from %s\n", fileName.toStdString().c_str()); +} + +void Settings::saveSettings(const QString & fileName, const QByteArray & windowGeometry) +{ + QSettings ini(fileName, QSettings::IniFormat); + for(ParametersMap::const_iterator iter = parameters_.begin(); iter!=parameters_.end(); ++iter) + { + QString type = Settings::getParametersType().value(iter.key()); + if(type.compare("float") == 0) + { + ini.setValue(iter.key(), QString::number(iter.value().toFloat(),'g',6)); + } + else + { + ini.setValue(iter.key(), iter.value()); + } + } + if(!windowGeometry.isEmpty()) + { + ini.setValue("windowGeometry", windowGeometry); + } + printf("Settings saved to %s\n", fileName.toStdString().c_str()); +} + +cv::FeatureDetector * Settings::createFeaturesDetector() +{ + cv::FeatureDetector * detector = 0; + QString str = getDetector_Type().toString(); + QStringList split = str.split(':'); + if(split.size()==2) + { + bool ok = false; + int index = split.first().toInt(&ok); + if(ok) + { + QStringList strategies = split.last().split(';'); + if(strategies.size() == 8 && index>=0 && index<8) + { + switch(index) + { + case 0: + if(strategies.at(index).compare("Dense") == 0) + { + cv::DenseFeatureDetector::Params params; + params.initFeatureScale = getDense_initFeatureScale().toFloat(); + params.featureScaleLevels = getDense_featureScaleLevels().toInt(); + params.featureScaleMul = getDense_featureScaleMul().toFloat(); + params.initXyStep = getDense_initXyStep().toInt(); + params.initImgBound = getDense_initImgBound().toInt(); + params.varyXyStepWithScale = getDense_varyXyStepWithScale().toBool(); + params.varyImgBoundWithScale = getDense_varyImgBoundWithScale().toBool(); + detector = new cv::DenseFeatureDetector(params); + } + break; + case 1: + if(strategies.at(index).compare("Fast") == 0) + { + detector = new cv::FastFeatureDetector( + getFast_threshold().toInt(), + getFast_nonmaxSuppression().toBool()); + } + break; + case 2: + if(strategies.at(index).compare("GoodFeaturesToTrack") == 0) + { + cv::GoodFeaturesToTrackDetector::Params params; + params.maxCorners = getGoodFeaturesToTrack_maxCorners().toInt(); + params.qualityLevel = getGoodFeaturesToTrack_qualityLevel().toDouble(); + params.minDistance = getGoodFeaturesToTrack_minDistance().toDouble(); + params.blockSize = getGoodFeaturesToTrack_blockSize().toInt(); + params.useHarrisDetector = getGoodFeaturesToTrack_useHarrisDetector().toBool(); + params.k = getGoodFeaturesToTrack_k().toDouble(); + detector = new cv::GoodFeaturesToTrackDetector(params); + } + break; + case 3: + if(strategies.at(index).compare("Mser") == 0) + { + CvMSERParams params = cvMSERParams(); + params.delta = getMser_delta().toInt(); + params.maxArea = getMser_maxArea().toInt(); + params.minArea = getMser_minArea().toInt(); + params.maxVariation = getMser_maxVariation().toFloat(); + params.minDiversity = getMser_minDiversity().toFloat(); + params.maxEvolution = getMser_maxEvolution().toInt(); + params.areaThreshold = getMser_areaThreshold().toDouble(); + params.minMargin = getMser_minMargin().toDouble(); + params.edgeBlurSize = getMser_edgeBlurSize().toInt(); + detector = new cv::MserFeatureDetector(params); + } + break; + case 4: + if(strategies.at(index).compare("Orb") == 0) + { + cv::ORB::CommonParams params; + params.scale_factor_ = getOrb_scaleFactor().toFloat(); + params.n_levels_ = getOrb_nLevels().toUInt(); + params.first_level_ = getOrb_firstLevel().toUInt(); + params.edge_threshold_ = getOrb_edgeThreshold().toInt(); + detector = new cv::OrbFeatureDetector( + getOrb_nFeatures().toUInt(), + params); + } + break; + case 5: + if(strategies.at(index).compare("Sift") == 0) + { + cv::SIFT::DetectorParams detectorParams; + detectorParams.edgeThreshold = getSift_edgeThreshold().toDouble(); + detectorParams.threshold = getSift_threshold().toDouble(); + cv::SIFT::CommonParams commonParams; + commonParams.angleMode = getSift_angleMode().toInt(); + commonParams.firstOctave = getSift_firstOctave().toInt(); + commonParams.nOctaveLayers = getSift_nOctaveLayers().toInt(); + commonParams.nOctaves = getSift_nOctaves().toInt(); + detector = new cv::SiftFeatureDetector( + detectorParams, + commonParams); + } + break; + case 6: + if(strategies.at(index).compare("Star") == 0) + { + CvStarDetectorParams params = cvStarDetectorParams(); + params.lineThresholdBinarized = getStar_lineThresholdBinarized().toInt(); + params.lineThresholdProjected = getStar_lineThresholdProjected().toInt(); + params.maxSize = getStar_maxSize().toInt(); + params.responseThreshold = getStar_responseThreshold().toInt(); + params.suppressNonmaxSize = getStar_suppressNonmaxSize().toInt(); + detector = new cv::StarFeatureDetector(params); + } + break; + case 7: + if(strategies.at(index).compare("Surf") == 0) + { + detector = new cv::SurfFeatureDetector( + getSurf_hessianThreshold().toDouble(), + getSurf_octaves().toInt(), + getSurf_octaveLayers().toInt(), + getSurf_upright().toBool()); + } + break; + default: + break; + } + } + } + } + return detector; +} + +cv::DescriptorExtractor * Settings::createDescriptorsExtractor() +{ + cv::DescriptorExtractor * extractor = 0; + QString str = getDescriptor_Type().toString(); + QStringList split = str.split(':'); + if(split.size()==2) + { + bool ok = false; + int index = split.first().toInt(&ok); + if(ok) + { + QStringList strategies = split.last().split(';'); + if(strategies.size() == 4 && index>=0 && index<4) + { + switch(index) + { + case 0: + if(strategies.at(index).compare("Brief") == 0) + { + extractor = new cv::BriefDescriptorExtractor( + getBrief_bytes().toInt()); + } + break; + case 1: + if(strategies.at(index).compare("Orb") == 0) + { + cv::ORB::CommonParams params; + params.scale_factor_ = getOrb_scaleFactor().toFloat(); + params.n_levels_ = getOrb_nLevels().toUInt(); + params.first_level_ = getOrb_firstLevel().toUInt(); + params.edge_threshold_ = getOrb_edgeThreshold().toInt(); + extractor = new cv::OrbDescriptorExtractor(params); + } + break; + case 2: + if(strategies.at(index).compare("Sift") == 0) + { + cv::SIFT::DescriptorParams descriptorParams; + descriptorParams.isNormalize = getSift_isNormalize().toBool(); + descriptorParams.magnification = getSift_magnification().toDouble(); + descriptorParams.recalculateAngles = getSift_recalculateAngles().toBool(); + cv::SIFT::CommonParams commonParams; + commonParams.angleMode = getSift_angleMode().toInt(); + commonParams.firstOctave = getSift_firstOctave().toInt(); + commonParams.nOctaveLayers = getSift_nOctaveLayers().toInt(); + commonParams.nOctaves = getSift_nOctaves().toInt(); + extractor = new cv::SiftDescriptorExtractor( + descriptorParams, + commonParams); + } + break; + case 3: + if(strategies.at(index).compare("Surf") == 0) + { + extractor = new cv::SurfDescriptorExtractor( + getSurf_octaves().toInt(), + getSurf_octaveLayers().toInt(), + getSurf_extended().toBool(), + getSurf_upright().toBool()); + } + break; + default: + break; + } + } + } + } + + return extractor; +} + +Camera * Settings::createCamera() +{ + return new Camera( + getCamera_deviceId().toInt(), + getCamera_imageWidth().toInt(), + getCamera_imageHeight().toInt()); +} + +QString Settings::currentDetectorType() +{ + int index = Settings::getDetector_Type().toString().split(':').first().toInt(); + return getDetector_Type().toString().split(':').last().split(';').at(index); +} + +QString Settings::currentDescriptorType() +{ + int index = Settings::getDescriptor_Type().toString().split(':').first().toInt(); + return getDescriptor_Type().toString().split(':').last().split(';').at(index); +} + diff --git a/src/Settings.h b/src/Settings.h new file mode 100644 index 00000000..20b8a250 --- /dev/null +++ b/src/Settings.h @@ -0,0 +1,150 @@ +/* + * Settings.h + * + * Created on: 2011-10-22 + * Author: matlab + */ + +#ifndef SETTINGS_H_ +#define SETTINGS_H_ + +#include +#include +#include +#include + +class Camera; + +typedef QMap ParametersMap; // Key, value +typedef QMap ParametersType; // Key, type + +// MACRO BEGIN +#define PARAMETER(PREFIX, NAME, TYPE, DEFAULT_VALUE) \ + public: \ + static QString k##PREFIX##_##NAME() {return QString(#PREFIX "/" #NAME);} \ + static TYPE default##PREFIX##_##NAME() {return DEFAULT_VALUE;} \ + static QString type##PREFIX##_##NAME() {return QString(#TYPE);} \ + static QVariant get##PREFIX##_##NAME() {return parameters_.value(#PREFIX "/" #NAME);} \ + static void set##PREFIX##_##NAME(const TYPE & value) {parameters_[#PREFIX "/" #NAME] = value;} \ + private: \ + class Dummy##PREFIX##_##NAME { \ + public: \ + Dummy##PREFIX##_##NAME() { \ + defaultParameters_.insert(#PREFIX "/" #NAME, QVariant(DEFAULT_VALUE)); \ + parameters_.insert(#PREFIX "/" #NAME, DEFAULT_VALUE); \ + parametersType_.insert(#PREFIX "/" #NAME, #TYPE);} \ + }; \ + Dummy##PREFIX##_##NAME dummy##PREFIX##_##NAME; +// MACRO END + +class Settings +{ + PARAMETER(Camera, deviceId, int, 0); + PARAMETER(Camera, imageWidth, int, 640); + PARAMETER(Camera, imageHeight, int, 480); + PARAMETER(Camera, imageRate, int, 5); // Hz + + //List format : [Index:item0;item1;item3;...] + PARAMETER(Detector, Type, QString, "1:Dense;Fast;GoodFeaturesToTrack;Mser;Orb;Sift;Star;Surf"); + PARAMETER(Descriptor, Type, QString, "0:Brief;Orb;Sift;Surf"); + + PARAMETER(Brief, bytes, int, 32); + + PARAMETER(Dense, initFeatureScale, float, cv::DenseFeatureDetector::Params().initFeatureScale); + PARAMETER(Dense, featureScaleLevels, int, cv::DenseFeatureDetector::Params().featureScaleLevels); + PARAMETER(Dense, featureScaleMul, float, cv::DenseFeatureDetector::Params().featureScaleMul); + PARAMETER(Dense, initXyStep, int, cv::DenseFeatureDetector::Params().initXyStep); + PARAMETER(Dense, initImgBound, int, cv::DenseFeatureDetector::Params().initImgBound); + PARAMETER(Dense, varyXyStepWithScale, bool, cv::DenseFeatureDetector::Params().varyXyStepWithScale); + PARAMETER(Dense, varyImgBoundWithScale, bool, cv::DenseFeatureDetector::Params().varyImgBoundWithScale); + + PARAMETER(Fast, threshold, int, 20); + PARAMETER(Fast, nonmaxSuppression, bool, true); + + PARAMETER(GoodFeaturesToTrack, maxCorners, int, cv::GoodFeaturesToTrackDetector::Params().maxCorners); + PARAMETER(GoodFeaturesToTrack, qualityLevel, double, cv::GoodFeaturesToTrackDetector::Params().qualityLevel); + PARAMETER(GoodFeaturesToTrack, minDistance, double, cv::GoodFeaturesToTrackDetector::Params().minDistance); + PARAMETER(GoodFeaturesToTrack, blockSize, int, cv::GoodFeaturesToTrackDetector::Params().blockSize); + PARAMETER(GoodFeaturesToTrack, useHarrisDetector, bool, cv::GoodFeaturesToTrackDetector::Params().useHarrisDetector); + PARAMETER(GoodFeaturesToTrack, k, double, cv::GoodFeaturesToTrackDetector::Params().k); + + PARAMETER(Orb, nFeatures, unsigned int, 700); + PARAMETER(Orb, scaleFactor, float, cv::ORB::CommonParams().scale_factor_); + PARAMETER(Orb, nLevels, unsigned int, cv::ORB::CommonParams().n_levels_); + PARAMETER(Orb, firstLevel, unsigned int, cv::ORB::CommonParams().first_level_); + PARAMETER(Orb, edgeThreshold, int, cv::ORB::CommonParams().edge_threshold_); + + PARAMETER(Mser, delta, int, cvMSERParams().delta); + PARAMETER(Mser, minArea, int, cvMSERParams().minArea); + PARAMETER(Mser, maxArea, int, cvMSERParams().maxArea); + PARAMETER(Mser, maxVariation, float, cvMSERParams().maxVariation); + PARAMETER(Mser, minDiversity, float, cvMSERParams().minDiversity); + PARAMETER(Mser, maxEvolution, int, cvMSERParams().maxEvolution); + PARAMETER(Mser, areaThreshold, double, cvMSERParams().areaThreshold); + PARAMETER(Mser, minMargin, double, cvMSERParams().minMargin); + PARAMETER(Mser, edgeBlurSize, int, cvMSERParams().edgeBlurSize); + + PARAMETER(Sift, threshold, double, cv::SIFT::DetectorParams::GET_DEFAULT_THRESHOLD()); + PARAMETER(Sift, edgeThreshold, double, cv::SIFT::DetectorParams::GET_DEFAULT_EDGE_THRESHOLD()); + PARAMETER(Sift, nOctaves, int, cv::SIFT::CommonParams::DEFAULT_NOCTAVES); + PARAMETER(Sift, nOctaveLayers, int, cv::SIFT::CommonParams::DEFAULT_NOCTAVE_LAYERS); + PARAMETER(Sift, firstOctave, int, cv::SIFT::CommonParams::DEFAULT_FIRST_OCTAVE); + PARAMETER(Sift, angleMode, int, cv::SIFT::CommonParams::FIRST_ANGLE); + PARAMETER(Sift, magnification, double, cv::SIFT::DescriptorParams::GET_DEFAULT_MAGNIFICATION()); + PARAMETER(Sift, isNormalize, bool, cv::SIFT::DescriptorParams::DEFAULT_IS_NORMALIZE); + PARAMETER(Sift, recalculateAngles, bool, true); + + PARAMETER(Star, maxSize, int, cvStarDetectorParams().maxSize); + PARAMETER(Star, responseThreshold, int, cvStarDetectorParams().responseThreshold); + PARAMETER(Star, lineThresholdProjected, int, cvStarDetectorParams().lineThresholdProjected); + PARAMETER(Star, lineThresholdBinarized, int, cvStarDetectorParams().lineThresholdBinarized); + PARAMETER(Star, suppressNonmaxSize, int, cvStarDetectorParams().suppressNonmaxSize); + + PARAMETER(Surf, hessianThreshold, double, 400.0); + PARAMETER(Surf, octaves, int, 3); + PARAMETER(Surf, octaveLayers, int, 4); + PARAMETER(Surf, upright, bool, false); + PARAMETER(Surf, extended, bool, false); + + PARAMETER(NN, nndrRatio, float, 0.8f); // NNDR RATIO + + PARAMETER(General, nextObjID, unsigned int, 1); + + PARAMETER(Homography, ransacReprojThr, double, 1.0); + PARAMETER(Homography, minimumInliers, int, 10); + +public: + virtual ~Settings(){} + + static const char * iniDefaultFileName; // "./" PROJECT_NAME ".ini" + + static void loadSettings(const QString & fileName = iniDefaultFileName, QByteArray * windowGeometry = 0); + static void saveSettings(const QString & fileName = iniDefaultFileName, const QByteArray & windowGeometry = QByteArray()); + + static const ParametersMap & getDefaultParameters() {return defaultParameters_;} + static const ParametersMap & getParameters() {return parameters_;} + static const ParametersType & getParametersType() {return parametersType_;} + static void setParameter(const QString & key, const QVariant & value) {if(parameters_.contains(key))parameters_[key] = value;} + static void resetParameter(const QString & key) {if(defaultParameters_.contains(key)) parameters_.insert(key, defaultParameters_.value(key));} + static QVariant getParameter(const QString & key) {return parameters_.value(key, QVariant());} + + static cv::FeatureDetector * createFeaturesDetector(); + static cv::DescriptorExtractor * createDescriptorsExtractor(); + + static QString currentDescriptorType(); + static QString currentDetectorType(); + + static Camera * createCamera(); + +private: + Settings(){} + +private: + static ParametersMap defaultParameters_; + static ParametersMap parameters_; + static ParametersType parametersType_; + static Settings dummyInit_; +}; + + +#endif /* SETTINGS_H_ */ diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 00000000..ccd4c2a3 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,18 @@ +#include +#include "MainWindow.h" + +int main(int argc, char* argv[]) +{ + /* Create tasks */ + QApplication app(argc, argv); + MainWindow mainWindow; + + mainWindow.showNormal(); + + // Now wait for application to finish + app.connect( &app, SIGNAL( lastWindowClosed() ), + &app, SLOT( quit() ) ); + app.exec();// MUST be called by the Main Thread + + return 0; +} diff --git a/src/qtipl.cpp b/src/qtipl.cpp new file mode 100644 index 00000000..5c7de42f --- /dev/null +++ b/src/qtipl.cpp @@ -0,0 +1,30 @@ + +#include "qtipl.h" +#include + +// TODO : support only from gray 8bits ? +QImage Ipl2QImage(const IplImage *newImage) +{ + QImage qtemp; + if (newImage && newImage->depth == IPL_DEPTH_8U && cvGetSize(newImage).width>0) + { + int x; + int y; + char* data = newImage->imageData; + + qtemp= QImage(newImage->width, newImage->height,QImage::Format_RGB32 ); + for( y = 0; y < newImage->height; y++, data +=newImage->widthStep ) + { + for( x = 0; x < newImage->width; x++) + { + uint *p = (uint*)qtemp.scanLine (y) + x; + *p = qRgb(data[x * newImage->nChannels+2], data[x * newImage->nChannels+1],data[x * newImage->nChannels]); + } + } + } + else + { + //Wrong IplImage format + } + return qtemp; +} diff --git a/src/qtipl.h b/src/qtipl.h new file mode 100644 index 00000000..e8631b22 --- /dev/null +++ b/src/qtipl.h @@ -0,0 +1,9 @@ +#ifndef QTIPL_H +#define QTIPL_H + +#include +#include + +QImage Ipl2QImage(const IplImage *newImage); + +#endif diff --git a/src/ui/addObjectDialog.ui b/src/ui/addObjectDialog.ui new file mode 100644 index 00000000..053606ac --- /dev/null +++ b/src/ui/addObjectDialog.ui @@ -0,0 +1,91 @@ + + + addObjectDialog + + + + 0 + 0 + 527 + 420 + + + + Add object + + + + + + (Instructions) + + + + + + + + + + + + + + + + + + + Cancel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Back + + + + + + + Take picture + + + + + + + End + + + + + + + + + + Object + QWidget +
Object.h
+ 1 +
+
+ + +
diff --git a/src/ui/mainWindow.ui b/src/ui/mainWindow.ui new file mode 100644 index 00000000..29ec4196 --- /dev/null +++ b/src/ui/mainWindow.ui @@ -0,0 +1,450 @@ + + + mainWindow + + + + 0 + 0 + 864 + 533 + + + + Find object + + + + + 0 + + + 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 + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + + + + + + + + + + + + + 0 + 0 + 864 + 25 + + + + + File + + + + + + + + + Edit + + + + + + + + View + + + + + + + + + + 300 + 180 + + + + false + + + Parameters + + + 2 + + + + + + + 0 + + + + + 0 + 0 + 282 + 401 + + + + Timings + + + + + + 6 + + + 0 + + + 0 + + + + + ms + + + + + + + 000 + + + + + + + ms + + + + + + + Descriptors extraction + + + + + + + Features detection + + + + + + + 000 + + + + + + + Descriptors matching + + + + + + + Descriptors indexing + + + + + + + 000 + + + + + + + 000 + + + + + + + ms + + + + + + + ms + + + + + + + Detect outliers and GUI + + + + + + + 000 + + + + + + + ms + + + + + + + + + Qt::Vertical + + + + 20 + 174 + + + + + + + + + + + + Restore defaults + + + + + + + + + + 300 + 121 + + + + Objects + + + 1 + + + + + + + + 150 + 0 + + + + true + + + + + 0 + 0 + 280 + 463 + + + + + 0 + + + + + Qt::Vertical + + + + 20 + 230 + + + + + + + + + + + + + + Exit + + + + + Add object... + + + + + Start camera + + + + + Stop camera + + + + + Save objects... + + + + + Load objects... + + + + + + Object + QWidget +
Object.h
+ 1 +
+ + ParametersToolBox + QToolBox +
ParametersToolBox.h
+ 1 +
+
+ + +