From 18c2d43165fef540b64e4ce936e506b81e72107b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20J=C3=BAnior?= Date: Sun, 25 May 2008 21:18:38 -0300 Subject: [PATCH] Adding everything that was done before I create this repo --- LICENSE | 165 +++++++++++++++++++++++++++++++++ README | 3 + about.cpp | 21 +++++ about.h | 33 +++++++ about.ui | 81 ++++++++++++++++ basicfilter.cpp | 32 +++++++ basicfilter.h | 35 +++++++ butterworth.cpp | 72 +++++++++++++++ butterworth.h | 37 ++++++++ camaleon.jpeg | Bin 0 -> 22925 bytes complex.cpp | 115 +++++++++++++++++++++++ complex.h | 52 +++++++++++ fft.cpp | 130 ++++++++++++++++++++++++++ fft.h | 39 ++++++++ help.cpp | 21 +++++ help.h | 33 +++++++ help.ui | 86 +++++++++++++++++ histogram.cpp | 82 ++++++++++++++++ histogram.h | 44 +++++++++ ideal.ui | 88 ++++++++++++++++++ idealfilter.cpp | 71 ++++++++++++++ idealfilter.h | 22 +++++ idealfilteredimage.cpp | 142 ++++++++++++++++++++++++++++ idealfilteredimage.h | 54 +++++++++++ images.qrc | 22 +++++ imagetabs.cpp | 159 ++++++++++++++++++++++++++++++++ imagetabs.h | 30 ++++++ main.cpp | 34 +++++++ main.ui | 200 ++++++++++++++++++++++++++++++++++++++++ passaalta.cpp | 45 +++++++++ passaalta.h | 33 +++++++ passabaixa.cpp | 45 +++++++++ passabaixa.h | 33 +++++++ pid.pro | 33 +++++++ pidmain.cpp | 199 +++++++++++++++++++++++++++++++++++++++ pidmain.h | 31 +++++++ simplefilter.cpp | 65 +++++++++++++ simplefilter.h | 27 ++++++ simplefilter.ui | 125 +++++++++++++++++++++++++ simplefilteredimage.cpp | 81 ++++++++++++++++ simplefilteredimage.h | 30 ++++++ 41 files changed, 2650 insertions(+) create mode 100644 LICENSE create mode 100644 README create mode 100644 about.cpp create mode 100644 about.h create mode 100644 about.ui create mode 100644 basicfilter.cpp create mode 100644 basicfilter.h create mode 100644 butterworth.cpp create mode 100644 butterworth.h create mode 100644 camaleon.jpeg create mode 100644 complex.cpp create mode 100644 complex.h create mode 100755 fft.cpp create mode 100755 fft.h create mode 100644 help.cpp create mode 100644 help.h create mode 100644 help.ui create mode 100644 histogram.cpp create mode 100644 histogram.h create mode 100644 ideal.ui create mode 100644 idealfilter.cpp create mode 100644 idealfilter.h create mode 100644 idealfilteredimage.cpp create mode 100644 idealfilteredimage.h create mode 100644 images.qrc create mode 100644 imagetabs.cpp create mode 100644 imagetabs.h create mode 100644 main.cpp create mode 100644 main.ui create mode 100644 passaalta.cpp create mode 100644 passaalta.h create mode 100644 passabaixa.cpp create mode 100644 passabaixa.h create mode 100644 pid.pro create mode 100644 pidmain.cpp create mode 100644 pidmain.h create mode 100644 simplefilter.cpp create mode 100644 simplefilter.h create mode 100644 simplefilter.ui create mode 100644 simplefilteredimage.cpp create mode 100644 simplefilteredimage.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fc8a5de --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README b/README new file mode 100644 index 0000000..a35f090 --- /dev/null +++ b/README @@ -0,0 +1,3 @@ +Carlos Henrique Júnior +Gregory Pereira Barbosa +Lucas Lanna diff --git a/about.cpp b/about.cpp new file mode 100644 index 0000000..359e354 --- /dev/null +++ b/about.cpp @@ -0,0 +1,21 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "about.h" + +About::About(PidMain *parent) : QDialog(parent) +{ setupUi(this); } diff --git a/about.h b/about.h new file mode 100644 index 0000000..3026d8e --- /dev/null +++ b/about.h @@ -0,0 +1,33 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#ifndef ABOUT_H +#define ABOUT_H + +#include +#include "ui_about.h" +#include "pidmain.h" + +class About : public QDialog, public Ui::AboutDialog +{ + Q_OBJECT + +public: + About(PidMain*); +}; + +#endif diff --git a/about.ui b/about.ui new file mode 100644 index 0000000..c6a4882 --- /dev/null +++ b/about.ui @@ -0,0 +1,81 @@ + + + + AboutDialog + + + Qt::ApplicationModal + + + + 0 + 0 + 429 + 401 + + + + + 0 + 0 + + + + About us + + + true + + + + + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Trebuchet MS'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;">Produzido e mantido por:</p> +<ul style="-qt-list-indent: 1;"><li style=" font-family:'Sans Serif'; font-size:9pt;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline; color:#0000ff;">Carlos Henrique Júnior</span></li> +<li style=" font-family:'Sans Serif'; font-size:9pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline; color:#0000ff;">Gregory Pereira Barbosa</span></li> +<li style=" font-family:'Sans Serif'; font-size:9pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline; color:#0000ff;">Lucas Lanna</span></li></ul></body></html> + + + + + + + + + + :/images/camaleon.jpeg + + + false + + + + + + + + + + + + diff --git a/basicfilter.cpp b/basicfilter.cpp new file mode 100644 index 0000000..9688abd --- /dev/null +++ b/basicfilter.cpp @@ -0,0 +1,32 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "basicfilter.h" +#include + +bool BasicFilter::H(int u, int v, int r, int x0, int y0, bool a) +{ + double hypo = hypot(u - x0, v - y0); + + if (a) + return hypo <= r; + else + return hypo > r; +} + +BasicFilter::~BasicFilter() +{ } diff --git a/basicfilter.h b/basicfilter.h new file mode 100644 index 0000000..10bde1b --- /dev/null +++ b/basicfilter.h @@ -0,0 +1,35 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#ifndef BASICFILTER_H +#define BASICFILTER_H + +#include +#include "complex.h" +#include "simplefilteredimage.h" + +class BasicFilter +{ +public: + virtual QImage* run(Complex*, int, SimpleFilteredImage*)=0; + virtual char* desc()=0; + virtual ~BasicFilter(); +protected: + bool H(int, int, int, int, int, bool); +}; + +#endif diff --git a/butterworth.cpp b/butterworth.cpp new file mode 100644 index 0000000..d457df4 --- /dev/null +++ b/butterworth.cpp @@ -0,0 +1,72 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "butterworth.h" +#include "fft.h" +#include +#include + +Butterworth::Butterworth(bool low) +{ + this->low = low; // low is true +} + +char* Butterworth::desc() +{ + /*char *d; + sprintf(d, "Butterworth (passa %s)", low ? "baixa" : "alta");*/ + return "Butterworth"; +} + +QImage* Butterworth::run(Complex* dft, int value, SimpleFilteredImage* img) +{ + int width = img->spectrum()->width(); + int height = img->spectrum()->height(); + int i, j, pos, size = width * height; + double h; + int n = QInputDialog::getInteger(img, "Butterworth filter", "n="); + + dft = Fourier::cp(dft, size); + + for (i = 0; i < width; i++) + for (j = 0; j < height; j++) + { + h = H(i, j, value, img->x0(), img->y0(), low, n); + pos = (i * height) + j; + dft[pos].setIm(dft[pos].im() * h); + dft[pos].setRe(dft[pos].re() * h); + } + + Complex* inv = Fourier::inverse(dft, size); + QImage *im = Fourier::toImage(inv, width, height); + delete[] dft; + delete[] inv; + + return im; +} + +Butterworth::~Butterworth() +{ } + +double Butterworth::H(int u, int v, int r, int x0, int y0, bool a, int n) +{ + double t = !a ? hypot(u - x0, v - y0) / r : r / hypot(u - x0, v - y0); + double hypo = 1 / (1 + (sqrt(2) - 1) * pow(t, 2*n) ); + + return hypo; +} + diff --git a/butterworth.h b/butterworth.h new file mode 100644 index 0000000..166417f --- /dev/null +++ b/butterworth.h @@ -0,0 +1,37 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#ifndef BUTTERWORTH_H +#define BUTTERWORTH_H + +#include "basicfilter.h" +#include "complex.h" +#include + +class Butterworth : public BasicFilter +{ + bool low; +public: + Butterworth(bool); + QImage* run(Complex*, int, SimpleFilteredImage*); + char* desc(); + ~Butterworth(); +protected: + double H(int u, int v, int r, int x0, int y0, bool a, int n); +}; + +#endif diff --git a/camaleon.jpeg b/camaleon.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..b3a6977611e7643a63aafa30d547beb0b7ab0257 GIT binary patch literal 22925 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 Sa{p_KqW=`&_`kgOclIAY<96Tx literal 0 HcmV?d00001 diff --git a/complex.cpp b/complex.cpp new file mode 100644 index 0000000..f85870c --- /dev/null +++ b/complex.cpp @@ -0,0 +1,115 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include +#include +#include "complex.h" + +Complex::Complex(double real, double imag) +{ + _re = real; + _im = imag; +} + +Complex::Complex(Complex *c) +{ + _re = c->re(); + _im = c->im(); +} + +double Complex::abso() +{ + return log(hypot(_re, _im)); +} +double Complex::phase() +{ + return atan2(_im, _re); +} + +double Complex::magnitude() +{ + return abs(_re + _im); +} + +Complex Complex::plus(Complex b) +{ + double real = _re + b.re(); + double imag = _im + b.im(); + return Complex(real, imag); +} + +Complex Complex::minus(Complex b) { + double real = _re - b.re(); + double imag = _im - b.im(); + return Complex(real, imag); +} + +Complex Complex::times(Complex b) +{ + double real = _re * b.re() - _im * b.im(); + double imag = _re * b.im() + _im * b.re(); + return Complex(real, imag); +} + +Complex Complex::times(double alpha) +{ + return Complex(alpha * _re, alpha * _im); +} + +Complex Complex::conjugate() +{ + return Complex(_re, -1 * _im); +} + +Complex Complex::reciprocal() +{ + double scale = _re * _re + _im * _im; + return Complex(_re / scale, -1 * _im / scale); +} + +Complex Complex::divides(Complex b) +{ + return times(b.reciprocal()); +} + +Complex Complex::expo() +{ + return Complex(exp(_re) * cos(_im), exp(_re) * sin(_im)); +} + +Complex Complex::sino() +{ + return Complex(sin(_re) * cosh(_im), cos(_re) * sinh(_im)); +} + +Complex Complex::coso() +{ + return Complex(cos(_re) * cosh(_im), -1 * sin(_re) * sinh(_im)); +} + +Complex Complex::tan() +{ + return sino().divides(coso()); +} + +Complex Complex::plus(Complex a, Complex b) +{ + double real = a.re() + b.re(); + double imag = a.im() + b.im(); + return Complex(real, imag); +} + diff --git a/complex.h b/complex.h new file mode 100644 index 0000000..e277e72 --- /dev/null +++ b/complex.h @@ -0,0 +1,52 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#ifndef COMPLEX_H +#define COMPLEX_H + +class Complex +{ + double _re; + double _im; +public: + Complex(double real=0.0, double imag=0.0); + Complex(Complex*); + double abso(); + double phase(); + double magnitude(); + Complex plus(Complex); + Complex minus(Complex); + Complex times(Complex); + Complex times(double alpha); + Complex conjugate(); + Complex reciprocal(); + double re() { return _re; } + double im() { return _im; } + void setRe(double re) { _re = re; } + void setIm(double im) { _im = im; } + void set(double re, double im) { _re = re; _im = im; } + void set(Complex &c) { _re = c.re(); _im = c.im(); } + Complex divides(Complex); + Complex expo(); + Complex sino(); + Complex coso(); + Complex tan(); + static Complex plus(Complex, Complex); +}; + +#endif + diff --git a/fft.cpp b/fft.cpp new file mode 100755 index 0000000..5f96bd0 --- /dev/null +++ b/fft.cpp @@ -0,0 +1,130 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "fft.h" +#include +#include + +Complex* Fourier::transform(Complex* x, int N) +{ + if (N == 1) + { + Complex* r = new Complex[1]; + r[0].set(x[0]); + return r; + } + if (N % 2 != 0) { throw NotPowerOfTwo(); } + + Complex* even = new Complex[N / 2]; + for (int k = 0; k < N / 2; k++) + even[k].set(x[2 * k]); + Complex* q = transform(even, N / 2); + + Complex* odd = even; + for (int k = 0; k < N / 2; k++) + odd[k].set(x[2 * k + 1]); + Complex* r = transform(odd, N / 2); + + Complex* y = new Complex[N]; + for (int k = 0; k < N / 2; k++) + { + double kth = -2 * k * M_PI / N; + Complex wk(cos(kth), sin(kth)); + y[k] = q[k].plus(wk.times(r[k])); + y[k + N / 2] = q[k].minus(wk.times(r[k])); + } + + delete[] r; + delete[] q; + + return y; +} + +Complex* Fourier::inverse(Complex* x, int N) +{ + Complex* y = new Complex[N]; + + // take conjugate + for (int i = 0; i < N; i++) + y[i] = x[i].conjugate(); + + // compute forward FFT + y = transform(y, N); + + // take conjugate again + for (int i = 0; i < N; i++) + y[i] = y[i].conjugate(); + + + // divide by N + for (int i = 0; i < N; i++) + y[i] = y[i].times(1.0 / N); + + return y; +} + +Complex* Fourier::fromImage(QImage *img, int &x, int &y) +{ + int i, j, k = 0, size; + // TODO: always increase the size to decrease after filters + /*x = (int) pow(2, round(log10(img->width()) / log10(2))); + y = (int) pow(2, round(log10(img->height()) / log10(2)));*/ + x = img->width(); y = img->height(); + size = x * y; + + Complex* result = new Complex[size]; + Complex* res; + double pix; + + for (i = 0; i < x; i++) + for (j = 0; j < y; j++) + { + pix = QColor::fromRgba(img->pixel(i, j)).red() * pow(-1, i + j); + result[k].set(pix, 0.0); + k++; + } + + res = transform(result, size); + delete[] result; + + return res; +} + +QImage* Fourier::toImage(Complex* inv, int width, int height) +{ + QImage *im = new QImage(width, height, QImage::Format_RGB32); + int i, j, bright; + for (i = 0; i < width; i++) + for (j = 0; j < height; j++) + { + bright = (int)round(abs((int)inv[(i * height) + j].re())); + im->setPixel(i, j, qRgb(bright, bright, bright)); + } + + return im; +} + +Complex* Fourier::cp(Complex* dft, int size) +{ + Complex* ndft = new Complex[size]; + + for (int i = 0; i < size; i++) + ndft[i].set(dft[i]); + + return ndft; +} + diff --git a/fft.h b/fft.h new file mode 100755 index 0000000..0cef5c6 --- /dev/null +++ b/fft.h @@ -0,0 +1,39 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#ifndef FFT_H +#define FFT_H + +#include "complex.h" +#include + +namespace Fourier +{ + class NotPowerOfTwo { }; + + Complex* transform(Complex*, int); + Complex* inverse(Complex*, int); + + // Helpers + Complex* cp(Complex*, int); + + // Image helpers + Complex* fromImage(QImage*, int&, int&); + QImage* toImage(Complex*, int, int); +} + +#endif diff --git a/help.cpp b/help.cpp new file mode 100644 index 0000000..b3c5d92 --- /dev/null +++ b/help.cpp @@ -0,0 +1,21 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "help.h" + +Help::Help(PidMain *parent) : QDialog(parent) +{ setupUi(this); } diff --git a/help.h b/help.h new file mode 100644 index 0000000..8674ad4 --- /dev/null +++ b/help.h @@ -0,0 +1,33 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#ifndef HELP_H +#define HELP_H + +#include +#include "ui_help.h" +#include "pidmain.h" + +class Help : public QDialog, public Ui::HelpDialog +{ + Q_OBJECT + +public: + Help(PidMain*); +}; + +#endif diff --git a/help.ui b/help.ui new file mode 100644 index 0000000..26e6735 --- /dev/null +++ b/help.ui @@ -0,0 +1,86 @@ + + + + HelpDialog + + + + 0 + 0 + 600 + 600 + + + + + 0 + 0 + + + + + 600 + 600 + + + + + 600 + 600 + + + + Image Editor Help + + + + + + true + + + <html><head><meta name="qrichtext" content="1" /><title>Image Editor Help</title><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:x-large; font-weight:600;"><span style=" font-size:x-large;">Abrindo uma imagem</span></p> +<ul style="-qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small; font-weight:600;">Ctrl+O ou File/Open</span></li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small;">Abre uma imagem que será tratada pelo programa de varias maneiras, dependendo da opção escolhida pelo usuário.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:x-large; font-weight:600;"><span style=" font-size:x-large;">Salvar imagem atual</span></p> +<ul style="-qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small; font-weight:600; color:#000000;">Ctrl+Shift+S ou File/Save</span></li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small;">Salva a imagem atual e suas alterações que foram realizadas até este momento em um diretório a ser escolhido.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small;">Com este recurso você pode salvar a imagem original, sua versão em escala de cinza ou ainda o espectro de fourier</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:x-large; font-weight:600;"><span style=" font-size:x-large;">Gerar escala de cinza</span></p> +<ul style="-qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small; font-weight:600;">Ctrl+G ou Image/Generate Gray Scale</span> </li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small; color:#000000;">Gera uma versão na escala de cinza da imagem, partindo do pressuposto que está é colorida. Uma função é utilizada para alterar os valores RGB(red, green, blue) de cada pixel da imagem para transformá-lo em um pixel de tom cinza.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:x-large; font-weight:600;"><span style=" font-size:x-large;">Gerar Histograma</span></p> +<ul style="-qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small; font-weight:600; color:#000000;">Ctrl+H ou Image/Generate Histogram</span></li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small;">Gera o histograma da imagem após ser transformada na versão em escala de cinza, feito com base na distribuição de freqüências de tons de cinza presentes na imagem, normalmente um gráfico de barras verticais.</span></p> +<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:x-large; font-weight:600;"><span style=" font-size:x-large;">Espectro de Fourier</span></p> +<ul style="-qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small; font-weight:600; color:#000000;">Ctrl+F ou Image/Generate Fourier Spectrum</span></li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:small;">Gera o espectro de Fourier da imagem atual utilizando uma função que aplica a transformada de Fourier em uma imagem de duas dimensões. O espectro de Fourier é o gráfico da magnitude versus freqüência, aonde a freqüência corresponde a freqüência na forma de senos e cosenos.</span></p></body></html> + + + + + + + + diff --git a/histogram.cpp b/histogram.cpp new file mode 100644 index 0000000..809e96e --- /dev/null +++ b/histogram.cpp @@ -0,0 +1,82 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include +#include +#include +#include "histogram.h" + +Histogram::Histogram(int idx[256]) : QPixmap(HISTOGRAM_WIDTH, HISTOGRAM_HEIGHT) +{ + perClass = 256 / _HISTOGRAM_CLASSES; + + for (int i = 0; i < _HISTOGRAM_CLASSES; i++) + { + int val = 0; + for (int j = i * perClass; j < (i+1) * perClass - 1; j++) + val = val + idx[j]; + indexes[i] = val; + } + + generate(); +} + +void Histogram::generate() +{ + fill(); + QPainter painter(this); + int max = indexes[0]; + for (int i = 0; i < _HISTOGRAM_CLASSES; i++) + if (indexes[i] > max) + max = indexes[i]; + + max = max + (100 - max % 100); + + paintGraphBase(&painter, max); + + for (int i = 0; i < _HISTOGRAM_CLASSES; i++) + paintBar(&painter, max, i); +} + +void Histogram::paintGraphBase(QPainter *painter, int max) +{ + int interval = max / 10; + int posInterval = ZERO_POINT / 10; + for (int i = 0; i <= 10; i++) + { + int val = max - i * interval; + int pos = posInterval * i + TOP_SPACE; + painter->drawText(0, pos - 5, QString::number(val)); + painter->drawLine(0, pos, (BAR_WIDTH + BAR_SPACE) * _HISTOGRAM_CLASSES + SIDE_SPACE, pos); + } +} + +void Histogram::paintBar(QPainter *painter, int max, int i) +{ + int size = qRound(indexes[i] * (ZERO_POINT - TOP_SPACE) / max) + 1; + + QLinearGradient color; + int starting_color = i * perClass; + int ending_color = (i + 1) * perClass - 1; + color.setColorAt(0, QColor(starting_color, starting_color, starting_color)); + color.setColorAt(1, QColor(ending_color, ending_color, ending_color)); + painter->setBrush(color); + painter->drawRect(i * (BAR_WIDTH + BAR_SPACE) + SIDE_SPACE, ZERO_POINT - size + TOP_SPACE, BAR_WIDTH, size); + painter->drawText(i * (BAR_WIDTH + BAR_SPACE) + SIDE_SPACE, ZERO_POINT + 12 + TOP_SPACE, QString::number(i)); + + painter->drawText(_HISTOGRAM_CLASSES * (BAR_WIDTH + BAR_SPACE) + SIDE_SPACE + 10, i * 13 + 20, QString::number(i) + " = " + QString::number(starting_color) + " - " + QString::number(ending_color)); +} diff --git a/histogram.h b/histogram.h new file mode 100644 index 0000000..1394a72 --- /dev/null +++ b/histogram.h @@ -0,0 +1,44 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#ifndef HISTOGRAM_H +#define HISTOGRAM_H + +#include +#include +#define _HISTOGRAM_CLASSES 32 +#define BAR_WIDTH 15 +#define BAR_SPACE 3 +#define ZERO_POINT 400 +#define TOP_SPACE 20 +#define SIDE_SPACE 40 +#define HISTOGRAM_WIDTH (SIDE_SPACE + ((BAR_WIDTH + BAR_SPACE) * _HISTOGRAM_CLASSES)) +#define HISTOGRAM_HEIGHT (HISTOGRAM_WIDTH, ZERO_POINT + TOP_SPACE + 20) + +class Histogram : public QPixmap +{ + int indexes[_HISTOGRAM_CLASSES]; + int perClass; +public: + Histogram(int[255]); + void generate(); +private: + void paintGraphBase(QPainter*, int); + void paintBar(QPainter*, int, int); +}; + +#endif diff --git a/ideal.ui b/ideal.ui new file mode 100644 index 0000000..0184fff --- /dev/null +++ b/ideal.ui @@ -0,0 +1,88 @@ + + + + IdealFilterDialog + + + + 0 + 0 + 511 + 433 + + + + Ideal Filter + + + + + + + + 14 + 14 + 503 + 389 + + + + + + + + + + + + + + Show guide lines + + + true + + + + + + + Apply + + + + + + + + + + IdealFilteredImage + QLabel +
idealfilteredimage.h
+
+ + QScrollArea + QWidget +
QScrollArea
+ 1 +
+
+ + +
diff --git a/idealfilter.cpp b/idealfilter.cpp new file mode 100644 index 0000000..5545fd9 --- /dev/null +++ b/idealfilter.cpp @@ -0,0 +1,71 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "idealfilter.h" +#include "complex.h" +#include "fft.h" +#include +#include + +IdealFilter::IdealFilter(PidMain *parent, ImageTabs* imgs) : QDialog(parent), +images(imgs) +{ + setupUi(this); + scrollArea->setWidget(imageLabel); + imageLabel->setSpectrum(image()); + + connect(applyButton, SIGNAL( clicked() ), this, SLOT( applyFilter() )); + connect(showGuideLines, SIGNAL( toggled(bool) ), this, SLOT( toggleShowGuideLines(bool) )); +} + +void IdealFilter::applyFilter() +{ + int width = image()->width(); + int height = image()->height(); + int i, j, k, size = width * height; + + Complex* dft = Fourier::cp(images->getDFT(), size); + + for (i = 0; i < width; i++) + for (j = 0; j < height; j++) + for (k = 0; k < imageLabel->selections().size(); k++) + if (imageLabel->selections().at(k).contains(i, j)) + { + dft[(i * height) + j].set(0.0, 0.0); + break; + } + + Complex* inv = Fourier::inverse(dft, size); + QImage *im = Fourier::toImage(inv, width, height); + delete[] dft; + delete[] inv; + + images->addImage("Special Filter", im); + close(); +} + +QImage* IdealFilter::image() +{ + return images->getSpectrum(); +} + +void IdealFilter::toggleShowGuideLines(bool a) +{ + imageLabel->setShowGuideLines(a); + imageLabel->update(); +} + diff --git a/idealfilter.h b/idealfilter.h new file mode 100644 index 0000000..6e8c9ae --- /dev/null +++ b/idealfilter.h @@ -0,0 +1,22 @@ +#ifndef IDEALFILTER_H +#define IDEALFILTER_H + +#include +#include "ui_ideal.h" +#include "pidmain.h" +#include "imagetabs.h" + +class IdealFilter : public QDialog, public Ui::IdealFilterDialog +{ + Q_OBJECT + ImageTabs* images; +public: + IdealFilter(PidMain*, ImageTabs*); +public slots: + void applyFilter(); + void toggleShowGuideLines(bool); +private: + QImage* image(); +}; + +#endif diff --git a/idealfilteredimage.cpp b/idealfilteredimage.cpp new file mode 100644 index 0000000..9a1b300 --- /dev/null +++ b/idealfilteredimage.cpp @@ -0,0 +1,142 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "idealfilteredimage.h" +#include +#include + +IdealFilteredImage::IdealFilteredImage(QWidget *parent) : QLabel(parent) +{ + rubberBand = NULL; + showGuideLines = true; +} + +void IdealFilteredImage::mousePressEvent(QMouseEvent *event) +{ + selOrigin = event->pos(); + if (!rubberBand) + rubberBand = new QRubberBand(QRubberBand::Rectangle, this); + rubberBand->setGeometry(QRect(selOrigin, QSize())); + rubberBand->show(); +} + +void IdealFilteredImage::mouseMoveEvent(QMouseEvent *event) +{ + rubberBand->setGeometry(QRect(selOrigin, event->pos()).normalized()); +} + +void IdealFilteredImage::mouseReleaseEvent(QMouseEvent *event) +{ + rubberBand->hide(); + selDest = event->pos(); + int deltaX = selOrigin.x() - selDest.x(); + int deltaY = selOrigin.y() - selDest.y(); + + if (!(deltaX < 0 && deltaY < 0)) + { + if (deltaX > 0 && deltaY > 0) + { + // \< + QPoint tmp = selDest; + selDest = selOrigin; + selOrigin = tmp; + } + else if (deltaX < 0 && deltaY > 0) + { + // /> + int tmp = selOrigin.y(); + selOrigin.setY(selDest.y()); + selDest.setY(tmp); + } + else if (deltaX > 0 && deltaY < 0) + { + // /< + int tmp = selOrigin.x(); + selOrigin.setX(selDest.x()); + selDest.setX(tmp); + } + } + + _selections << QRect(selOrigin, selDest); + + // reflex + int width = abs(deltaX); + int height = abs(deltaY); + int rx = _x0 + _x0 - selOrigin.x() - width; + int ry = _y0 + _y0 - selOrigin.y() - height; + _selections << QRect(QPoint(rx, ry), QPoint(rx + width, ry + height)); + + update(); + // determine selection, for example using QRect::intersects() + // and QRect::contains(). +} + +void +IdealFilteredImage::setSpectrum(QImage* s) +{ + spec = s; + setPixmap(QPixmap::fromImage(*spec)); + _x0 = (int) round(spec->width() / 2.f); + _y0 = (int) round(spec->height() / 2.f); + setFixedHeight(spec->height()); + setFixedWidth(spec->width()); +} + +int IdealFilteredImage::y0() +{ + return _y0; +} + +int IdealFilteredImage::x0() +{ + return _x0; +} + +void IdealFilteredImage::paintEvent(QPaintEvent* ev) +{ + QLabel::paintEvent(ev); + QPainter painter(this); + + painter.setPen(Qt::black); + painter.setBrush(Qt::black); + + for (int i = 0; i < _selections.size(); i++) + painter.drawRect(_selections[i]); + + if (showGuideLines) + { + painter.setPen(Qt::red); + painter.drawLine(0, _y0, spectrum()->width() - 1, _y0); + painter.drawLine(_x0, 0, _x0, spectrum()->height() - 1); + } +} + +void IdealFilteredImage::setShowGuideLines(bool a) +{ + showGuideLines = a; +} + +QImage* IdealFilteredImage::spectrum() +{ + return spec; +} + +QList IdealFilteredImage::selections() +{ + return _selections; +} + diff --git a/idealfilteredimage.h b/idealfilteredimage.h new file mode 100644 index 0000000..f62a480 --- /dev/null +++ b/idealfilteredimage.h @@ -0,0 +1,54 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#ifndef IDEAL_FILTERED_IMAGE_H +#define IDEAL_FILTERED_IMAGE_H + +#include +#include +#include +#include +#include +#include + +class IdealFilteredImage : public QLabel +{ + Q_OBJECT + QImage *spec; + int _x0, _y0; // image center + QList _selections; + bool showGuideLines; + + // current selection + QRubberBand *rubberBand; + QPoint selOrigin, selDest; +public: + IdealFilteredImage(QWidget*); + void setSpectrum(QImage*); + QImage* spectrum(); + int y0(); + int x0(); + void paintEvent(QPaintEvent*); + void setShowGuideLines(bool); + QList selections(); +protected: + void mousePressEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); +}; + +#endif diff --git a/images.qrc b/images.qrc new file mode 100644 index 0000000..b93e02b --- /dev/null +++ b/images.qrc @@ -0,0 +1,22 @@ + + + + + camaleon.jpeg + + diff --git a/imagetabs.cpp b/imagetabs.cpp new file mode 100644 index 0000000..b58bfc0 --- /dev/null +++ b/imagetabs.cpp @@ -0,0 +1,159 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "imagetabs.h" +#include "histogram.h" +#include "fft.h" +#include +#include +#include +#include + +ImageTabs::ImageTabs(QWidget *parent, QString imageLocation) : QTabWidget(parent) +{ + original = new QImage(imageLocation); + bool grayScale = original->isGrayscale(); + gray = (grayScale) ? original : NULL; + dft = NULL; + spectrum = NULL; + + addImage("Original" + QString((grayScale) ? " (Grayscale)" : ""), original); +} + +QImage* +ImageTabs::getOriginal() +{ + return original; +} + +QImage* +ImageTabs::getGray() +{ + generateGrayScale(); + return gray; +} + +QImage* +ImageTabs::getSpectrum() +{ + if (dft == NULL) + dft = Fourier::fromImage(getGray(), spectX, spectY); + if (spectrum == NULL) + { + spectrum = new QImage(spectX, spectY, QImage::Format_RGB32); + int bright; + int pos; + + for (int i = 0; i < spectX; i++) + for (int j = 0; j < spectY; j++) + { + pos = (i * spectY) + j; + bright = (int) dft[pos].abso(); + spectrum->setPixel(i, j, qRgb(bright, bright, bright)); + } + } + + return spectrum; +} + +QImage +ImageTabs::getCurrent() +{ + QScrollArea *scroll = (QScrollArea*)currentWidget(); + return ((QLabel*)scroll->widget())->pixmap()->toImage(); +} + +void +ImageTabs::generateGrayScale() +{ + if (gray == NULL) + { + gray = new QImage(*original); + QRgb grayPix; + int bright; + + for (int i = 0; i < gray->width(); i++) + for (int j = 0; j < gray->height(); j++) + { + QColor curPix = QColor::fromRgba(gray->pixel(i, j)); + bright = qRound(0.3 * curPix.red() + 0.5 * curPix.green() + 0.2 * curPix.blue()); + grayPix = qRgb(bright, bright, bright); + gray->setPixel(i, j, grayPix); + } + + addImage("Gray Scale", gray); + } +} + +void +ImageTabs::generateHistogram() +{ + generateGrayScale(); + + int indexes[256]; + for (int i = 0; i < 256; i++) + indexes[i] = 0; + + for (int i = 0; i < gray->width(); i++) + for (int j = 0; j < gray->height(); j++) + { + QColor curPix = QColor::fromRgba(gray->pixel(i, j)); + indexes[curPix.red()]++; + } + + QLabel *hView = new QLabel(this); + hView->setPixmap(Histogram(indexes)); + + QScrollArea *scroll = new QScrollArea; + scroll->setWidget(hView); + + addTab(scroll, "Histogram"); + setCurrentWidget(scroll); +} + +void +ImageTabs::addImage(QString label, QImage *img) +{ + QLabel *view = new QLabel(this); + view->setPixmap(QPixmap::fromImage(*img)); + + QScrollArea *scroll = new QScrollArea; + scroll->setWidget(view); + + addTab(scroll, label); + setCurrentWidget(scroll); +} + +Complex* +ImageTabs::getDFT() +{ + return dft; +} + +ImageTabs::~ImageTabs() +{ + if (dft != NULL) + delete[] dft; + + if (gray != original) + delete gray; + delete original; + + if (spectrum != NULL) + delete spectrum; +} + diff --git a/imagetabs.h b/imagetabs.h new file mode 100644 index 0000000..8268ebb --- /dev/null +++ b/imagetabs.h @@ -0,0 +1,30 @@ +#ifndef IMAGETABS_H +#define IMAGETABS_H + +#include +#include +#include +#include "complex.h" + +class ImageTabs : public QTabWidget +{ + Q_OBJECT + + QImage *original, *gray, *spectrum; + int spectX, spectY; + Complex* dft; + +public: + ImageTabs(QWidget *parent, QString imageLocation); + QImage* getOriginal(); + QImage* getGray(); + QImage* getSpectrum(); + Complex* getDFT(); + QImage getCurrent(); + void generateGrayScale(); + void generateHistogram(); + void addImage(QString, QImage*); + ~ImageTabs(); +}; + +#endif diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..165437c --- /dev/null +++ b/main.cpp @@ -0,0 +1,34 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include +#include +#include +#include "pidmain.h" +#include "complex.h" +#include "fft.h" + +int +main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + PidMain *dialog = new PidMain; + + dialog->show(); + return app.exec(); +} + diff --git a/main.ui b/main.ui new file mode 100644 index 0000000..27cf852 --- /dev/null +++ b/main.ui @@ -0,0 +1,200 @@ + + + + PIDMainWindow + + + + 0 + 0 + 800 + 600 + + + + Blind Camaleon v1.0a + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + 0 + 0 + 800 + 29 + + + + + &File + + + + + + + &Image + + + + + + + &Help + + + + + + + + Filters + + + + Butterworth + + + + + + + + + + + + + + + + + + &Open Image + + + Ctrl+O + + + + + true + + + Generate &Gray Scale + + + Ctrl+G + + + + + &Save Current As... + + + Ctrl+Shift+S + + + + + &Help + + + F1 + + + + + &About Blind Camaleon + + + + + Generate &Histogram + + + Ctrl+H + + + + + Generate &Fourier Spectrum + + + Ctrl+F + + + + + Passa alta + + + Ctrl+P, A + + + + + Passa baixa + + + Ctrl+P, B + + + + + Ideal + + + Ctrl+I + + + + + Passa alta + + + + + Passa baixa + + + + + + QMdiArea + QFrame +
QMdiArea
+ 1 +
+
+ + +
diff --git a/passaalta.cpp b/passaalta.cpp new file mode 100644 index 0000000..45ec3b2 --- /dev/null +++ b/passaalta.cpp @@ -0,0 +1,45 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "passaalta.h" +#include "fft.h" +#include + +QImage* PassaAlta::run(Complex* dft, int value, SimpleFilteredImage* img) +{ + int width = img->spectrum()->width(); + int height = img->spectrum()->height(); + int i, j, size = width * height; + + dft = Fourier::cp(dft, size); + + for (i = 0; i < width; i++) + for (j = 0; j < height; j++) + if (H(i, j, value, img->x0(), img->y0(), true)) + dft[(i * height) + j].set(0.0, 0.0); + + Complex* inv = Fourier::inverse(dft, size); + QImage *im = Fourier::toImage(inv, width, height); + delete[] dft; + delete[] inv; + + return im; +} + +PassaAlta::~PassaAlta() +{ } + diff --git a/passaalta.h b/passaalta.h new file mode 100644 index 0000000..1f698d4 --- /dev/null +++ b/passaalta.h @@ -0,0 +1,33 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#ifndef PASSAALTA_H +#define PASSAALTA_H + +#include "basicfilter.h" +#include "complex.h" +#include + +class PassaAlta : public BasicFilter +{ +public: + QImage* run(Complex*, int, SimpleFilteredImage*); + char* desc() { return "Passa alta"; } + ~PassaAlta(); +}; + +#endif diff --git a/passabaixa.cpp b/passabaixa.cpp new file mode 100644 index 0000000..067aeea --- /dev/null +++ b/passabaixa.cpp @@ -0,0 +1,45 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "passabaixa.h" +#include "fft.h" +#include + +QImage* PassaBaixa::run(Complex* dft, int value, SimpleFilteredImage* img) +{ + int width = img->spectrum()->width(); + int height = img->spectrum()->height(); + int i, j, size = width * height; + + dft = Fourier::cp(dft, size); + + for (i = 0; i < width; i++) + for (j = 0; j < height; j++) + if (H(i, j, value, img->x0(), img->y0(), false)) + dft[(i * height) + j].set(0.0, 0.0); + + Complex* inv = Fourier::inverse(dft, size); + QImage *im = Fourier::toImage(inv, width, height); + delete[] dft; + delete[] inv; + + return im; +} + +PassaBaixa::~PassaBaixa() +{ } + diff --git a/passabaixa.h b/passabaixa.h new file mode 100644 index 0000000..21b1b26 --- /dev/null +++ b/passabaixa.h @@ -0,0 +1,33 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#ifndef PASSABAIXA_H +#define PASSABAIXA_H + +#include "basicfilter.h" +#include "complex.h" +#include + +class PassaBaixa : public BasicFilter +{ +public: + QImage* run(Complex*, int, SimpleFilteredImage*); + char* desc() { return "Passa baixa"; } + ~PassaBaixa(); +}; + +#endif diff --git a/pid.pro b/pid.pro new file mode 100644 index 0000000..21d51da --- /dev/null +++ b/pid.pro @@ -0,0 +1,33 @@ +########### +## This file is part of Blind Camaleon. +## +## Blind Camaleon is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## Blind Camaleon 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with Blind Camaleon. If not, see . +########### + + +# files +HEADERS = pidmain.h about.h help.h histogram.h imagetabs.h complex.h simplefilter.h simplefilteredimage.h fft.h basicfilter.h passaalta.h passabaixa.h idealfilter.h idealfilteredimage.h butterworth.h +SOURCES = pidmain.cpp about.cpp help.cpp main.cpp histogram.cpp imagetabs.cpp complex.cpp simplefilter.cpp simplefilteredimage.cpp fft.cpp passabaixa.cpp passaalta.cpp basicfilter.cpp idealfilter.cpp idealfilteredimage.cpp butterworth.cpp +FORMS = main.ui about.ui help.ui simplefilter.ui ideal.ui +RESOURCES = images.qrc + +# configurations +TEMPLATE = app +CONFIG += release + +# install +target.path = pidmain +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS##.pro +sources.path = . +INSTALLS += target sources diff --git a/pidmain.cpp b/pidmain.cpp new file mode 100644 index 0000000..9d5136f --- /dev/null +++ b/pidmain.cpp @@ -0,0 +1,199 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include +#include +#include +#include "pidmain.h" +#include "about.h" +#include "help.h" +#include "imagetabs.h" +#include "simplefilter.h" +#include "idealfilter.h" +#include "butterworth.h" +#include "passaalta.h" +#include "passabaixa.h" + +PidMain::PidMain(QWidget *parent) : QMainWindow(parent) +{ + setupUi(this); + + // Connect signals + // File + connect(menuOpenImage, SIGNAL( triggered() ), this, SLOT( openImage() )); + connect(menuSaveCurrent, SIGNAL( triggered() ), this, SLOT( saveCurrentAs() )); + + // Image + connect(menuGenerateGrayScale, SIGNAL( triggered() ), this, SLOT( generateGrayScale() )); + connect(menuGenerateHistogram, SIGNAL( triggered() ), this, SLOT( generateHistogram() )); + + // Help + connect(menuOpenAbout, SIGNAL( triggered() ), this, SLOT( openAboutDialog() )); + connect(menuOpenHelp, SIGNAL( triggered() ), this, SLOT( openHelpDialog() )); + + // Filters + connect(menuFiltersAltaIdeal, SIGNAL( triggered() ), this, SLOT( openPassaAltaIdeal() )); + connect(menuFiltersBaixaIdeal, SIGNAL( triggered() ), this, SLOT( openPassaBaixaIdeal() )); + connect(menuFiltersIdeal, SIGNAL( triggered() ), this, SLOT( openIdeal() )); + connect(menuButterworthBaixa, SIGNAL( triggered() ), this, SLOT( openButterworthBaixa() )); + connect(menuButterworthAlta, SIGNAL( triggered() ), this, SLOT( openButterworthAlta() )); + + // initializing some widgets + mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); +} + +void +PidMain::openImage() +{ + QString path; + + path = QFileDialog::getOpenFileName(this, + "Choose an image file to open", + QString::null, + "*.jpg *.jpeg"); + + if (path != NULL) + { + ImageTabs *img = new ImageTabs(mdiArea, path); + QMdiSubWindow *imgWindow = mdiArea->addSubWindow(img); + imgWindow->setWindowTitle(path); + imgWindow->show(); + } +} + +void +PidMain::openHelpDialog() +{ + Help a(this); + a.exec(); +} + +void +PidMain::openAboutDialog() +{ + About a(this); + a.exec(); +} + +void +PidMain::generateGrayScale() +{ + ImageTabs* current = getCurrentImageWindow(); + + if (current != NULL) + current->generateGrayScale(); +} + +void +PidMain::generateHistogram() +{ + ImageTabs* current = getCurrentImageWindow(); + + if (current != NULL) + current->generateHistogram(); +} + +void +PidMain::saveCurrentAs() +{ + ImageTabs* current = getCurrentImageWindow(); + + if (current != NULL) + { + QString path; + + path = QFileDialog::getSaveFileName(this, + "Choose an image file to open", + QString::null, + "Images (*.jpg *.png)"); + + if (path != NULL) + current->getCurrent().save(path); + } +} + +void +PidMain::openPassaAltaIdeal() +{ + ImageTabs* current = getCurrentImageWindow(); + if (current != NULL) + { + SimpleFilter *filter = new SimpleFilter(this, current, new PassaAlta); + filter->setAttribute(Qt::WA_DeleteOnClose); + filter->exec(); + } +} + +void +PidMain::openPassaBaixaIdeal() +{ + ImageTabs* current = getCurrentImageWindow(); + if (current != NULL) + { + SimpleFilter *filter = new SimpleFilter(this, current, new PassaBaixa); + filter->setAttribute(Qt::WA_DeleteOnClose); + filter->exec(); + } +} + +void +PidMain::openButterworthBaixa() +{ + ImageTabs* current = getCurrentImageWindow(); + if (current != NULL) + { + SimpleFilter *filter = new SimpleFilter(this, current, new Butterworth(false)); + filter->setAttribute(Qt::WA_DeleteOnClose); + filter->exec(); + } +} + +void +PidMain::openButterworthAlta() +{ + ImageTabs* current = getCurrentImageWindow(); + if (current != NULL) + { + SimpleFilter *filter = new SimpleFilter(this, current, new Butterworth(true)); + filter->setAttribute(Qt::WA_DeleteOnClose); + filter->exec(); + } +} + +void +PidMain::openIdeal() +{ + ImageTabs* current = getCurrentImageWindow(); + if (current != NULL) + { + IdealFilter *filter = new IdealFilter(this, current); + //filter->setAttribute(Qt::WA_DeleteOnClose); + filter->exec(); + } +} + +ImageTabs* +PidMain::getCurrentImageWindow() +{ + QMdiSubWindow *activeWindow = mdiArea->activeSubWindow(); + + if (activeWindow == NULL) + return NULL; + else + return (ImageTabs*)activeWindow->widget(); +} diff --git a/pidmain.h b/pidmain.h new file mode 100644 index 0000000..825679c --- /dev/null +++ b/pidmain.h @@ -0,0 +1,31 @@ +#ifndef PID_H +#define PID_H + +#include "imagetabs.h" +#include "ui_main.h" + +class PidMain : public QMainWindow, public Ui::PIDMainWindow +{ + Q_OBJECT + +public: + PidMain(QWidget *parent = 0); + ImageTabs* getCurrentImageWindow(); + +public slots: + void openImage(); + void generateGrayScale(); + void generateHistogram(); + void saveCurrentAs(); + void openAboutDialog(); + void openHelpDialog(); + + // Filters + void openPassaAltaIdeal(); + void openPassaBaixaIdeal(); + void openIdeal(); + void openButterworthAlta(); + void openButterworthBaixa(); +}; + +#endif diff --git a/simplefilter.cpp b/simplefilter.cpp new file mode 100644 index 0000000..7e9a02d --- /dev/null +++ b/simplefilter.cpp @@ -0,0 +1,65 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "simplefilter.h" +#include "simplefilteredimage.h" +#include +#include + +SimpleFilter::SimpleFilter(PidMain *parent, ImageTabs* imgs, BasicFilter* filter) : QDialog(parent), +images(imgs) +{ + setupUi(this); + this->filter = filter; + scrollArea->setWidget(imageLabel); + imageLabel->setSpectrum(image()); + filterPosition->setMaximum((int) round(hypot(imageLabel->x0(), imageLabel->y0()))); + filterPosition->setMinimum(0); + + connect(imageLabel, SIGNAL( imageClicked() ), this, SLOT( setFilterPosition() )); + connect(filterPosition, SIGNAL( valueChanged(int) ), this, SLOT( setFilterPosition(int) )); + connect(applyButton, SIGNAL( clicked() ), this, SLOT( applyFilter() )); +} + +void SimpleFilter::setFilterPosition() +{ + filterPosition->setValue(imageLabel->z()); + imageLabel->update(); +} + +void SimpleFilter::setFilterPosition(int p) +{ + imageLabel->setZ(p); + imageLabel->update(); +} + +void SimpleFilter::applyFilter() +{ + images->addImage(QString().sprintf("%s [%d]", filter->desc(), filterPosition->value()), filter->run(images->getDFT(), filterPosition->value(), imageLabel)); + close(); +} + +QImage* SimpleFilter::image() +{ + return images->getSpectrum(); +} + +SimpleFilter::~SimpleFilter() +{ + delete filter; +} + diff --git a/simplefilter.h b/simplefilter.h new file mode 100644 index 0000000..a14f95b --- /dev/null +++ b/simplefilter.h @@ -0,0 +1,27 @@ +#ifndef SIMPLE_FILTER_H +#define SIMPLE_FILTER_H + +#include +#include "simplefilteredimage.h" +#include "ui_simplefilter.h" +#include "pidmain.h" +#include "imagetabs.h" +#include "basicfilter.h" + +class SimpleFilter : public QDialog, public Ui::SimpleFilterDialog +{ + Q_OBJECT + ImageTabs* images; + BasicFilter* filter; +public: + SimpleFilter(PidMain*, ImageTabs*, BasicFilter*); + ~SimpleFilter(); +public slots: + void setFilterPosition(); + void setFilterPosition(int); + void applyFilter(); +private: + QImage* image(); +}; + +#endif diff --git a/simplefilter.ui b/simplefilter.ui new file mode 100644 index 0000000..6b46559 --- /dev/null +++ b/simplefilter.ui @@ -0,0 +1,125 @@ + + + + SimpleFilterDialog + + + Qt::WindowModal + + + + 0 + 0 + 843 + 477 + + + + Apply Filter + + + + + + + + 14 + 14 + 628 + 91 + + + + + 0 + 0 + + + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + K= + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Apply! + + + + + + + + + + SimpleFilteredImage + QLabel +
simplefilteredimage.h
+
+ + QScrollArea + QWidget +
QScrollArea
+ 1 +
+
+ + +
diff --git a/simplefilteredimage.cpp b/simplefilteredimage.cpp new file mode 100644 index 0000000..7d9b60f --- /dev/null +++ b/simplefilteredimage.cpp @@ -0,0 +1,81 @@ +/* + * This file is part of Blind Camaleon. + * + * Blind Camaleon is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Blind Camaleon 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Blind Camaleon. If not, see . + */ + +#include "simplefilteredimage.h" +#include +#include + +SimpleFilteredImage::SimpleFilteredImage(QDialog*) +{ } + +SimpleFilteredImage::SimpleFilteredImage(QWidget *parent) : QLabel(parent) +{ } + +void +SimpleFilteredImage::mouseReleaseEvent(QMouseEvent *event) +{ + QPoint p = event->pos(); + _z = (int) round(hypot(p.x() - _x0, p.y() - _y0)); + emit imageClicked(); +} + +void +SimpleFilteredImage::setSpectrum(QImage* s) +{ + spec = s; + setPixmap(QPixmap::fromImage(*spec)); + _x0 = (int) round(spec->width() / 2.f); + _y0 = (int) round(spec->height() / 2.f); + setFixedHeight(spec->height()); + setFixedWidth(spec->width()); +} + +void +SimpleFilteredImage::setZ(int z) +{ + _z = z; +} + +int SimpleFilteredImage::y0() +{ + return _y0; +} + +int SimpleFilteredImage::x0() +{ + return _x0; +} + +int SimpleFilteredImage::z() +{ + return _z; +} + +void SimpleFilteredImage::paintEvent(QPaintEvent* ev) +{ + QLabel::paintEvent(ev); + QPainter painter(this); + int d = _z * 2; + painter.setPen(Qt::red); + painter.drawEllipse(_x0 - _z, _y0 - _z, d, d); +} + +QImage* SimpleFilteredImage::spectrum() +{ + return spec; +} + diff --git a/simplefilteredimage.h b/simplefilteredimage.h new file mode 100644 index 0000000..71d63f9 --- /dev/null +++ b/simplefilteredimage.h @@ -0,0 +1,30 @@ +#ifndef SIMPLE_FILTERED_IMAGE_H +#define SIMPLE_FILTERED_IMAGE_H + +#include +#include +#include +#include + +class SimpleFilteredImage : public QLabel +{ + Q_OBJECT + QImage *spec; + int _x0, _y0, _z; +public: + SimpleFilteredImage(QDialog*); + SimpleFilteredImage(QWidget*); + void setSpectrum(QImage*); + QImage* spectrum(); + int y0(); + int x0(); + int z(); + void setZ(int); + void paintEvent(QPaintEvent*); +protected: + void mouseReleaseEvent(QMouseEvent*); +signals: + void imageClicked(); +}; + +#endif