diff --git a/app/Operations/PixelOperation.cpp b/app/Operations/PixelOperation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5845ee7783ba6298dde980c7835cf82d2e6ddde --- /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 0000000000000000000000000000000000000000..6274fb2df3baf492c025520bc0eef283a3f77b98 --- /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; } + }; + + + +};