diff --git a/app/SandboxSetup/beamerlocationgui.cpp b/app/SandboxSetup/beamerlocationgui.cpp index f655bc70cb7666826d42a3853b20c8fc210ba0c2..213a2a1b436b9a9e989f17abefc02a79b30fb71c 100644 --- a/app/SandboxSetup/beamerlocationgui.cpp +++ b/app/SandboxSetup/beamerlocationgui.cpp @@ -152,7 +152,7 @@ void BeamerLocationGui::userValidePoint(){ // enough points to perform linear regression and move into next step if(capturedPoints.size() >= beamer->MAX_LINEAR_LINE_POINTS){ - beamer->findLinearLineFrom(&capturedPoints, &bases, &directions); + beamer->findLinearLine(&capturedPoints, &bases, &directions); capturedPoints.clear(); stepCross++; diff --git a/app/SandboxSetup/beamerlocationgui.ui b/app/SandboxSetup/beamerlocationgui.ui index 6bb6fc48258fd56b02b446aae0a552c959226e7d..135e9bc5d49177ffbfb11bd4f96342a66b08f521 100644 --- a/app/SandboxSetup/beamerlocationgui.ui +++ b/app/SandboxSetup/beamerlocationgui.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>632</width> - <height>639</height> + <height>661</height> </rect> </property> <property name="windowTitle"> @@ -17,7 +17,7 @@ <property name="geometry"> <rect> <x>240</x> - <y>570</y> + <y>600</y> <width>131</width> <height>51</height> </rect> @@ -45,7 +45,7 @@ <x>40</x> <y>360</y> <width>541</width> - <height>201</height> + <height>231</height> </rect> </property> <property name="readOnly"> @@ -62,7 +62,8 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Note :</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - The little square at the center will change from red to green when it detects the target.</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - For each point you validate, change the height of your target to not save the same position twice in the process.</p></body></html></string> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - For each point you validate, change the height of your target to not save the same position twice in the process.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> - If the detection of the target fail or is inconsistent (maybe due to the square passing to green), go back and adjust the parameters</p></body></html></string> </property> </widget> <widget class="QLabel" name="label_2"> diff --git a/app/SandboxSetup/camerafocusgui.cpp b/app/SandboxSetup/camerafocusgui.cpp index 86349965ba5d0c3d5227896e96db14870e3ea593..724ebdaaf6467ae38af4739c0d6fd24c81f1951e 100644 --- a/app/SandboxSetup/camerafocusgui.cpp +++ b/app/SandboxSetup/camerafocusgui.cpp @@ -44,6 +44,7 @@ void CameraFocusGui::showEvent(QShowEvent *event){ cv::Mat black = cv::Mat(setup->getBeamer()->getHeight(), setup->getBeamer()->getWidth(), CV_8UC3, cv::Scalar(0, 0, 0)); cv::line(black, cv::Point(black.cols/2, 0), cv::Point(black.cols/2, black.rows-1), cv::Scalar(255, 0, 0), 4); cv::line(black, cv::Point(0, black.rows/2), cv::Point(black.cols-1, black.rows/2), cv::Scalar(255, 0, 0), 4); + cv::rectangle(black, cv::Point(black.cols/2 -10, black.rows/2 -10), cv::Point(black.cols/2 +10, black.rows/2 +10), cv::Scalar(0, 180, 0), cv::FILLED, 8, 0 ); blackScreen->editGeometry(mg->getResolution()); blackScreen->imShow(black); frameTimer->start(100); @@ -98,6 +99,7 @@ void CameraFocusGui::refreshFrame(){ // Preview image for the user cv::cvtColor(rgb, gray, CV_BGR2GRAY); + cv::GaussianBlur(gray, gray, cv::Size(9, 9), 2, 2); gray = setup->getBeamer()->editContrast(gray, (double)profil->getContrast(), (double)profil->getBrightness()); cv::Canny(gray, cannyGray, profil->getCannyEdgeThreshold(), profil->getCannyEdgeThreshold()/2); diff --git a/app/SandboxSetup/camerafocusgui.ui b/app/SandboxSetup/camerafocusgui.ui index ac84b6fb1bb14708b26df670ac26734cc9ce5dd5..6c48d3ded8dfe116bd73e0df448f0ae35e6b48f1 100644 --- a/app/SandboxSetup/camerafocusgui.ui +++ b/app/SandboxSetup/camerafocusgui.ui @@ -39,7 +39,7 @@ <property name="geometry"> <rect> <x>680</x> - <y>270</y> + <y>260</y> <width>89</width> <height>25</height> </rect> @@ -100,7 +100,7 @@ <property name="geometry"> <rect> <x>60</x> - <y>310</y> + <y>290</y> <width>671</width> <height>311</height> </rect> @@ -389,6 +389,39 @@ </item> </layout> </widget> + <widget class="QLabel" name="label_6"> + <property name="geometry"> + <rect> + <x>50</x> + <y>610</y> + <width>161</width> + <height>17</height> + </rect> + </property> + <property name="text"> + <string>Instructions :</string> + </property> + </widget> + <widget class="QTextEdit" name="txtInstructions"> + <property name="geometry"> + <rect> + <x>60</x> + <y>630</y> + <width>671</width> + <height>31</height> + </rect> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="html"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Now you can remove the cardboard and adjust the parameters to easily detect the circle target.</p></body></html></string> + </property> + </widget> </widget> <resources/> <connections/> diff --git a/app/SandboxSetup/mainwindow.cpp b/app/SandboxSetup/mainwindow.cpp index 69fa475c92bf387f21181a2154b5d622ba97d9af..2fa7223066ece3d6e30090ee60743c416dfbfedb 100644 --- a/app/SandboxSetup/mainwindow.cpp +++ b/app/SandboxSetup/mainwindow.cpp @@ -15,16 +15,16 @@ MainWindow::MainWindow(QWidget *parent) : init = new InitCameraGui(setup); mg = new MonitorGui(setup); pg = new ProjectionGui(setup, mg); - cf = new CameraFocusGui(setup, mg); cm = new CroppingMaskGui(setup, mg); + cf = new CameraFocusGui(setup, mg); bl = new BeamerLocationGui(setup, mg); scfg = new SaveConfigGui(setup); applist.push_back(init); applist.push_back(mg); applist.push_back(pg); - applist.push_back(cf); applist.push_back(cm); + applist.push_back(cf); applist.push_back(bl); applist.push_back(scfg); @@ -38,8 +38,8 @@ MainWindow::~MainWindow() { delete scfg; delete bl; - delete cm; delete cf; + delete cm; delete pg; delete mg; delete init; diff --git a/app/SandboxSetup/mainwindow.ui b/app/SandboxSetup/mainwindow.ui index 1bed0271cfb6027a6a18489b3fa480750749c02f..5ad209fa47871ccb4f92382ca5c190a34bf6854c 100644 --- a/app/SandboxSetup/mainwindow.ui +++ b/app/SandboxSetup/mainwindow.ui @@ -10,7 +10,7 @@ <x>0</x> <y>0</y> <width>800</width> - <height>747</height> + <height>789</height> </rect> </property> <property name="focusPolicy"> @@ -26,7 +26,7 @@ <x>0</x> <y>50</y> <width>801</width> - <height>621</height> + <height>661</height> </rect> </property> <layout class="QVBoxLayout" name="apps"/> @@ -38,7 +38,7 @@ <property name="geometry"> <rect> <x>650</x> - <y>680</y> + <y>720</y> <width>89</width> <height>25</height> </rect> @@ -54,7 +54,7 @@ <property name="geometry"> <rect> <x>530</x> - <y>680</y> + <y>720</y> <width>89</width> <height>25</height> </rect> @@ -70,7 +70,7 @@ <property name="geometry"> <rect> <x>330</x> - <y>680</y> + <y>720</y> <width>89</width> <height>25</height> </rect> diff --git a/app/SandboxSetup/monitorgui.cpp b/app/SandboxSetup/monitorgui.cpp index 0f427a489e3cd9cd9816e83b33497e38561a02df..d2dbd2a6aae63cfec673a886e1a93a49aecab71c 100644 --- a/app/SandboxSetup/monitorgui.cpp +++ b/app/SandboxSetup/monitorgui.cpp @@ -1,7 +1,5 @@ #include "monitorgui.h" #include "ui_monitorgui.h" -#include <X11/Xlib.h> -#include <X11/extensions/Xrandr.h> MonitorGui::MonitorGui(SandboxSetup *_setup, QWidget *parent) : SubApp("Monitors", "Cancel resolution", parent), @@ -13,7 +11,7 @@ MonitorGui::MonitorGui(SandboxSetup *_setup, QWidget *parent) : std::string path = ".monitors.tmp"; monitors = std::map<std::string, std::vector<std::string>>(); - initMonitorMap(); + initMonitorMapWithFile(path); QList<QScreen*> screens = QApplication::screens(); for(int i=0; i<screens.size(); i++){ @@ -82,42 +80,17 @@ void MonitorGui::on_cbxOutputs_currentIndexChanged(int index) showMonitorsScreenshot(sc); } -void MonitorGui::initMonitorMap(){ - - Display *dp = XOpenDisplay(NULL); - if(dp){ - XRRScreenResources *screen = XRRGetScreenResources (dp, DefaultRootWindow(dp)); - - // 4 display ports - // physical caracteristics ? - for(int i=0; i<screen->ncrtc; i++){ - XRRCrtcInfo *info = XRRGetCrtcInfo (dp, screen, screen->crtcs[i]); - - // 2 display port ON (main monitor + beamer) - // display connected with modes vs display unconnected with no modes ? - for(int j=0; j<info->noutput; j++){ - - XRROutputInfo *output = XRRGetOutputInfo(dp, screen, info->outputs[j]); - if(output->nmode > 0){ - std::string key = std::string(output->name); - monitors[key] = std::vector<std::string>(); - - for(int k=0; k<output->nmode; k++){ - XRRModeInfo resolution = screen->modes[k]; - std::string res = std::string(std::to_string(resolution.width) + "x" + std::to_string(resolution.height)); - - if(std::find(monitors[key].begin(), monitors[key].end(), res) == monitors[key].end()) - monitors[key].push_back(res); - } - } - XRRFreeOutputInfo(output); - } - XRRFreeCrtcInfo(info); - } - XRRFreeScreenResources(screen); - XCloseDisplay(dp); - } +void MonitorGui::initMonitorMapWithFile(std::string path){ + + // Save in file the monitors and their resolutions + int err = system( ("xrandr | sed -n '1!p' > " + path).c_str() ); + if(err){ + std::cout << "Couldn't get screens and their resolutions" << std::endl; + exit(err); + } + loadResolutionsFromFile(path); + std::remove(path.c_str()); } // load resolutions into GUI @@ -146,6 +119,31 @@ std::vector<std::string> MonitorGui::splitResolution(std::string s){ return res; } +bool MonitorGui::isResolution(std::string s){ + return splitResolution(s).size() == 2; +} + +void MonitorGui::loadResolutionsFromFile(std::string path){ + // Get monitors and their resolutions into a Map + std::ifstream infile(path); + std::string line; + std::string key; + + while (std::getline(infile, line)){ + + std::istringstream iss(line); + std::string l; + iss >> l; + + if(!isResolution(l)){ + key = l; + monitors[key] = std::vector<std::string>(); + }else{ + monitors[key].push_back(l); + } + } +} + void MonitorGui::showMonitorsScreenshot(QScreen *screen){ QPixmap px = screen->grabWindow(0); ui->lblScreenshot->setPixmap(px); diff --git a/app/SandboxSetup/monitorgui.h b/app/SandboxSetup/monitorgui.h index 642272206139d76c9458033e49cf20e47908e57a..6d9c0856dc6596c0963478b1a031d96afca7ed68 100644 --- a/app/SandboxSetup/monitorgui.h +++ b/app/SandboxSetup/monitorgui.h @@ -50,8 +50,10 @@ private: QScreen* getMonitor(); void loadResolutionsOf(QScreen* screen); std::vector<std::string> splitResolution(std::string s); + bool isResolution(std::string s); + void loadResolutionsFromFile(std::string path); + void initMonitorMapWithFile(std::string path); void showMonitorsScreenshot(QScreen *screen); - void initMonitorMap(); }; #endif // MONITORGUI_H diff --git a/inc/beamer.h b/inc/beamer.h index b881f128ec5418eb28a9fbf7b9707c40c012fbd2..d5dff5d5eaf1106bc9ae3d273923feea258891a7 100644 --- a/inc/beamer.h +++ b/inc/beamer.h @@ -39,7 +39,7 @@ class Beamer{ std::vector<cv::Point2i> getCrossList(); cv::Mat buildCrossFrame(cv::Point2i projectedCross, int step, int max, bool circlesFound); cv::Point3d approximatePosition(std::vector<cv::Point3d> *bases, std::vector<cv::Point3d> *directions); - void findLinearLineFrom(std::vector<cv::Point3f> *capturedPoints, std::vector<cv::Point3d> *bases, std::vector<cv::Point3d> *directions); + void findLinearLine(std::vector<cv::Point3f> *capturedPoints, std::vector<cv::Point3d> *bases, std::vector<cv::Point3d> *directions); std::vector<cv::Point3i> findCircles(cv::Mat &rgb, double contrast, int brightness, double centersMinDist, int cannyEdgeThreshold, int houghAccThreshold, double minRadius, double maxRadius); void printPosition(); diff --git a/inc/sandbox.h b/inc/sandbox.h index c07945d215ac4d6935f8341999ab39ff3b9735bb..5fc8e3b407c18a31d675504246d8cbed1e4e9a1c 100644 --- a/inc/sandbox.h +++ b/inc/sandbox.h @@ -7,6 +7,10 @@ #include "beamer.h" #include "sandboxConfig.h" +/*! +* @class Sandbox +* API to build augmented reality applications which use the configuration file +*/ class Sandbox{ private: char *defaultConfigFilePath = (char *)"./sandbox_conf.yaml"; @@ -23,13 +27,55 @@ class Sandbox{ Beamer* getBeamer(){ return beamer; }; Projection* getProjection(){ return projection; }; + /*! + * Initialize the components needed for the applications + * @return int indicating if there was an error, where 0 indicates no error + */ int init(); + + /*! + * Capture a frame from the camera, this update the depth buffer and the color buffer of the camera + */ void captureFrame(); + + /*! + * Get a copy of the colored RGB frame from the buffer + * @return Colored frame represented by a matrix filled of 3 bytes values + */ cv::Mat_<cv::Vec3b> getColorFrame(); + + /*! + * Get a copy of the depth frame from the buffer with values in meter + * @return Depth frame represented by a matrix filled of float values + */ cv::Mat_<float> getDepthFrame(); + + /*! + * Adjust the frame to the topology by taking a picture with the depth camera + * @param frame Image to be adapted on the sandbox + * @return The image adjusted to the topology in RGB + */ cv::Mat_<cv::Vec3b> adjustProjection(cv::Mat_<cv::Vec3b> &frame); + + /*! + * Adjust the frame to the topology by adapting to the topology passed with the frame + * @param frame Image to be adapted on the sandbox + * @param depth Depth frame representing the topology of the sand + * @return The image adjusted to the topology in RGB + */ cv::Mat_<cv::Vec3b> adjustProjection(cv::Mat_<cv::Vec3b> &frame, cv::Mat_<float> &depth); + + /*! + * Load the configuration from the file at the default location + * @return int indicating if there was an error, where 0 indicates no error + */ int loadConfig(); + + /*! + * Load the configuration from the file at the specified location + * @param path to the configuration file + * @return int indicating if there was an error, where 0 indicates no error + */ int loadConfig(char *path); }; diff --git a/inc/sandboxSetup.h b/inc/sandboxSetup.h index 5449a2ae17cd8408ce3ffa3fb34ee6a876dd5a85..6a436c30aa42d6a0e5e32f440df8e1e99a56aaa9 100644 --- a/inc/sandboxSetup.h +++ b/inc/sandboxSetup.h @@ -7,6 +7,10 @@ #include "camera.h" #include "sandboxConfig.h" +/*! +* @class SandboxSetup +* API to build setup applications which will generate the configuration file +*/ class SandboxSetup{ private: char *defaultConfigFilePath = (char *)"./sandbox_conf.yaml"; @@ -27,17 +31,57 @@ class SandboxSetup{ Beamer* getBeamer(){ return beamer; }; - // save config in file => persistant + /*! + * Save the configuration in the file at the path indicated + * @param path Location of the file will be save + * @return int indicating if there was an error, where 0 indicates no error + */ int saveConfig(char *path); + + /*! + * Save the configuration in the file at default path + * @return int indicating if there was an error, where 0 indicates no error + */ int saveConfig(); + /*! + * Load the FrameProcessProfil from a specific file + * @param path Location of the file to read from + * @return int indicating if there was an error, where 0 indicates no error + */ int loadFrameProcessProfil(char *path); + + /*! + * Load the FrameProcessProfil from the default location + * @return int indicating if there was an error, where 0 indicates no error + */ int loadFrameProcessProfil(); + + /*! + * Load the CroppingMask and the AdjusingMatrix from a specific file + * @param path Location of the file to read from + * @return int indicating if there was an error, where 0 indicates no error + */ int loadCroppingMaskAndAdjustingMatrix(char *path); + + /*! + * Load the FrameProcessProfil from the default location + * @return int indicating if there was an error, where 0 indicates no error + */ int loadCroppingMaskAndAdjustingMatrix(); - // edit variables of config => not persistant + /*! + * Find the adjusting matrix from the coordinates of the corner of the rectangle and the center of rotation + * @param rectPoints List of the points forming the rectangle + * @param center Coordinates of the center of rotation + */ void setupAdjustMatrix(std::vector<cv::Point2i> rectPoints, cv::Point2i center); + + /*! + * Find the cropping mask from the coordinates of the corner of the rectangle and the center of rotation by applying the rotation on the corners + * @param rectPoints List of the points forming the rectangle + * @param center Coordinates of the center of rotation + */ void setupCroppingMask(std::vector<cv::Point2i> rectPoints, cv::Point2i center); }; diff --git a/src/components/beamer.cpp b/src/components/beamer.cpp index f1eefbe5bf428a166077f2dd4f3b2cd416c876b3..d5a4f5cc9e882a159a5f096c94d7b8c67c6a656e 100644 --- a/src/components/beamer.cpp +++ b/src/components/beamer.cpp @@ -55,12 +55,12 @@ cv::Mat Beamer::editContrast(cv::Mat image, double contrast, int brightness){ std::vector<cv::Point3i> Beamer::findCircles(cv::Mat &rgb, double contrast, int brightness, double centersMinDist, int cannyEdgeThreshold, int houghAccThreshold, double minRadius, double maxRadius){ cv::Mat src_gray; - cv::cvtColor(rgb, src_gray, CV_BGR2GRAY); - /// Reduce the noise so we avoid false circle detection - cv::GaussianBlur(src_gray, src_gray, cv::Size(9, 9), 2, 2); std::vector<cv::Vec3f> circles; circles.clear(); + cv::cvtColor(rgb, src_gray, CV_BGR2GRAY); + /// Reduce the noise so we avoid false circle detection + cv::GaussianBlur(src_gray, src_gray, cv::Size(9, 9), 2, 2); src_gray = editContrast(src_gray, (double)contrast, (double)brightness); /// Apply the Hough Transform to find the circles @@ -88,7 +88,7 @@ cv::Mat Beamer::buildCrossFrame(cv::Point projectedCross, int step, int max, boo cv::Mat frameImage(resolution, CV_8UC3, cv::Scalar(0, 0, 0)); cv::Scalar red = cv::Scalar(0, 0, 255); - cv::Scalar color = (circlesFound) ? cv::Scalar(0, 255, 0) : cv::Scalar(0, 0, 255); + cv::Scalar color = (circlesFound) ? cv::Scalar(0, 180, 0) : cv::Scalar(0, 0, 255); cv::line(frameImage, cv::Point(projectedCross.x, 0), cv::Point(projectedCross.x, frameImage.rows - 1), red, 4); cv::line(frameImage, cv::Point(0, projectedCross.y), cv::Point(frameImage.cols - 1, projectedCross.y), red, 4); @@ -111,7 +111,7 @@ cv::Mat Beamer::buildCrossFrame(cv::Point projectedCross, int step, int max, boo } -void Beamer::findLinearLineFrom(std::vector<cv::Point3f> *capturedPoints, std::vector<cv::Point3d> *bases, std::vector<cv::Point3d> *directions){ +void Beamer::findLinearLine(std::vector<cv::Point3f> *capturedPoints, std::vector<cv::Point3d> *bases, std::vector<cv::Point3d> *directions){ cv::Vec6f line; cv::fitLine(*capturedPoints, line, CV_DIST_L2, 0, 0.01, 0.01);