From d729aaa23dd85d16ae2f70d24034f20f789748e2 Mon Sep 17 00:00:00 2001
From: "simon.fanetti" <simon.fanetti@etu.hesge.ch>
Date: Wed, 20 May 2020 14:22:33 +0200
Subject: [PATCH] temp cropping mask app

---
 app/SandboxSetup/SandboxSetup.pro |   9 +-
 app/SandboxSetup/croppingmask.cpp | 104 +++++++++++++++++++++++
 app/SandboxSetup/croppingmask.h   |  45 ++++++++++
 app/SandboxSetup/croppingmask.ui  | 134 ++++++++++++++++++++++++++++++
 app/SandboxSetup/main.cpp         |  50 ++++++-----
 app/SandboxSetup/monitorgui.cpp   |   8 +-
 inc/beamer.h                      |   4 +-
 inc/sandboxSetup.h                |   3 +
 src/lib/sandboxSetup.cpp          |  51 +++++++++---
 9 files changed, 369 insertions(+), 39 deletions(-)
 create mode 100644 app/SandboxSetup/croppingmask.cpp
 create mode 100644 app/SandboxSetup/croppingmask.h
 create mode 100644 app/SandboxSetup/croppingmask.ui

diff --git a/app/SandboxSetup/SandboxSetup.pro b/app/SandboxSetup/SandboxSetup.pro
index 69b20aa..b9aa084 100644
--- a/app/SandboxSetup/SandboxSetup.pro
+++ b/app/SandboxSetup/SandboxSetup.pro
@@ -26,15 +26,18 @@ DEFINES += QT_DEPRECATED_WARNINGS
 SOURCES += \
         main.cpp \
     monitorgui.cpp \
-    camerafocus.cpp
+    camerafocus.cpp \
+    croppingmask.cpp
 
 HEADERS += \
     monitorgui.h \
-    camerafocus.h
+    camerafocus.h \
+    croppingmask.h
 
 FORMS += \
     monitorgui.ui \
-    camerafocus.ui
+    camerafocus.ui \
+    croppingmask.ui
 
 
 
diff --git a/app/SandboxSetup/croppingmask.cpp b/app/SandboxSetup/croppingmask.cpp
new file mode 100644
index 0000000..b76acca
--- /dev/null
+++ b/app/SandboxSetup/croppingmask.cpp
@@ -0,0 +1,104 @@
+#include "croppingmask.h"
+#include "ui_croppingmask.h"
+
+CroppingMask::CroppingMask(SandboxSetup *sandbox, QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::CroppingMask)
+{
+    ui->setupUi(this);
+    setup = sandbox;
+    // TODO : try to load cropping mask from file
+
+}
+
+CroppingMask::~CroppingMask()
+{
+    delete ui;
+}
+
+void CroppingMask::paintEvent(QPaintEvent *){
+    QPainter p;
+    p.begin(this);
+    p.end();
+}
+
+void CroppingMask::on_btnTakePicture_clicked()
+{
+    setup->captureBlueScreen();
+    cv::Mat rgb = setup->camera.getRGBFrame();
+    cameraRGBFrame = rgb;
+
+    QImage img = QImage((uchar *)rgb.data, (int)rgb.cols, (int)rgb.rows, static_cast<int>(rgb.step.buf[0]), QImage::Format_RGB888);
+    QPixmap image = QPixmap::fromImage(img);
+
+    //ui->lblFrame->setPixmap(image);
+
+    // no config found
+    if(!maskValideInFrame(rgb)){
+        float y = ui->lblMask->height();
+        float x = ui->lblMask->width();
+        rectPoints = std::vector<cv::Point>{ cv::Point(1.0/4*x, 1.0/4*y), cv::Point(1.0/4*x, 3.0/4*y), cv::Point(3.0/4*x, 3.0/4*y), cv::Point(3.0/4*x, 1.0/4*y) };
+    }
+    drawMask(rectPoints);
+}
+
+bool CroppingMask::maskValideInFrame(cv::Mat rgb){
+
+    if(rectPoints.empty())
+        return false;
+
+    for(uint i=0; i<rectPoints.size(); i++){
+        if( !(( 0<=rectPoints[i].x && rectPoints[i].x<rgb.size().width ) &&
+            ( 0<=rectPoints[i].y && rectPoints[i].y<rgb.size().height ) ))
+            {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void CroppingMask::drawMask(std::vector<cv::Point> rectPoints){
+
+    QPixmap img;
+    QPainter maskPainter(&img);
+    QPolygon poly;
+
+    for(uint i=0; i<rectPoints.size(); i++){
+        poly << QPoint(rectPoints[i].x, rectPoints[i].y);
+    }
+
+    // QPen: style(), width(), brush(), capStyle() and joinStyle().
+    QPen pen(Qt::green, 2, Qt::DashLine, Qt::RoundCap, Qt::RoundJoin);
+    maskPainter.setPen(pen);
+    maskPainter.drawPolygon(poly);
+
+    maskPainter.drawRect(15,15,100,100);
+
+
+    QPixmap px;
+    QPainter p(&px);
+    p.setPen(Qt::blue);
+    p.drawLine(5,5, 40, 40);
+    p.end();
+
+    ui->lblMask->setPixmap(px);
+}
+
+void CroppingMask::scaleMaskWindowToFrame(){
+
+    float xCoeff = cameraRGBFrame.size().width / ui->lblMask->width();
+    float yCoeff = cameraRGBFrame.size().height / ui->lblMask->height();
+
+    for(uint i=0; i<rectPoints.size(); i++){
+        rectPoints[i].x = rectPoints[i].x * xCoeff;
+        rectPoints[i].y = rectPoints[i].y * yCoeff;
+    }
+}
+
+void CroppingMask::on_btnbxEnd_accepted()
+{
+    state = true;
+    // Needed because the image shown is stretched
+    scaleMaskWindowToFrame();
+}
diff --git a/app/SandboxSetup/croppingmask.h b/app/SandboxSetup/croppingmask.h
new file mode 100644
index 0000000..b582cbc
--- /dev/null
+++ b/app/SandboxSetup/croppingmask.h
@@ -0,0 +1,45 @@
+#ifndef CROPPINGMASK_H
+#define CROPPINGMASK_H
+
+#include <QDialog>
+#include <sandboxSetup.h>
+
+#include <QPainter>
+#include <QPolygon>
+//#include <QPainterPath>
+
+namespace Ui {
+class CroppingMask;
+}
+
+class CroppingMask : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit CroppingMask(SandboxSetup *sandbox,QWidget *parent = 0);
+    ~CroppingMask();
+    std::vector<cv::Point> getRectPoints(){ return rectPoints; };
+    bool isOk(){ return state; };
+
+private slots:
+    void on_btnTakePicture_clicked();
+    void on_btnbxEnd_accepted();
+
+private:
+    Ui::CroppingMask *ui;
+    SandboxSetup *setup;
+    std::vector<cv::Point> rectPoints;
+    bool state = false;
+    cv::Mat cameraRGBFrame;
+
+    bool maskValideInFrame(cv::Mat rgb);
+    void drawMask(std::vector<cv::Point> rectPoints);
+    void scaleMaskWindowToFrame();
+
+protected:
+    void paintEvent(QPaintEvent* event);
+
+};
+
+#endif // CROPPINGMASK_H
diff --git a/app/SandboxSetup/croppingmask.ui b/app/SandboxSetup/croppingmask.ui
new file mode 100644
index 0000000..c206a8c
--- /dev/null
+++ b/app/SandboxSetup/croppingmask.ui
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CroppingMask</class>
+ <widget class="QDialog" name="CroppingMask">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>635</width>
+    <height>422</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <widget class="QDialogButtonBox" name="btnbxEnd">
+   <property name="enabled">
+    <bool>true</bool>
+   </property>
+   <property name="geometry">
+    <rect>
+     <x>270</x>
+     <y>370</y>
+     <width>341</width>
+     <height>32</height>
+    </rect>
+   </property>
+   <property name="orientation">
+    <enum>Qt::Horizontal</enum>
+   </property>
+   <property name="standardButtons">
+    <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+   </property>
+  </widget>
+  <widget class="QLabel" name="lblFrame">
+   <property name="geometry">
+    <rect>
+     <x>40</x>
+     <y>30</y>
+     <width>441</width>
+     <height>281</height>
+    </rect>
+   </property>
+   <property name="lineWidth">
+    <number>3</number>
+   </property>
+   <property name="text">
+    <string>Press &quot;Take Picture&quot; when your beamer is ready</string>
+   </property>
+   <property name="scaledContents">
+    <bool>true</bool>
+   </property>
+   <property name="alignment">
+    <set>Qt::AlignCenter</set>
+   </property>
+   <property name="wordWrap">
+    <bool>false</bool>
+   </property>
+  </widget>
+  <widget class="QPushButton" name="btnTakePicture">
+   <property name="geometry">
+    <rect>
+     <x>520</x>
+     <y>60</y>
+     <width>101</width>
+     <height>25</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Take Picture</string>
+   </property>
+  </widget>
+  <widget class="QLabel" name="lblMask">
+   <property name="geometry">
+    <rect>
+     <x>40</x>
+     <y>30</y>
+     <width>441</width>
+     <height>281</height>
+    </rect>
+   </property>
+   <property name="lineWidth">
+    <number>3</number>
+   </property>
+   <property name="text">
+    <string/>
+   </property>
+   <property name="scaledContents">
+    <bool>true</bool>
+   </property>
+   <property name="alignment">
+    <set>Qt::AlignCenter</set>
+   </property>
+   <property name="wordWrap">
+    <bool>false</bool>
+   </property>
+  </widget>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>btnbxEnd</sender>
+   <signal>accepted()</signal>
+   <receiver>CroppingMask</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>btnbxEnd</sender>
+   <signal>rejected()</signal>
+   <receiver>CroppingMask</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/app/SandboxSetup/main.cpp b/app/SandboxSetup/main.cpp
index 079ccbf..8c5d5dc 100644
--- a/app/SandboxSetup/main.cpp
+++ b/app/SandboxSetup/main.cpp
@@ -1,5 +1,6 @@
 #include "monitorgui.h"
 #include "camerafocus.h"
+#include "croppingmask.h"
 #include <QApplication>
 
 #include <sandboxSetup.h>
@@ -8,44 +9,55 @@ int main(int argc, char *argv[])
 {
 
     SandboxSetup setup;
-    QApplication a(argc, argv);
+    QApplication app(argc, argv);
 
-    MonitorGui m;
-    m.show();
-    a.exec();
-    if(!m.isOk()){
+
+    // Select output screen and projection's resolutions
+    MonitorGui mg;
+    mg.show();
+    app.exec();
+    if(!mg.isOk()){
         std::cout << "Cancel resolution" << std::endl;
         return 1;
     }
-    setup.setBeamerResolution(cv::Size(m.getWidth(), m.getHeight()));
+    setup.setBeamerResolution(cv::Size(mg.getWidth(), mg.getHeight()));
+
 
-    CameraFocus c(&setup);
-    c.show();
-    a.exec();
-    if(!c.isOk()){
+    // Edit frame process profil for the setupBeamerLocation routine
+    CameraFocus cf(&setup);
+    cf.show();
+    app.exec();
+    if(!cf.isOk()){
         std::cout << "Cancel camera parameters" << std::endl;
         return 1;
     }
 
-    FrameProcessProfil p = *setup.beamer.getProfil();
-    std::cout << "params" << std::endl;
-    std::cout << p.getContrast() << std::endl;
-    std::cout << p.getBrightness() << std::endl;
-    std::cout << p.getRadiusRatio() << std::endl;
-    std::cout << p.getUpperMinThreshold() << std::endl;
-    std::cout << p.getLowerMinThreshold() << std::endl;
 
-
-    if(setup.setupProjection()){
+    // Setup the adjust matrix and cropping mask
+    CroppingMask cm(&setup);
+    cm.show();
+    app.exec();
+    if(!cm.isOk()){
         std::cout << "Cancel crop" << std::endl;
         return 1;
     }
 
+    cv::Size s = setup.camera.getDepthFrame().size();
+    cv::Point center(s.width / 2, s.height / 2);
+    std::vector<cv::Point> rectPoints = cm.getRectPoints();
+
+    setup.setupAdjustMatrix(rectPoints, center);
+    setup.setupCroppingMask(rectPoints);
+
+
+    // Setup the beamer location
     if(setup.setupBeamerLocation()){
         std::cout << "Cancel beamer position" << std::endl;
         return 1;
     }
 
+
+    // Save config in file
     if(setup.saveConfig()){
         std::cout << "Failed to save configuration" << std::endl;
         return 1;
diff --git a/app/SandboxSetup/monitorgui.cpp b/app/SandboxSetup/monitorgui.cpp
index 17c43a3..d146386 100644
--- a/app/SandboxSetup/monitorgui.cpp
+++ b/app/SandboxSetup/monitorgui.cpp
@@ -47,7 +47,11 @@ void MonitorGui::on_btnbxMonitors_accepted()
 void MonitorGui::initMonitorMapWithFile(std::string path){
 
     // Save in file the monitors and their resolutions
-    system( ("xrandr -d :0 | sed -n '1!p' > " + path).c_str() );
+    int err = system( ("xrandr -d :0 | 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());
 }
@@ -58,7 +62,7 @@ void MonitorGui::loadResolutionsOf(QScreen* sc){
     const char *key = sc->name().toStdString().c_str();
     std::vector<std::string> resolutions = monitors[key];
 
-    for(int i=0; i<resolutions.size(); i++){
+    for(uint i=0; i<resolutions.size(); i++){
         std::vector<std::string> res = splitResolution(resolutions[i]);
         ui->cbxResolutions->addItem( QString::fromStdString(res[0] + "x" + res[1]) );
     }
diff --git a/inc/beamer.h b/inc/beamer.h
index d0460f5..c1caea0 100644
--- a/inc/beamer.h
+++ b/inc/beamer.h
@@ -13,8 +13,8 @@ class FrameProcessProfil{
         // radius of the circle based on the width of the frame, where :
         // radius = frame.width / ratioRadius
         int ratioRadius; // [1, n]
-        int upperMinThreshold; // [lowerMin, 255]
-        int lowerMinThreshold; // [0, upperMin]
+        int upperMinThreshold; // [lowerMin, 255] the strongest the contrast in the image is, the higher this param should be
+        int lowerMinThreshold; // [0, upperMin] should be set way lower than upperMin if cicles have weak contrasts at their edges
     
     public:
         FrameProcessProfil(double c=1.0, int b=0, int r=8, int up=200, int low=100){
diff --git a/inc/sandboxSetup.h b/inc/sandboxSetup.h
index e3a9389..574d6c0 100644
--- a/inc/sandboxSetup.h
+++ b/inc/sandboxSetup.h
@@ -28,6 +28,9 @@ class SandboxSetup{
         int saveFrameProcessProfil();
 
         // edit variables of config => not persistant
+        void captureBlueScreen();
+        void setupAdjustMatrix(std::vector<cv::Point> rectPoints, cv::Point center);
+        void setupCroppingMask(std::vector<cv::Point> rectPoints);
         int setupProjection();
         int setupBeamerResolution();
         int setupBeamerLocation();
diff --git a/src/lib/sandboxSetup.cpp b/src/lib/sandboxSetup.cpp
index 3938ff8..46d0f2d 100644
--- a/src/lib/sandboxSetup.cpp
+++ b/src/lib/sandboxSetup.cpp
@@ -61,6 +61,10 @@ int SandboxSetup::saveFrameProcessProfil(){
 }
 
 
+//
+// Default setup routines
+//
+
 int SandboxSetup::setupBeamerResolution(){
     int width = 0;
     int height = 0;
@@ -92,22 +96,12 @@ int SandboxSetup::setupBeamerLocation(){
 // return 1 when user exits process
 int SandboxSetup::setupProjection(){
 
-    // Blue screen 
-    char windowName[] = "border";
-    initWindowsFullScreen(windowName);
-    cv::Mat frameBeamer(cv::Size(beamer.getWidth(), beamer.getHeight()), CV_8UC3, cv::Scalar(255, 0, 0));
-    cv::imshow(windowName, frameBeamer);
-    cv::waitKey(100);
+    captureBlueScreen();
 
-    // Take picture
-    camera.start(); // 1 seconde of warming up
-    camera.captureFrame();
     cv::Mat frameData = camera.getDepthFrame();
     cv::Mat coloredFrame = camera.getRGBFrame();
     cv::Size s = frameData.size();
     cv::Point center(s.width / 2, s.height / 2);
-    camera.stop();
-    cv::destroyAllWindows();
 
     // Edit projection
     float y = coloredFrame.size().height;
@@ -118,18 +112,49 @@ int SandboxSetup::setupProjection(){
     }
     cv::destroyAllWindows();
 
+    
+    // must be called before setupCroppingMask
+    setupAdjustMatrix(rectPoints, center);
+
+    setupCroppingMask(rectPoints);
+
+    return 0;
+}
+
+
+void SandboxSetup::captureBlueScreen(){
+
+    // Blue screen 
+    char windowName[] = "border";
+    initWindowsFullScreen(windowName);
+    cv::Mat frameBeamer(cv::Size(beamer.getWidth(), beamer.getHeight()), CV_8UC3, cv::Scalar(255, 0, 0));
+    cv::imshow(windowName, frameBeamer);
+    cv::waitKey(100);
+
+    // Take picture
+    camera.start(); // 1 seconde of warming up
+    camera.captureFrame();
+    camera.stop();
+    cv::destroyAllWindows();
+}
+
+
+void SandboxSetup::setupAdjustMatrix(std::vector<cv::Point> rectPoints, cv::Point center){
+
     // Set adjusting matrix for the projection
     int widthTop = rectPoints[3].x - rectPoints[0].x;
     double angle1 = atan((double)(rectPoints[3].y - rectPoints[0].y) / widthTop);
     cv::Mat matRotation = cv::getRotationMatrix2D(center, toDegrees(angle1), 1); // adjustingMatrix
     projection.setAdjustingMatrix(matRotation);
+}
+
+void SandboxSetup::setupCroppingMask(std::vector<cv::Point> rectPoints){
 
     // Set cropping mask
+    int widthTop = rectPoints[3].x - rectPoints[0].x;
     cv::Size rectSize = cv::Size(widthTop, cvRound(widthTop / 1.33333) + 5);
     cv::Point p = projection.rotatePixel(rectPoints[0]);
     camera.setCroppingMask(cv::Rect(p, rectSize)); // croppingMask
-
-    return 0;
 }
 
 
-- 
GitLab