From be711358ea81cfbfbdd9b54ce4c436b3f1d18d47 Mon Sep 17 00:00:00 2001
From: yliu2 <liuyu2209@gmail.com>
Date: Mon, 7 Sep 2020 16:39:17 +0200
Subject: [PATCH] update image-pixel/image operations update pyramid operations
 update fourier transform operations update classification result update image
 saving process

---
 app/Algorithms/DCT.h                   |   1 -
 app/Algorithms/Pyramid.cpp             | 172 +++++++++++++------------
 app/Algorithms/Pyramid.h               |  16 ++-
 app/Operations/ClassResultOp.cpp       |  14 +-
 app/Operations/FFTOp.cpp               |  12 +-
 app/Operations/InversePyramidDialog.h  |   1 -
 app/Operations/InversePyramidDialog.ui |   2 +-
 app/Operations/InversePyramidOp.cpp    |   3 +-
 app/Operations/PointOp.cpp             |  71 ++++++----
 app/Operations/PointOp.h               |  90 ++++++++-----
 app/Operations/PyramidDialog.cpp       |   6 +
 app/Operations/PyramidDialog.h         |   1 +
 app/Operations/PyramidDialog.ui        |   4 +-
 app/Operations/PyramidOp.cpp           |   4 +-
 app/Operations/Transforms.cpp          |   8 +-
 15 files changed, 240 insertions(+), 165 deletions(-)

diff --git a/app/Algorithms/DCT.h b/app/Algorithms/DCT.h
index ad7d262..17b6513 100644
--- a/app/Algorithms/DCT.h
+++ b/app/Algorithms/DCT.h
@@ -20,7 +20,6 @@
 #ifndef DCT_H
 #define DCT_H
 
-#include "DCT.h"
 #include <Image.h>
 #include <string>
 
diff --git a/app/Algorithms/Pyramid.cpp b/app/Algorithms/Pyramid.cpp
index 6dabc89..532862d 100644
--- a/app/Algorithms/Pyramid.cpp
+++ b/app/Algorithms/Pyramid.cpp
@@ -24,6 +24,7 @@
 #include <cstring>
 #include <cstdlib>
 #include <cmath>
+#include <Converter.h>
 using namespace std;
 using namespace imagein;
 using namespace Pyramid;
@@ -133,7 +134,7 @@ void Filters::getDefault( Filtre &to_fill ) {
 }
 
 /*---------------------------------------------------------------------------
-    Cration de l'tage suivant de la pyramide Gaussienne
+    Creation de l'étage suivant de la pyramide Gaussienne
 ---------------------------------------------------------------------------*/
 void Pyramid::etage_suiv_g(const uint8_t *srcTab, uint8_t *dstTab, int srcWidth, int srcHeight, Filtre &utile)
 {
@@ -157,11 +158,12 @@ void Pyramid::etage_suiv_g(const uint8_t *srcTab, uint8_t *dstTab, int srcWidth,
 //            dstTab[i + j * dstWidth] = intermed[i + 2 * j * dstWidth];
         }
     }
-    delete intermed;
+//    delete intermed;
+    delete[] intermed;
 }
 
 /*---------------------------------------------------------------------------
-    Cration d'une pyramide Gaussienne jusqu'au nime tage
+    Creation d'une pyramide Gaussienne jusqu'au n-ième étage
 ---------------------------------------------------------------------------*/
 void Pyramid::pyram_g_n(uint8_t *rep, int nStage, long nbc, long nbl, const uint8_t *itab, Filtre &utile)
 {
@@ -185,7 +187,7 @@ void Pyramid::pyram_g_n(uint8_t *rep, int nStage, long nbc, long nbl, const uint
 }
 
 /*---------------------------------------------------------------------------
-    Creation d'une pyramide Laplacienne jusqu'au nime tage
+    Creation d'une pyramide Laplacienne jusqu'au n-ième étage
 ---------------------------------------------------------------------------*/
 void Pyramid::pyram_l_n (uint8_t *rep,int n, long nbc, long nbl, const uint8_t *itab, Filtre &utile)
 {
@@ -228,19 +230,19 @@ void Pyramid::pyram_l_n (uint8_t *rep,int n, long nbc, long nbl, const uint8_t *
 
 
 /*---------------------------------------------------------------------------
-    Cration d'une pyramide Gaussienne avec entre en conversationnel
-    des diffrentes proprits de cette pyramide
+    Creation d'une pyramide Gaussienne avec entrée en conversationnel
+    des diffrentes propriétés de cette pyramide
 ---------------------------------------------------------------------------*/
 Image *Pyramid::pyram_g(const GrayscaleImage *im, int etage_f, Filtre &utile, string &to_print)
 {
     if(!( im != NULL )) {
-        throw "Error in Pyramid::pyram_g:\nim = NULL";
+        throw "Error : Image is NULL";
     }
     if(!( im->getWidth() == im->getHeight() )) {
-        throw  "Error in Pyramid::pyram_g:\nim->getWidth() != im->getHeight()";
+        throw  "Error : Image has different width and height";
     }
     if( !isPowerOf2(im->getWidth()) ) {
-        throw  "Error in Pyramid::pyram_g:\nimage dimensions not a power of 2";
+        throw  "Error : Image dimension is not a power of 2";
     }
     long nbl = im->getHeight();
     long nbc = im->getWidth();
@@ -263,7 +265,7 @@ Image *Pyramid::pyram_g(const GrayscaleImage *im, int etage_f, Filtre &utile, st
     return resImg;
 }
 /*---------------------------------------------------------------------------
-    Cration d'un tage de la  pyramide Gaussienne
+    Creation d'un étage de la  pyramide Gaussienne
 ---------------------------------------------------------------------------*/
 Image *Pyramid::n_pyram_g(const Image *im, int etage_f, Filtre &utile, std::string &to_print)
 {
@@ -309,8 +311,8 @@ Image *Pyramid::n_pyram_g(const Image *im, int etage_f, Filtre &utile, std::stri
     return resImg;
 }
 /*---------------------------------------------------------------------------
-    Cration d'une pyramide Laplacienne avec entre en conversationnel
-    des diffrentes proprits de cette pyramide
+    Creation d'une pyramide Laplacienne avec entrée en conversationnel
+    des diffrentes propriétés de cette pyramide
 ---------------------------------------------------------------------------*/
 Image *Pyramid::pyram_l (const Image *im, int etage_f, Filtre &utile, string &to_print)
 {
@@ -342,7 +344,7 @@ Image *Pyramid::pyram_l (const Image *im, int etage_f, Filtre &utile, string &to
 
 }
 /*---------------------------------------------------------------------------
-    Cration d'un tage de la  pyramide Laplacienne
+    Creation d'un étage de la  pyramide Laplacienne
 ---------------------------------------------------------------------------*/
 Image *Pyramid::n_pyram_l(const Image *im, int etage_f, Filtre &utile, std::string &to_print)
 {
@@ -666,85 +668,87 @@ Image *Pyramid::rebuild_interface( const Image *pyramid, int etage_f, int pyrami
     // etage_f = stage that the original image was built to
     char buffer[255];
     if(!pyramid) {
-        throw "Error in TP6Pyramid::rebuild_interface:\npyramid = NULL";
+        throw "Error : Pyramid = NULL";
     }
     if(pyramid->getWidth() * 2 != pyramid->getHeight()) {
-        sprintf( buffer, "Error in TP6Pyramid::rebuild_interface:\npyramid->getWidth = %d, pyramid->getHeight = %d", pyramid->getWidth(), pyramid->getHeight() );
+        sprintf( buffer, "Error : Unsuitable size - pyramid->getWidth = %d, pyramid->getHeight = %d", pyramid->getWidth(), pyramid->getHeight());
         throw buffer;
     }
     if(!(isPowerOf2(pyramid->getWidth()))) {
-        throw "Error in TP6Pyramid::rebuild_interface:\npyramid->getWidth not a power of 2";
+        throw "Error : Height and width are not multiples of 2";
     }
     if( etage_f <= 0 || (1 << etage_f) > pyramid->getWidth() ) {
-        throw "Error in TP6Pyramid::rebuild_interface:\nInvalid etage_f specified";
+        throw "Error : Invalid etage_f specified";
     }
     if(pyramid_to < 0 || pyramid_to >= etage_f) {
-        throw "Error in TP6Pyramid::rebuild_interface:\nInvalid pyramid_to specified";
+        throw "Error : Rebuild pyramid should at a higher level";
     }
-    long nbc = pyramid->getWidth();
-    long nbl = pyramid->getWidth();
-    int i;
-    int j=0;
-    int taille_c=nbc;
-    int taille_l=nbl;
-    Image *returnval = NULL;
-    int taille;
-    int q=0;
-    int etage_rec;
-    const uint8_t *pyra1 = pyramid->begin();
-    uint8_t* intermed = new uint8_t[nbc * nbc / 2 * 3];
-    uint8_t* rep = new uint8_t[nbc * nbc / 2 * 3];
-
-    // Copy info into rep in a packed format
-    long current_offset = 0;
-    long current_rep_offset = 0;
-    for(int n = 0; n <= etage_f; ++n) {
-        for(int j=0; j< taille_l; j++ ) {
-            for(int i=0; i< taille_c; i++ ) {
-                rep[current_rep_offset + j * taille_c + i] = pyra1[current_offset + j * pyramid->getWidth() + i];
-            }
-        }
-        current_offset = current_offset + taille_l * nbc;
-        current_rep_offset = current_rep_offset + taille_l * taille_c;
-        taille_l = taille_l / 2;
-        taille_c = taille_c / 2;
-    }
-
-/* reconstruction de l'image  partir de sa pyramide laplacienne en s'arretant
-     un niveau etage_rec choisi par l'utilisateur
-    La pyramide est contenue dans la zone mmoire pointe par rep */
-    etage_rec = pyramid_to;
-    taille=nbc;
 
-    for(i=0;i<etage_f;i++)
-    {
-        q=q+taille*taille;
-        taille=taille/2;
-    }
-    for(i=q;i<q+taille*taille;i++)
-    {
-        *(intermed+i)=*(rep+i);
-    }
-    for(i=etage_f;i>etage_rec;i--)
-    {
-        agrandir((intermed+q),(intermed+q-taille*taille*4),taille,taille,utile);
-        taille=taille*2;
-        q=q-taille*taille;
-        for(j=q;j<q+taille*taille;j++)
-        {
-            int value = rep[j];
-            if(value > 128) value = value - 256;
-            value = value + intermed[j];
-            if(value < 0) value = 0;
-            if(value > 255) value = 255;
-            intermed[j] = value;
-        }
-    }
-    //printf("Entrez le nom du fichier de l'image reconstruite :");
-    //scanf("%s",nom);
-    //ecrire_image((intermed+q),nom,taille,taille);
-    returnval = new GrayscaleImage(taille, taille, intermed+q);
-    free(intermed);
-    free(rep);
-    return returnval;
-}
+    /*The reconstructed image has the same length and width*/
+    long nbc = pyramid->getWidth();
+       long nbl = pyramid->getWidth();
+       int i;
+       int j=0;
+       int taille_c=nbc;
+       int taille_l=nbl;
+       Image *returnval = NULL;
+       int taille;
+       int q=0;
+       int etage_rec;
+       const uint8_t *pyra1 = pyramid->begin();
+       uint8_t* intermed = new uint8_t[nbc * nbc / 2 * 3];
+       uint8_t* rep = new uint8_t[nbc * nbc / 2 * 3];
+
+       // Copy info into rep in a packed format
+       long current_offset = 0;
+       long current_rep_offset = 0;
+       for(int n = 0; n <= etage_f; ++n) {
+           for(int j=0; j< taille_l; j++ ) {
+               for(int i=0; i< taille_c; i++ ) {
+                   rep[current_rep_offset + j * taille_c + i] = pyra1[current_offset + j * pyramid->getWidth() + i];
+               }
+           }
+           current_offset = current_offset + taille_l * nbc;
+           current_rep_offset = current_rep_offset + taille_l * taille_c;
+           taille_l = taille_l / 2;
+           taille_c = taille_c / 2;
+       }
+
+   /* reconstruction de l'image  partir de sa pyramide laplacienne en s'arretant
+        un niveau etage_rec choisi par l'utilisateur
+       La pyramide est contenue dans la zone mmoire pointe par rep */
+       etage_rec = pyramid_to;
+       taille=nbc;
+
+       for(i=0;i<etage_f;i++)
+       {
+           q=q+taille*taille;
+           taille=taille/2;
+       }
+       for(i=q;i<q+taille*taille;i++)
+       {
+           *(intermed+i)=*(rep+i);
+       }
+       for(i=etage_f;i>etage_rec;i--)
+       {
+           agrandir((intermed+q),(intermed+q-taille*taille*4),taille,taille,utile);
+           taille=taille*2;
+           q=q-taille*taille;
+           for(j=q;j<q+taille*taille;j++)
+           {
+               int value = rep[j];
+               if(value > 128) value = value - 256;
+               value = value + intermed[j];
+               if(value < 0) value = 0;
+               if(value > 255) value = 255;
+               intermed[j] = value;
+           }
+       }
+       //printf("Entrez le nom du fichier de l'image reconstruite :");
+       //scanf("%s",nom);
+       //ecrire_image((intermed+q),nom,taille,taille);
+       returnval = new GrayscaleImage(taille, taille, intermed+q);
+       free(intermed);
+       free(rep);
+       return returnval;
+   }
diff --git a/app/Algorithms/Pyramid.h b/app/Algorithms/Pyramid.h
index f62dfb5..0d9eaae 100644
--- a/app/Algorithms/Pyramid.h
+++ b/app/Algorithms/Pyramid.h
@@ -52,8 +52,8 @@ namespace Pyramid
     *   Size is the maximum index to search for coefficient in the coeff_f[] 
     */
     struct Filtre {
-                char nom_f[30];         //!< Name of the filter 
-                float coeff_f[10];      //!< Coefficient of the filter 
+          char nom_f[30];         //!< Name of the filter
+          float coeff_f[10];      //!< Coefficient of the filter
           int taille_f;                 //!< Size of the filter
     };
 
@@ -61,7 +61,7 @@ namespace Pyramid
     * \Class Filters
     * \Brief A class used for pyramid operation
     *   
-    * This class regroup all all the filters possible in a tab 
+    * This class regroup all the filters possible in a tab
     */
     class Filters
     {
@@ -290,6 +290,16 @@ namespace Pyramid
      */
     std::string n_entropie_p(const uint8_t *pyra, int etage_f,int nbc,int nbl);
 
+    /**
+     * @brief Return the image reconstructed from a single layer in pyramide
+     *
+     * @param to_rebuild pyramid layer to rebuild
+     * @param etage_f number of level in the pyramid
+     * @param to_rebuild_to level to reconstruct
+     * @param utile filter to use
+     * @return imagein::Image* the output reconstructed image
+     */
+    imagein::Image* rebuild_basic(const imagein::Image *layer, int etage_f, int to_rebuild_to, Filtre &utile );
 
     /**
      * @brief Return the image reconstructed from a pyramide
diff --git a/app/Operations/ClassResultOp.cpp b/app/Operations/ClassResultOp.cpp
index 3ddb502..cb3767b 100644
--- a/app/Operations/ClassResultOp.cpp
+++ b/app/Operations/ClassResultOp.cpp
@@ -55,10 +55,11 @@ void ClassResultOp::operator()(const imagein::Image* img, const std::map<const i
     borderBox->setSuffix(" px");
     innerBox->setValue(8);
     borderBox->setValue(2);
-//    formLayout->insertRow(0, qApp->translate("ClassResult", "Critère de zone intérieure : "), innerBox);
-//    formLayout->insertRow(1, qApp->translate("ClassResult", "Critère de zone frontière : "), borderBox);
-    formLayout->insertRow(0, qApp->translate("ClassResult", "Largeur de couronne pour conserver la zone centrale : "), innerBox);
-    formLayout->insertRow(1, qApp->translate("ClassResult", "Largeur de couronne pour conserver la zone extérieure : "), borderBox);
+    formLayout->insertRow(0, qApp->translate("ClassResult", "Critère de zone intérieure : "), innerBox);
+    formLayout->insertRow(1, qApp->translate("ClassResult", "Critère de zone frontière : "), borderBox);
+    innerBox->setWhatsThis(qApp->translate("ClassResult", "Largeur de couronne pour conserver la zone intérieure"));
+    borderBox->setWhatsThis(qApp->translate("ClassResult", "Largeur de couronne pour conserver la zone frontière"));
+
     layout->addWidget(new QLabel(qApp->translate("ClassResult", "<b>Critère de zones (relatifs aux zones totales) : </b>")));
     layout->addLayout(formLayout);
     layout->addWidget(new QLabel(qApp->translate("ClassResult", "<b>Select the image's classes zones : </b>")));
@@ -78,12 +79,15 @@ void ClassResultOp::operator()(const imagein::Image* img, const std::map<const i
 //    int param2 = 8;
     /*The input parameters are not used*/
     int param1 = borderBox->value();
+    /*int paramBorderBox = borderBox->value();*/
     int param2 = innerBox->value();
     vector<Rectangle> selection = zoneSelector->getSelections();
     int K = selection.size();
     int* classes = new int[K];
+    outText(qApp->translate("ClassResult", "------Largeur de couronne pour conserver la zone intérieure : %1 ------").arg(param1).toStdString());
+    outText(qApp->translate("ClassResult", "------Largeur de couronne pour conserver la zone frontière : %1 ------\n").arg(param2).toStdString());
     outText(qApp->translate("ClassResult", "Voici les résultats du classement : \n").toStdString());
-    outText(qApp->translate("ClassResult", "\nNombre de classes = %1 ").arg(K).toStdString());
+    outText(qApp->translate("ClassResult", "Nombre de classes = %1 ").arg(K).toStdString());
     for(int i = 0; i < K; ++i) {
         Histogram histo = img->getHistogram(0, selection.at(i));
         classes[i] = (uint8_t) (std::max_element(histo.begin(), histo.end()) - histo.begin());
diff --git a/app/Operations/FFTOp.cpp b/app/Operations/FFTOp.cpp
index 6442955..82236b7 100644
--- a/app/Operations/FFTOp.cpp
+++ b/app/Operations/FFTOp.cpp
@@ -93,8 +93,9 @@ void FFTOp::operator()(const imagein::Image* image, const map<const imagein::Ima
                 }
             }
         }
-        this->outDoubleImage(phaseImg, qApp->translate("FFTOp", "DFT (phase)").toStdString(), true, false);
-        this->outDoubleImage(magnitudeImg, qApp->translate("FFTOp", "DFT (magnitude)").toStdString(), true, true);
+        /*(imagein::ImageDouble* img, std::string title = "", bool norm=false, bool log=false, double logScale = 1., bool abs = false)*/
+        this->outDoubleImage(phaseImg, qApp->translate("FFTOp", "DFT (Phase)").toStdString(), false, true);
+        this->outDoubleImage(magnitudeImg, qApp->translate("FFTOp", "DFT (Magnitude)").toStdString(), false, true);
     }
     else {
         Image_t<double>* realImg = new Image_t<double>(width, height, image->getNbChannels());
@@ -138,8 +139,11 @@ void FFTOp::operator()(const imagein::Image* image, const map<const imagein::Ima
                 }
             }
         }
-        this->outDoubleImage(realImg, "FFT (real)", true, true);
-        this->outDoubleImage(imagImg, "FFT (imag)", true, true);
+//        this->outDoubleImage(realImg, "FFT (real)", true, true);
+//        this->outDoubleImage(imagImg, "FFT (imag)", true, true);
+        /*Offset disabled by default*/
+        this->outDoubleImage(realImg, "FFT (Real part)", false, true);
+        this->outDoubleImage(imagImg, "FFT (Imaginary part)", false, true);
     }
 
 
diff --git a/app/Operations/InversePyramidDialog.h b/app/Operations/InversePyramidDialog.h
index 5280e8c..2dc7c9e 100644
--- a/app/Operations/InversePyramidDialog.h
+++ b/app/Operations/InversePyramidDialog.h
@@ -38,7 +38,6 @@ public:
     int getNbStep() const;
     int getStep() const;
 
-    
 private:
     Ui::InversePyramidDialog *ui;
 };
diff --git a/app/Operations/InversePyramidDialog.ui b/app/Operations/InversePyramidDialog.ui
index 22f4b29..7b0cbc3 100644
--- a/app/Operations/InversePyramidDialog.ui
+++ b/app/Operations/InversePyramidDialog.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>245</width>
-    <height>225</height>
+    <height>230</height>
    </rect>
   </property>
   <property name="windowTitle">
diff --git a/app/Operations/InversePyramidOp.cpp b/app/Operations/InversePyramidOp.cpp
index 36330a4..5c458c8 100644
--- a/app/Operations/InversePyramidOp.cpp
+++ b/app/Operations/InversePyramidOp.cpp
@@ -28,7 +28,7 @@
 using namespace std;
 using namespace imagein;
 
-InversePyramidOp::InversePyramidOp() : Operation(qApp->translate("Operations", "Pyramidal reconstruction").toStdString())
+InversePyramidOp::InversePyramidOp() : Operation(qApp->translate("Operations", "Laplacian pyramidal reconstruction").toStdString())
 {
 }
 
@@ -37,6 +37,7 @@ bool InversePyramidOp::needCurrentImg() const {
 }
 
 void InversePyramidOp::operator()(const imagein::Image* img, const std::map<const imagein::Image*, std::string>&) {
+
     if(2 * img->getWidth() != img->getHeight()) {
         QMessageBox::warning(NULL, qApp->translate("Operations", "The operation can't be applied on this image"),
                              qApp->translate("Operations", "The image width must be twice the image height."));
diff --git a/app/Operations/PointOp.cpp b/app/Operations/PointOp.cpp
index 75a3f25..c5cb395 100644
--- a/app/Operations/PointOp.cpp
+++ b/app/Operations/PointOp.cpp
@@ -50,11 +50,12 @@ PointOp::PixelOp* PointOp::PixelOp::fromString(QString op, QString expr) {
     if(op=="-") return new PixAdd(-expr.toInt(0,0));
     if(op=="*") return new PixMul(expr.toDouble());
     if(op=="/") return new PixMul(1/expr.toDouble());
-    if(op=="&") return new PixAnd(expr.toUInt(0,0));
-    if(op=="|") return new PixOr(expr.toUInt(0,0));
-    if(op=="^") return new PixXor(expr.toUInt(0,0));
-    if(op=="<<") return new PixLshift(expr.toUInt(0,0));
-    if(op==">>") return new PixRshift(expr.toUInt(0,0));
+    if(op=="&& (logical AND)") return new PixLogicalAnd(expr.toUInt(0,0));
+    if(op=="|| (logical OR)") return new PixLogicalOr(expr.toUInt(0,0));
+    if(op=="^^ (logical XOR)") return new PixLogicalXor(expr.toUInt(0,0));
+    /*The operator of shift operations is considered as a double to simplify the structure*/
+//    if(op=="<<") return new PixLshift(expr.toUInt(0,0));
+//    if(op==">>") return new PixRshift(expr.toUInt(0,0));
     if(op=="") return new PixIdent();
     std::cout << "Unknown operator '" << op.toStdString() << "' !" << std::endl;
     return new PixIdent();
@@ -64,9 +65,11 @@ PointOp::DoublePixelOp* PointOp::DoublePixelOp::fromString(QString op, QString e
     if(op=="-") return new DoublePixAdd(-expr.toDouble());
     if(op=="*") return new DoublePixMul(expr.toDouble());
     if(op=="/") return new DoublePixMul(1/expr.toDouble());
-    if(op=="&") return new DoublePixAnd(expr.toDouble());
-    if(op=="|") return new DoublePixOr(expr.toDouble());
-    if(op=="^") return new DoublePixXor(expr.toDouble());
+    if(op=="&& (logical AND)") return new DoublePixLogicalAnd(expr.toDouble());
+    if(op=="|| (logical OR)") return new DoublePixLogicalOr(expr.toDouble());
+    if(op=="^^ (logical XOR)") return new DoublePixLogicalXor(expr.toDouble());
+    if(op=="<<") return new PixLshift(expr.toDouble());
+    if(op==">>") return new PixRshift(expr.toDouble());
     if(op=="") return new DoublePixIdent();
     std::cout << "Unknown operator '" << op.toStdString() << "' !" << std::endl;
     return new DoublePixIdent();
@@ -75,11 +78,12 @@ PointOp::DoublePixelOp* PointOp::DoublePixelOp::fromString(QString op, QString e
 PointOp::ImageOp* PointOp::ImageOp::fromString(QString op) {
     if(op=="+") return new ImgAdd();
     if(op=="-") return new ImgSub();
-    if(op=="&") return new ImgAnd();
     if(op=="*") return new ImgMul();
     if(op=="/") return new ImgDiv();
-    if(op=="|") return new ImgOr();
-    if(op=="^") return new ImgXor();
+    if(op=="& (bit-wise AND)") return new ImgBitAnd();
+    if(op=="! (bit-wise NOT)") return new ImgBitNot();
+    if(op=="| (bit-wise OR)") return new ImgBitOr();
+    if(op=="^ (bit-wise XOR)") return new ImgBitXor();
     if(op=="") return new ImgIdent();
     std::cout << "Unknown operator '" << op.toStdString() << "' !" << std::endl;
     return new ImgIdent();
@@ -90,9 +94,7 @@ PointOp::DoubleImageOp* PointOp::DoubleImageOp::fromString(QString op) {
     if(op=="-") return new DoubleImgSub();
     if(op=="*") return new DoubleImgMul();
     if(op=="/") return new DoubleImgDiv();
-    if(op=="&") return new DoubleImgAnd();
-    if(op=="|") return new DoubleImgOr();
-    if(op=="^") return new DoubleImgXor();
+    if(op=="! (bit-wise NOT)") return new DoubleImgBitNot();
     if(op=="") return new DoubleImgIdent();
     std::cout << "Unknown operator '" << op.toStdString() << "' !" << std::endl;
     return new DoubleImgIdent();
@@ -100,10 +102,12 @@ PointOp::DoubleImageOp* PointOp::DoubleImageOp::fromString(QString op) {
 
 void PointOp::operator()(const ImageWindow* currentWnd, const vector<const ImageWindow*>& wndList) {
 
-    QStringList pixOperators, imgOperators;
+    QStringList pixOperators, imgOperators, pixDoubleOperators;
+
+    pixOperators << "" << "+" << "-" << "*" << "/" << "&& (logical AND)" << "|| (logical OR)" << "^^ (logical XOR)" << "<<" << ">>";
+    pixDoubleOperators << "" << "+" << "-" << "*" << "/";
+    imgOperators << "" << "+" << "-" << "*" << "/" << "& (bit-wise AND)" << "! (bit-wise NOT)" << "| (bit-wise OR)" << "^ (bit-wise XOR)";
 
-    pixOperators << "" << "+" << "-" << "*" << "/" << "&" << "|" << "^" << "<<" << ">>";
-    imgOperators << "" << "+" << "-" << "*" << "/" << "&" << "|" << "^";
     QString currentImgName = currentWnd->windowTitle();
     map<const Image*,string> stdImgList;
     map<const Image_t<double>*,string> dblImgList;
@@ -125,19 +129,17 @@ void PointOp::operator()(const ImageWindow* currentWnd, const vector<const Image
     QVBoxLayout* layout = new QVBoxLayout();
     dialog->setLayout(layout);
 
-    /*The generation order of the widgets does not match the layout, exchange their positions*/
     QGroupBox* radioGroup = new QGroupBox(qApp->translate("PointOp", "Second operand"), dialog);
-//    QRadioButton* uCharButton = new QRadioButton(qApp->translate("PointOp", "UChar"));
-//    QRadioButton* doubleButton = new QRadioButton(qApp->translate("PointOp", "Double"));
     QRadioButton* valueButton = new QRadioButton(qApp->translate("PointOp", "Value"));
+    valueButton->setWhatsThis(qApp->translate("PointOp", "Enter a real number in the blank space below as the second operand"));
     QRadioButton* imageButton = new QRadioButton(qApp->translate("PointOp", "Image"));
+    imageButton->setWhatsThis(qApp->translate("PointOp", "Select an image as the second operand"));
 
     QGroupBox* radioGroup2 = new QGroupBox(qApp->translate("PointOp", "Output image"), dialog);
-//    QRadioButton* valueButton = new QRadioButton(qApp->translate("PointOp", "Value"));
-//    QRadioButton* imageButton = new QRadioButton(qApp->translate("PointOp", "Image"));
     QRadioButton* uCharButton = new QRadioButton(qApp->translate("PointOp", "UChar"));
+    uCharButton->setWhatsThis(qApp->translate("PointOp", "Output the result image in uchar format"));
     QRadioButton* doubleButton = new QRadioButton(qApp->translate("PointOp", "Double"));
-
+    doubleButton->setWhatsThis(qApp->translate("PointOp", "Output the result image in double format"));
 
     QHBoxLayout* radioLayout = new QHBoxLayout(radioGroup);
     radioLayout->addWidget(valueButton);
@@ -152,7 +154,6 @@ void PointOp::operator()(const ImageWindow* currentWnd, const vector<const Image
     valueButton->setChecked(true);
     uCharButton->setChecked(true);
 
-
     //Si l'image est une image double le bouton est obligatoirement coché
     if(currentWnd->isDouble()){
         doubleButton->setChecked(true);
@@ -164,8 +165,11 @@ void PointOp::operator()(const ImageWindow* currentWnd, const vector<const Image
     QHBoxLayout* optLayout = new QHBoxLayout();
     QGridLayout* gridLayout = new QGridLayout();
     QCheckBox* offsetBox = new QCheckBox(qApp->translate("PointOp","Offset"));
+    offsetBox->setWhatsThis(qApp->translate("PointOp", "Add an offset of 127 to fit negative values"));
     QCheckBox* scalingBox = new QCheckBox(qApp->translate("PointOp","Scaling"));
+    scalingBox->setWhatsThis(qApp->translate("PointOp", "Map the value of each pixel to the range of 0-255 proportionally"));
     QCheckBox* colorBox = new QCheckBox(qApp->translate("PointOp", "Explode colors"));
+    colorBox->setWhatsThis(qApp->translate("PointOp", "Check this option to execute the manipulation by channel"));
     offsetBox->setAutoExclusive(false);
     scalingBox->setAutoExclusive(false);
     offsetBox->setEnabled(!doubleButton->isChecked());
@@ -193,8 +197,15 @@ void PointOp::operator()(const ImageWindow* currentWnd, const vector<const Image
     QWidget* pixelWidget = new QWidget(dialog);
     valueLayouts[0] = new QHBoxLayout();
     pixOperatorBoxes[0] = new QComboBox(pixelWidget);
+    pixOperatorBoxes[0]->setWhatsThis(qApp->translate("PointOp", "Supported operations list which takes a value as operand: \n The input operand will be rounded down for shift operations"));
     imgOperatorBoxes[0] = new QComboBox(pixelWidget);
-    pixOperatorBoxes[0]->addItems(pixOperators);
+    imgOperatorBoxes[0]->setWhatsThis(qApp->translate("PointOp", "Supported operations list whick takes an image as operand: \n The bit-wise NOT operation will automatically ignore the second image"));
+    if(currentWnd->isStandard()){
+        pixOperatorBoxes[0]->addItems(pixOperators);
+    }
+    if(currentWnd->isDouble()){
+        pixOperatorBoxes[0]->addItems(pixDoubleOperators);
+    }
     imgOperatorBoxes[0]->addItems(imgOperators);
     exprEdits[0] = new QLineEdit(pixelWidget);
     exprEdits[0]->setFixedWidth(64);
@@ -215,7 +226,13 @@ void PointOp::operator()(const ImageWindow* currentWnd, const vector<const Image
         valueLayouts[i] = new QHBoxLayout();
         pixOperatorBoxes[i] = new QComboBox(colorWidget);
         imgOperatorBoxes[i] = new QComboBox(colorWidget);
-        pixOperatorBoxes[i]->addItems(pixOperators);
+        if(currentWnd->isStandard()){
+            pixOperatorBoxes[i]->addItems(pixOperators);
+        }
+        if(currentWnd->isDouble()){
+            pixOperatorBoxes[i]->addItems(pixDoubleOperators);
+        }
+
         imgOperatorBoxes[i]->addItems(imgOperators);
         exprEdits[i] = new QLineEdit(colorWidget);
         exprEdits[i]->setFixedWidth(64);
@@ -244,7 +261,7 @@ void PointOp::operator()(const ImageWindow* currentWnd, const vector<const Image
     QObject::connect(uCharButton, SIGNAL(toggled(bool)), scalingBox, SLOT(setEnabled(bool)));
     QObject::connect(doubleButton, SIGNAL(toggled(bool)), offsetBox, SLOT(setChecked(bool)));
     QObject::connect(doubleButton, SIGNAL(toggled(bool)), scalingBox, SLOT(setChecked(bool)));
-    
+
     layout->setSizeConstraint(QLayout::SetFixedSize);
     
     QPushButton *okButton = new QPushButton(qApp->translate("Operations", "Validate"), dialog);
diff --git a/app/Operations/PointOp.h b/app/Operations/PointOp.h
index e78e5ff..c9b2a12 100644
--- a/app/Operations/PointOp.h
+++ b/app/Operations/PointOp.h
@@ -24,7 +24,6 @@
 #include <map>
 #include <limits>
 #include <QCoreApplication>
-
 #include "Operation.h"
 #include "Image.h"
 
@@ -51,7 +50,6 @@ class PointOp : public GenericOperation {
         return static_cast<depth_t>(value);
     }
 
-
     struct PixelOp {
         virtual depth_t operator()(depth_t pixel) {
             return normalize(this->op(pixel));
@@ -87,6 +85,7 @@ class PointOp : public GenericOperation {
         PixAdd(int value_) : PixOp_t<int>(value_) {}
         intmax_t op(depth_t pixel) { return pixel + value; }
     };
+
     struct DoublePixAdd : DoublePixelOp {
         DoublePixAdd(double value_) : DoublePixelOp(value_) {}
         double op(double pixel) { return pixel + value; }
@@ -96,54 +95,72 @@ class PointOp : public GenericOperation {
         PixMul(double value_) : PixOp_t<double>(value_) {}
         intmax_t op(depth_t pixel) { return pixel * value + 0.5; }
     };
+
     struct DoublePixMul : DoublePixelOp {
         DoublePixMul(double value_) : DoublePixelOp(value_) {}
         double op(double pixel) { return pixel * value; }
     };
 
-    struct PixAnd : PixOp_t<depth_t> {
-        PixAnd(depth_t value_) : PixOp_t<depth_t>(value_) {}
-        intmax_t op(depth_t pixel) { return pixel & value; }
+    struct PixLogicalAnd : PixOp_t<depth_t> {
+        PixLogicalAnd(depth_t value_) : PixOp_t<depth_t>(value_) {}
+        intmax_t op(depth_t pixel) { return pixel && value; }
     };
 
     /*Return zero if the operands have zero*/
-    struct DoublePixAnd : DoublePixelOp {
-        DoublePixAnd(double value_) : DoublePixelOp(value_) {}
+    struct DoublePixLogicalAnd : DoublePixelOp {
+        DoublePixLogicalAnd(double value_) : DoublePixelOp(value_) {}
         double op(double pixel) { return (pixel==0 or value==0) ? 0 : pixel; }
     };
 
-    struct PixOr : PixOp_t<depth_t> {
-        PixOr(depth_t value_) : PixOp_t<depth_t>(value_) {}
-        intmax_t op(depth_t pixel) { return pixel | value; }
+    /*There's no not logic for double value*/
+    struct PixNot : PixOp_t<depth_t> {
+        PixNot(depth_t value_) : PixOp_t<depth_t>(value_) {}
+        intmax_t op(depth_t pixel) { return 255 - pixel; }
+    };
+
+    struct PixLogicalOr : PixOp_t<depth_t> {
+        PixLogicalOr(depth_t value_) : PixOp_t<depth_t>(value_) {}
+        intmax_t op(depth_t pixel) { return pixel || value; }
     };
 
     /*Return zero only if the operands are both zero*/
-    struct DoublePixOr : DoublePixelOp {
-        DoublePixOr(double value_) : DoublePixelOp(value_) {}
+    struct DoublePixLogicalOr : DoublePixelOp {
+        DoublePixLogicalOr(double value_) : DoublePixelOp(value_) {}
         double op(double pixel) { return (pixel==0 and value==0) ? 0 : pixel; }
     };
 
-    struct PixXor : PixOp_t<depth_t> {
-        PixXor(depth_t value_) : PixOp_t<depth_t>(value_) {}
-        intmax_t op(depth_t pixel) { return pixel ^ value; }
+    struct PixLogicalXor : PixOp_t<depth_t> {
+        PixLogicalXor(depth_t value_) : PixOp_t<depth_t>(value_) {}
+        intmax_t op(depth_t pixel) { return (pixel==value) ? 0 : pixel; }
     };
 
     /*Return zero only if the operands have the same value*/
-    struct DoublePixXor : DoublePixelOp {
-        DoublePixXor(double value_) : DoublePixelOp(value_) {}
+    struct DoublePixLogicalXor : DoublePixelOp {
+        DoublePixLogicalXor(double value_) : DoublePixelOp(value_) {}
         double op(double pixel) { return (pixel==value) ? 0 : pixel; }
     };
 
-    struct PixLshift : PixOp_t<unsigned int> {
-        PixLshift(unsigned int value_) : PixOp_t<unsigned int>(value_) {}
-        intmax_t op(depth_t pixel) { return pixel << value; }
-    };
+//    struct PixLshift : PixOp_t<depth_t> {
+//        PixLshift(depth_t value_) : PixOp_t<depth_t>(value_) {}
+//        intmax_t op(depth_t pixel) { return pixel << value; }
+//    };
     
-    struct PixRshift : PixOp_t<unsigned int> {
-        PixRshift(unsigned int value_) : PixOp_t<unsigned int>(value_) {}
-        intmax_t op(depth_t pixel) { return pixel >> value; }
+//    struct PixRshift : PixOp_t<depth_t> {
+//        PixRshift(depth_t value_) : PixOp_t<depth_t>(value_) {}
+//        intmax_t op(depth_t pixel) { return (int)pixel >> (int)value; }
+//    };
+
+    struct PixLshift : DoublePixelOp {
+        PixLshift(depth_t value_) : DoublePixelOp(value_) {}
+        double op(double pixel) { return (int)pixel << (int)value; }
     };
 
+    struct PixRshift : DoublePixelOp {
+        PixRshift(depth_t value_) : DoublePixelOp(value_) {}
+        double op(double pixel) { return (int)pixel >> (int)value; }
+    };
+
+
     struct ImageOp {
         virtual depth_t operator()(depth_t pixel1, depth_t pixel2) {
             return normalize(this->op(pixel1, pixel2));
@@ -196,27 +213,38 @@ class PointOp : public GenericOperation {
         double op(double pix1, double pix2) { return pix1 / pix2; }
     };
 
-    struct ImgAnd : ImageOp {
+    struct ImgBitAnd : ImageOp {
         intmax_t op(depth_t pix1, depth_t pix2) { return pix1 & pix2; } 
     };
 
-    struct DoubleImgAnd : DoubleImageOp {
+    struct DoubleImgBitAnd : DoubleImageOp {
         double op(double pix1, double pix2) { return (pix1==0 or pix2==0) ? 0 : pix1;}
     };
-    
-    struct ImgOr : ImageOp {
+
+    /*To keep the symmetry of the interface, BitNot was categorized as an image operation
+      But for the negation operation, the second operand is unnecessary*/
+    struct ImgBitNot : ImageOp {
+        intmax_t op(depth_t pix1, depth_t pix2) { return 255 - pix1; }
+    };
+
+    /*DoubleImgBitNot is defined to reconcile two operators in different types*/
+    struct DoubleImgBitNot : DoubleImageOp {
+        double op(double pix1, double pix2) { return 255 - pix1; }
+    };
+
+    struct ImgBitOr : ImageOp {
         intmax_t op(depth_t pix1, depth_t pix2) { return pix1 | pix2; } 
     };
     
-    struct DoubleImgOr : DoubleImageOp {
+    struct DoubleImgBitOr : DoubleImageOp {
         double op(double pix1, double pix2) { return (pix1==0 and pix2==0) ? 0 : pix1;}
     };
 
-    struct ImgXor : ImageOp {
+    struct ImgBitXor : ImageOp {
         intmax_t op(depth_t pix1, depth_t pix2) { return pix1 ^ pix2; } 
     };
 
-    struct DoubleImgXor : DoubleImageOp {
+    struct DoubleImgBitXor : DoubleImageOp {
         double op(double pix1, double pix2) { return (pix1 == pix2) ? 0 : pix1; }
     };
 
diff --git a/app/Operations/PyramidDialog.cpp b/app/Operations/PyramidDialog.cpp
index f7eb036..d56e099 100644
--- a/app/Operations/PyramidDialog.cpp
+++ b/app/Operations/PyramidDialog.cpp
@@ -86,3 +86,9 @@ void PyramidDialog::setOneStepChecked(bool a){
 void PyramidDialog::setOneStep(int a){
     ui->onlyStepBox->setValue(a);
 }
+
+/*Update the maximum decomposition level according to the size of the input image*/
+void PyramidDialog::updateMaxLevel(int max)
+{
+    ui->stepBox->setMaximum(max);
+}
diff --git a/app/Operations/PyramidDialog.h b/app/Operations/PyramidDialog.h
index e28a0a2..a4a8ff9 100644
--- a/app/Operations/PyramidDialog.h
+++ b/app/Operations/PyramidDialog.h
@@ -45,6 +45,7 @@ public:
     void setFilter(int);
     void setOneStep(int);
     void setOneStepChecked(bool);
+    void updateMaxLevel(int);
 
 private:
     Ui::PyramidDialog *ui;
diff --git a/app/Operations/PyramidDialog.ui b/app/Operations/PyramidDialog.ui
index 2a1cccb..fc1e4b2 100644
--- a/app/Operations/PyramidDialog.ui
+++ b/app/Operations/PyramidDialog.ui
@@ -81,7 +81,7 @@
      <item row="1" column="0">
       <widget class="QLabel" name="nbStepLabel">
        <property name="text">
-        <string>Number of steps : </string>
+        <string>Number of levels : </string>
        </property>
       </widget>
      </item>
@@ -102,7 +102,7 @@
      <item>
       <widget class="QCheckBox" name="oneStepBox">
        <property name="text">
-        <string>Create only one step :</string>
+        <string>Create only one level :</string>
        </property>
       </widget>
      </item>
diff --git a/app/Operations/PyramidOp.cpp b/app/Operations/PyramidOp.cpp
index 5253d7a..2bfbd3f 100644
--- a/app/Operations/PyramidOp.cpp
+++ b/app/Operations/PyramidOp.cpp
@@ -52,6 +52,8 @@ void PyramidOp::operator()(const imagein::Image* img, const std::map<const image
     }
 
     PyramidDialog* dialog = new PyramidDialog(QApplication::activeWindow());
+    /*Update the maximum decomposition level according to the size of the input image*/
+    dialog->updateMaxLevel(Pyramid::etage_max(img));
 
     if(_test){
         dialog->setFilter(_filter);
@@ -94,7 +96,7 @@ void PyramidOp::operator()(const imagein::Image* img, const std::map<const image
         }
     }
     catch(const char*e) {
-        QMessageBox::critical(NULL, "Error", QString(e));
+        QMessageBox::critical(NULL, "Error", QString("wtf"));
         return;
     }
 
diff --git a/app/Operations/Transforms.cpp b/app/Operations/Transforms.cpp
index ebf9644..b22dad8 100644
--- a/app/Operations/Transforms.cpp
+++ b/app/Operations/Transforms.cpp
@@ -567,10 +567,10 @@ for(unsigned int c = 0; c < tmpImg->getNbChannels(); c++) {
 //    size = nbc * nbl;
 //    GrayscaleImage* tabout = new GrayscaleImage(im->getWidth(), im->getHeight());
 //    Image_t<double>* tmpImg = Converter<Image_t<double> >::convert(*image);
-////    tabin = new double[ size ];
-////    for(i=0 ; i<nbl ; i++)
-////        for(j=0 ; j<nbc ; j++)
-////            tabin[i*nbc+j] = (double)im->getPixel( j, i );
+//    tabin = new double[ size ];
+//    for(i=0 ; i<nbl ; i++)
+//        for(j=0 ; j<nbc ; j++)
+//            tabin[i*nbc+j] = (double)im->getPixel( j, i );
 
 ///*---------------------------------------------------------------------
 //*
-- 
GitLab