From f42104a225741d2c102d05b442e4c9a0d059ea78 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sacha=20Percot-T=C3=A9tu?= <zakinster@zakinster.com>
Date: Thu, 5 Jul 2012 19:13:35 +0200
Subject: [PATCH] Added PixelOperation

---
 app/Operations/PixelOperation.cpp | 236 ++++++++++++++++++++++++++++++
 app/Operations/PixelOperation.h   | 148 +++++++++++++++++++
 2 files changed, 384 insertions(+)
 create mode 100644 app/Operations/PixelOperation.cpp
 create mode 100644 app/Operations/PixelOperation.h

diff --git a/app/Operations/PixelOperation.cpp b/app/Operations/PixelOperation.cpp
new file mode 100644
index 0000000..e5845ee
--- /dev/null
+++ b/app/Operations/PixelOperation.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ * 
+ * This file is part of EIImage.
+ * 
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <QWidget>
+#include <QDialog>
+#include <QVBoxLayout>
+#include <QButtonGroup>
+#include <QRadioButton>
+#include <QPushButton>
+#include <QLabel>
+#include <QLineEdit>
+#include <QComboBox>
+#include <QCheckBox>
+#include <QGroupBox>
+
+#include "PixelOperation.h"
+#include "ImgWidget.h"
+
+using namespace std;
+using namespace imagein;
+
+PixelOperation::PixelOperation() : Operation("Pixel operations") {
+    
+}
+
+PixelOperation::PixelOp* PixelOperation::PixelOp::fromString(QString op, QString expr) {
+    if(op=="+") return new PixAdd(expr.toInt(0,0));
+    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=="") return new PixIdent();
+    std::cout << "Unknown operator '" << op.toStdString() << "' !" << std::endl;
+    return new PixIdent();
+}
+
+PixelOperation::ImageOp* PixelOperation::ImageOp::fromString(QString op) {
+    if(op=="+") return new ImgAdd();
+    if(op=="-") return new ImgSub();
+    if(op=="&") return new ImgAnd();
+    if(op=="|") return new ImgOr();
+    if(op=="^") return new ImgXor();
+    if(op=="") return new ImgIdent();
+    std::cout << "Unknown operator '" << op.toStdString() << "' !" << std::endl;
+    return new ImgIdent();
+}
+
+vector<QWidget*> PixelOperation::operator()(const imagein::Image* image, const std::map<std::string, const imagein::Image*>& imgList) {
+    vector<QWidget*> result;
+    QStringList pixOperators, imgOperators;
+    pixOperators << "" << "+" << "-" << "*" << "/" << "&" << "|" << "^" << "<<" << ">>";
+    imgOperators << "" << "+" << "-" << "&" << "|" << "^";
+    QStringList imageNames;
+    for(map<string, const Image*>::const_iterator it = imgList.begin(); it != imgList.end(); ++it) {
+        imageNames << it->first.c_str();
+    }
+    
+    
+    QDialog* dialog = new QDialog();
+    dialog->setWindowTitle(dialog->tr("Parameter"));
+    dialog->setMinimumWidth(180);
+    QVBoxLayout* layout = new QVBoxLayout();
+    dialog->setLayout(layout);
+
+    QGroupBox* radioGroup = new QGroupBox("Second operand", dialog);
+    QRadioButton* valueButton = new QRadioButton(dialog->tr("Value"));
+    QRadioButton* imageButton = new QRadioButton(dialog->tr("Image"));
+    QHBoxLayout* radioLayout = new QHBoxLayout(radioGroup);
+    radioLayout->addWidget(valueButton);
+    radioLayout->addWidget(imageButton);
+    layout->addWidget(radioGroup);
+    valueButton->setChecked(true);
+
+    QCheckBox* colorBox = new QCheckBox("Explode colors", dialog);
+    layout->addWidget(colorBox);
+
+    int nChannel = image->getNbChannels();
+    QHBoxLayout** valueLayouts = new QHBoxLayout*[nChannel+1];
+    QComboBox** pixOperatorBoxes = new QComboBox*[nChannel+1];
+    QComboBox** imgOperatorBoxes = new QComboBox*[nChannel+1];
+    QLineEdit** exprEdits = new QLineEdit*[nChannel+1];
+    QComboBox** imageBoxes = new QComboBox*[nChannel+1];
+
+    QWidget* pixelWidget = new QWidget(dialog);
+    valueLayouts[0] = new QHBoxLayout();
+    pixOperatorBoxes[0] = new QComboBox(pixelWidget);
+    imgOperatorBoxes[0] = new QComboBox(pixelWidget);
+    pixOperatorBoxes[0]->addItems(pixOperators); 
+    imgOperatorBoxes[0]->addItems(imgOperators); 
+    exprEdits[0] = new QLineEdit(pixelWidget);
+    exprEdits[0]->setFixedWidth(64);
+    imageBoxes[0] = new QComboBox(pixelWidget);
+    imageBoxes[0]->addItems(imageNames);
+    valueLayouts[0]->addWidget(new QLabel("Image", pixelWidget));
+    valueLayouts[0]->addWidget(pixOperatorBoxes[0]);
+    valueLayouts[0]->addWidget(imgOperatorBoxes[0]);
+    valueLayouts[0]->addWidget(exprEdits[0]);
+    valueLayouts[0]->addWidget(imageBoxes[0]);
+    imageBoxes[0]->setVisible(false);
+    imgOperatorBoxes[0]->setVisible(false);
+    pixelWidget->setLayout(valueLayouts[0]);
+    layout->addWidget(pixelWidget);
+
+    QWidget* colorWidget = new QWidget(dialog);
+    colorWidget->setLayout(new QVBoxLayout());
+    for(int i=1; i <= nChannel; ++i) {
+        valueLayouts[i] = new QHBoxLayout();
+        pixOperatorBoxes[i] = new QComboBox(colorWidget);
+        imgOperatorBoxes[i] = new QComboBox(colorWidget);
+        pixOperatorBoxes[i]->addItems(pixOperators); 
+        imgOperatorBoxes[i]->addItems(imgOperators); 
+        exprEdits[i] = new QLineEdit(colorWidget);
+        exprEdits[i]->setFixedWidth(64);
+        imageBoxes[i] = new QComboBox(colorWidget);
+        imageBoxes[i]->addItems(imageNames);
+        valueLayouts[i]->addWidget(new QLabel(colorName(i-1, nChannel), colorWidget));
+        valueLayouts[i]->addWidget(pixOperatorBoxes[i]);
+        valueLayouts[i]->addWidget(imgOperatorBoxes[i]);
+        valueLayouts[i]->addWidget(exprEdits[i]);
+        valueLayouts[i]->addWidget(imageBoxes[i]);
+        imageBoxes[i]->setVisible(false);
+        imgOperatorBoxes[i]->setVisible(false);
+        colorWidget->layout()->addItem(valueLayouts[i]);
+    }
+    colorWidget->setVisible(false);
+    layout->addWidget(colorWidget);
+
+    for(int i=0; i<=nChannel; ++i) {
+        QObject::connect(valueButton, SIGNAL(toggled(bool)), exprEdits[i], SLOT(setVisible(bool)));
+        QObject::connect(valueButton, SIGNAL(toggled(bool)), pixOperatorBoxes[i], SLOT(setVisible(bool)));
+        QObject::connect(imageButton, SIGNAL(toggled(bool)), imageBoxes[i], SLOT(setVisible(bool)));
+        QObject::connect(imageButton, SIGNAL(toggled(bool)), imgOperatorBoxes[i], SLOT(setVisible(bool)));
+    }
+    QObject::connect(colorBox, SIGNAL(toggled(bool)), pixelWidget, SLOT(setHidden(bool)));
+    QObject::connect(colorBox, SIGNAL(toggled(bool)), colorWidget, SLOT(setVisible(bool)));
+    
+    layout->setSizeConstraint(QLayout::SetFixedSize);
+    
+    QPushButton *okButton = new QPushButton(dialog->tr("Validate"), dialog);
+    okButton->setDefault(true);
+    layout->addWidget(okButton);
+    QObject::connect(okButton, SIGNAL(clicked()), dialog, SLOT(accept()));
+    
+    QDialog::DialogCode code = static_cast<QDialog::DialogCode>(dialog->exec());
+    
+    if(code!=QDialog::Accepted) {
+        return result;
+    }
+
+    PixelOp** pixelOps = new PixelOp*[nChannel];
+    ImageOp** imageOps = new ImageOp*[nChannel];
+    const Image**  imageImgs = new const Image*[nChannel];
+    unsigned int maxWidth = image->getWidth();
+    unsigned int maxHeight = image->getHeight();
+    
+    if(!colorBox->isChecked()) {
+        QString expr = exprEdits[0]->text();
+        PixelOp* pixelOp = PixelOp::fromString(pixOperatorBoxes[0]->currentText(), expr);
+        ImageOp* imageOp = ImageOp::fromString(imgOperatorBoxes[0]->currentText());
+        const Image* imageImg = imgList.find(imageBoxes[0]->currentText().toStdString())->second;
+        maxWidth = min(maxWidth, imageImg->getWidth());
+        maxHeight = min(maxHeight, imageImg->getHeight());
+        
+        for(int i=0; i<nChannel; ++i) {
+            pixelOps[i] = pixelOp;
+            imageOps[i] = imageOp;
+            imageImgs[i] = imageImg;
+        }
+    }
+    else {
+        for(int i=0; i<nChannel; ++i) {
+            QString expr = exprEdits[i+1]->text();
+            pixelOps[i] = PixelOp::fromString(pixOperatorBoxes[i+1]->currentText(), expr);
+            imageOps[i] = ImageOp::fromString(imgOperatorBoxes[i+1]->currentText());
+            imageImgs[i] = imgList.find(imageBoxes[i+1]->currentText().toStdString())->second;
+            maxWidth = min(maxWidth, imageImgs[i]->getWidth());
+            maxHeight = min(maxHeight, imageImgs[i]->getHeight());
+        }
+    }
+
+    Image* resImg;
+    
+    if(valueButton->isChecked()) {
+        resImg = new Image(image->getWidth(), image->getHeight(), nChannel);
+        for(int c = 0; c < nChannel; ++c) {
+            for(unsigned int j = 0; j < image->getHeight(); ++j) {
+                for(unsigned int i = 0; i < image->getWidth(); ++i) {
+                    Image::depth_t value = image->getPixel(i, j, c);
+                    value = pixelOps[c]->operator()(value);
+                    resImg->setPixel(i, j, c, value);
+                }
+            }
+        }
+    }
+    else {
+        resImg = new Image(maxWidth, maxHeight, nChannel);
+        for(int c = 0; c < resImg->getNbChannels(); ++c) {
+            for(unsigned int j = 0; j < resImg->getHeight(); ++j) {
+                for(unsigned int i = 0; i < resImg->getWidth(); ++i) {
+                    Image::depth_t value1 = image->getPixel(i, j, c);
+                    const unsigned int channel = (c < imageImgs[c]->getNbChannels() ? c : 0);
+                    Image::depth_t value2 = imageImgs[c]->getPixel(i, j, channel);
+                    value1 = imageOps[c]->operator()(value1, value2);
+                    resImg->setPixel(i, j, c, value1);
+                }
+            }
+        }
+    }
+    result.push_back(new ImgWidget(resImg, ""));
+        
+    return result;
+}
+
+bool PixelOperation::needCurrentImg() {
+    return true;
+}
diff --git a/app/Operations/PixelOperation.h b/app/Operations/PixelOperation.h
new file mode 100644
index 0000000..6274fb2
--- /dev/null
+++ b/app/Operations/PixelOperation.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ * 
+ * This file is part of EIImage.
+ * 
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <vector>
+#include <map>
+#include <limits>
+#include <QCoreApplication>
+
+#include "Operation.h"
+#include "Image.h"
+
+class QWidget;
+
+class PixelOperation : public Operation {
+
+  public:
+
+    PixelOperation();
+
+    std::vector<QWidget*> operator()(const imagein::Image*, const std::map<std::string, const imagein::Image*>&);
+
+    bool needCurrentImg();
+
+    inline static QString colorName(int i, int n) {
+        if((n==1 || n==2) && i==0) return tr("Black");
+        if((n==2 && i==1) || (n==4 && i==3)) return tr("Alpha");
+        switch(i) { case 0: return tr("Red"); case 1: return tr("Green"); case 2: return tr("Blue"); default: return tr("Color"); }
+    }
+
+
+
+    static inline QString tr(const char* str) { return QCoreApplication::tr(str); }
+
+  private:
+    typedef imagein::Image::depth_t depth_t;
+
+    inline static depth_t normalize(intmax_t value) {
+        intmax_t max = std::numeric_limits<depth_t>::max();
+        intmax_t min = std::numeric_limits<depth_t>::min();
+        value = std::min(max, std::max(min, value));
+        return static_cast<depth_t>(value);
+    }
+
+
+    struct PixelOp {
+        virtual depth_t operator()(depth_t pixel) {
+            return normalize(this->op(pixel));
+        }
+        virtual intmax_t op(depth_t pixel) = 0;
+        static PixelOp* fromString(QString op, QString expr);
+    };
+    
+    struct PixIdent : PixelOp {
+        intmax_t op(depth_t pixel) { return pixel; }
+    };
+
+    template<typename T>
+    struct PixOp_t : public PixelOp {
+        PixOp_t(T value_) : value(value_) {}
+        T value;
+    };
+
+    struct PixAdd : PixOp_t<int> {
+        PixAdd(int value_) : PixOp_t(value_) {}
+        intmax_t op(depth_t pixel) { return pixel + value; }
+    };
+
+    struct PixMul : PixOp_t<double> {
+        PixMul(double value_) : PixOp_t(value_) {}
+        intmax_t op(depth_t pixel) { return pixel * value; }
+    };
+
+    struct PixAnd : PixOp_t<depth_t> {
+        PixAnd(depth_t value_) : PixOp_t(value_) {}
+        intmax_t op(depth_t pixel) { return pixel & value; }
+    };
+
+    struct PixOr : PixOp_t<depth_t> {
+        PixOr(depth_t value_) : PixOp_t(value_) {}
+        intmax_t op(depth_t pixel) { return pixel | value; }
+    };
+
+    struct PixXor : PixOp_t<depth_t> {
+        PixXor(depth_t value_) : PixOp_t(value_) {}
+        intmax_t op(depth_t pixel) { return pixel ^ value; }
+    };
+
+    struct PixLshift : PixOp_t<unsigned int> {
+        PixLshift(unsigned int value_) : PixOp_t(value_) {}
+        intmax_t op(depth_t pixel) { return pixel << value; }
+    };
+    
+    struct PixRshift : PixOp_t<unsigned int> {
+        PixRshift(unsigned int value_) : PixOp_t(value_) {}
+        intmax_t op(depth_t pixel) { return pixel >> value; }
+    };
+
+    struct ImageOp {
+        virtual depth_t operator()(depth_t pixel1, depth_t pixel2) {
+            return normalize(this->op(pixel1, pixel2));
+        }
+        virtual intmax_t op(depth_t pixel1, depth_t pixel2) = 0;
+        static ImageOp* fromString(QString op);
+    };
+    
+    struct ImgIdent : ImageOp {
+        intmax_t op(depth_t pix1, depth_t pix2) { return pix1; } 
+    };
+   
+    struct ImgAdd : ImageOp {
+        intmax_t op(depth_t pix1, depth_t pix2) { return pix1 + pix2; } 
+    };
+    
+    struct ImgSub : ImageOp {
+        intmax_t op(depth_t pix1, depth_t pix2) { return pix1 - pix2; } 
+    };
+    
+    struct ImgAnd : ImageOp {
+        intmax_t op(depth_t pix1, depth_t pix2) { return pix1 & pix2; } 
+    };
+    
+    struct ImgOr : ImageOp {
+        intmax_t op(depth_t pix1, depth_t pix2) { return pix1 | pix2; } 
+    };
+    
+    struct ImgXor : ImageOp {
+        intmax_t op(depth_t pix1, depth_t pix2) { return pix1 ^ pix2; } 
+    };
+
+
+
+};
-- 
GitLab