Import from internal git
This commit is contained in:
28
src/main/java/Main.java
Normal file
28
src/main/java/Main.java
Normal file
@@ -0,0 +1,28 @@
|
||||
import app.AppModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import presenters.MainPresenter;
|
||||
import presenters.NavPresenter;
|
||||
import ui.implementation.components.nav.NavBar;
|
||||
import ui.implementation.views.MainView;
|
||||
import ui.interfaces.IMainView;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Injector injector = Guice.createInjector(new AppModule());
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
|
||||
NavBar navBar = injector.getInstance(NavBar.class);
|
||||
MainView view = (MainView) injector.getInstance(IMainView.class);
|
||||
view.setNavBar(navBar);
|
||||
view.setVisible(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
49
src/main/java/app/AppModule.java
Normal file
49
src/main/java/app/AppModule.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package app;
|
||||
|
||||
import app.state.AppState;
|
||||
import app.state.DoubleMatrixState;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Scopes;
|
||||
import presenters.DoubleMatrixPresenter;
|
||||
import presenters.MainPresenter;
|
||||
import presenters.NavPresenter;
|
||||
import services.ImageService;
|
||||
import ui.implementation.components.nav.NavBar;
|
||||
import ui.implementation.views.DoubleMatrix;
|
||||
import ui.implementation.views.MainView;
|
||||
import ui.interfaces.IDoubleMatrix;
|
||||
import ui.interfaces.IMainView;
|
||||
import ui.interfaces.INavBar;
|
||||
|
||||
/**
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public class AppModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
|
||||
//--- States ---
|
||||
bind(AppState.class).in(Scopes.SINGLETON);
|
||||
bind(DoubleMatrixState.class);
|
||||
|
||||
//--- Application layer ---
|
||||
bind(EventBus.class).in(Scopes.SINGLETON);
|
||||
bind(INavigator.class).to(SwingNavigator.class).in(Scopes.SINGLETON);
|
||||
|
||||
//--- UI layer ---
|
||||
bind(INavBar.class).to(NavBar.class);
|
||||
bind(IMainView.class).to(MainView.class);
|
||||
bind(IDoubleMatrix.class).to(DoubleMatrix.class);
|
||||
|
||||
//--- Presentation layer ---
|
||||
bind(MainPresenter.class);
|
||||
bind(NavPresenter.class);
|
||||
bind(DoubleMatrixPresenter.class);
|
||||
|
||||
//--- Service layer layer ---
|
||||
bind(ImageService.class);
|
||||
|
||||
}
|
||||
}
|
||||
7
src/main/java/app/INavigator.java
Normal file
7
src/main/java/app/INavigator.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package app;
|
||||
|
||||
public interface INavigator {
|
||||
|
||||
void showFourier();
|
||||
|
||||
}
|
||||
23
src/main/java/app/SwingNavigator.java
Normal file
23
src/main/java/app/SwingNavigator.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package app;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import ui.implementation.views.DoubleMatrix;
|
||||
|
||||
public class SwingNavigator implements INavigator {
|
||||
|
||||
private final Provider<DoubleMatrix> doubleMatrixProvider;
|
||||
|
||||
@Inject
|
||||
public SwingNavigator(
|
||||
Provider<DoubleMatrix> doubleMatrixProvider
|
||||
) {
|
||||
this.doubleMatrixProvider = doubleMatrixProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showFourier() {
|
||||
DoubleMatrix doubleMatrix = doubleMatrixProvider.get();
|
||||
doubleMatrix.setVisible(true);
|
||||
}
|
||||
}
|
||||
37
src/main/java/app/state/AppState.java
Normal file
37
src/main/java/app/state/AppState.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package app.state;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import domain.common.Mode;
|
||||
import domain.events.ImageChangedEvent;
|
||||
import domain.events.ModeChangedEvent;
|
||||
import domain.image.Image;
|
||||
|
||||
@Singleton
|
||||
public class AppState extends State {
|
||||
|
||||
private Mode mode;
|
||||
private Image rgbImage;
|
||||
|
||||
@Inject
|
||||
public AppState(EventBus eventBus) {
|
||||
super(eventBus);
|
||||
}
|
||||
|
||||
public void setMode(Mode mode) {
|
||||
this.mode = mode;
|
||||
this.eventBus.post(new ModeChangedEvent(mode));
|
||||
}
|
||||
|
||||
public void setImage(Image image) {
|
||||
this.rgbImage = image;
|
||||
this.eventBus.post(new ImageChangedEvent(image));
|
||||
}
|
||||
|
||||
public Image getImage(){
|
||||
return this.rgbImage;
|
||||
}
|
||||
|
||||
public Mode getMode() { return this.mode; }
|
||||
}
|
||||
49
src/main/java/app/state/DoubleMatrixState.java
Normal file
49
src/main/java/app/state/DoubleMatrixState.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package app.state;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import domain.events.fourier.*;
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.processing.complex.ComplexMatrix;
|
||||
|
||||
public class DoubleMatrixState extends State {
|
||||
|
||||
private ComplexMatrix fourier;
|
||||
private GrayScaleMatrix module;
|
||||
private GrayScaleMatrix phase;
|
||||
private GrayScaleMatrix real;
|
||||
private GrayScaleMatrix imaginary;
|
||||
|
||||
@Inject
|
||||
public DoubleMatrixState() { super(new EventBus()); }
|
||||
|
||||
public ComplexMatrix getFourier() {
|
||||
return fourier;
|
||||
}
|
||||
|
||||
public void setFourier(ComplexMatrix fourier) {
|
||||
this.fourier = fourier;
|
||||
this.eventBus.post(new ComplexMatrixChanged(fourier));
|
||||
}
|
||||
|
||||
public void setModule(GrayScaleMatrix matrix) {
|
||||
this.module = matrix;
|
||||
this.eventBus.post(new ModuleChangedEvent(matrix));
|
||||
}
|
||||
|
||||
public void setPhase(GrayScaleMatrix matrix) {
|
||||
this.phase = matrix;
|
||||
this.eventBus.post(new PhaseChangedEvent(matrix));
|
||||
}
|
||||
|
||||
public void setReal(GrayScaleMatrix matrix) {
|
||||
this.real = matrix;
|
||||
this.eventBus.post(new RealChangedEvent(matrix));
|
||||
}
|
||||
|
||||
public void setImaginary(GrayScaleMatrix matrix) {
|
||||
this.imaginary = matrix;
|
||||
this.eventBus.post(new ImaginaryChangedEvent(matrix));
|
||||
}
|
||||
}
|
||||
16
src/main/java/app/state/State.java
Normal file
16
src/main/java/app/state/State.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package app.state;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
public abstract class State {
|
||||
|
||||
protected EventBus eventBus;
|
||||
|
||||
public State(EventBus eventBus) {
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
public void register(Object obj) {
|
||||
eventBus.register(obj);
|
||||
}
|
||||
}
|
||||
9
src/main/java/domain/common/Mode.java
Normal file
9
src/main/java/domain/common/Mode.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package domain.common;
|
||||
|
||||
public enum Mode {
|
||||
DISABLED,
|
||||
DRAW_PIXEL,
|
||||
DRAW_LINE,
|
||||
DRAW_RECTANGLE,
|
||||
DRAW_CIRCLE,
|
||||
}
|
||||
5
src/main/java/domain/events/ImageChangedEvent.java
Normal file
5
src/main/java/domain/events/ImageChangedEvent.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package domain.events;
|
||||
|
||||
import domain.image.Image;
|
||||
|
||||
public record ImageChangedEvent(Image image) { }
|
||||
6
src/main/java/domain/events/MatrixChangedEvent.java
Normal file
6
src/main/java/domain/events/MatrixChangedEvent.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package domain.events;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
|
||||
public record MatrixChangedEvent(GrayScaleMatrix matrix) {
|
||||
}
|
||||
5
src/main/java/domain/events/ModeChangedEvent.java
Normal file
5
src/main/java/domain/events/ModeChangedEvent.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package domain.events;
|
||||
|
||||
import domain.common.Mode;
|
||||
|
||||
public record ModeChangedEvent(Mode mode) { }
|
||||
@@ -0,0 +1,6 @@
|
||||
package domain.events.fourier;
|
||||
|
||||
import domain.image.processing.complex.ComplexMatrix;
|
||||
|
||||
public record ComplexMatrixChanged(ComplexMatrix matrix) {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package domain.events.fourier;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
|
||||
public record ImaginaryChangedEvent(GrayScaleMatrix matrix) {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package domain.events.fourier;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
|
||||
public record ModuleChangedEvent(GrayScaleMatrix matrix) {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package domain.events.fourier;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
|
||||
public record PhaseChangedEvent(GrayScaleMatrix matrix) {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package domain.events.fourier;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
|
||||
public record RealChangedEvent(GrayScaleMatrix matrix) {
|
||||
}
|
||||
130
src/main/java/domain/image/GrayScaleMatrix.java
Normal file
130
src/main/java/domain/image/GrayScaleMatrix.java
Normal file
@@ -0,0 +1,130 @@
|
||||
package domain.image;
|
||||
|
||||
import infrastructure.image.io.ImageSaver;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author Jean-Marc Wagner, Laurent Crema
|
||||
*/
|
||||
public class GrayScaleMatrix {
|
||||
|
||||
private final double[][] matrix;
|
||||
|
||||
private final double maxValue;
|
||||
private final double minValue;
|
||||
|
||||
public GrayScaleMatrix(double[][] matrix) {
|
||||
this.matrix = matrix;
|
||||
this.maxValue = computeMax();
|
||||
this.minValue = computeMin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the actual content of this matrix.
|
||||
* Since a copy is returned, no change that will be applied on it is going to affect the original matrix
|
||||
* @return a copy of the actual content
|
||||
*/
|
||||
public double[][] getRawData() {
|
||||
return Arrays.copyOf(matrix, matrix.length);
|
||||
}
|
||||
|
||||
public int getWidth(){
|
||||
return matrix[0].length;
|
||||
}
|
||||
|
||||
public int getHeight(){
|
||||
return matrix.length;
|
||||
}
|
||||
|
||||
public double getMaxValue() {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
public double getMinValue() {
|
||||
return minValue;
|
||||
}
|
||||
|
||||
public double getValueAt(double normalized) {
|
||||
if(normalized <= 0) { return minValue; }
|
||||
if(normalized >= 1) { return maxValue; }
|
||||
return minValue + (maxValue - minValue) * normalized;
|
||||
}
|
||||
|
||||
private double computeMax(){
|
||||
double res = matrix[0][0];
|
||||
for(int y = 0; y < getHeight(); y++) {
|
||||
for (int x = 0; x < getWidth(); x++) {
|
||||
double value = matrix[y][x];
|
||||
if (value > res) res = matrix[y][x];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private double computeMin(){
|
||||
double res = matrix[0][0];
|
||||
for(int y = 0; y < getHeight(); y++) {
|
||||
for (int x = 0; x < getWidth(); x++) {
|
||||
double value = matrix[y][x];
|
||||
if (value < res) res = matrix[y][x];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public GrayScaleMatrix clip() {
|
||||
return clip(minValue, maxValue);
|
||||
}
|
||||
|
||||
public GrayScaleMatrix clip(double lowerBound, double upperBound) {
|
||||
|
||||
int height = getHeight();
|
||||
int width = getWidth();
|
||||
|
||||
double[][] res = new double[height][width];
|
||||
|
||||
double range = upperBound - lowerBound;
|
||||
if (range == 0) range = 1;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
|
||||
double v = matrix[y][x];
|
||||
double out;
|
||||
|
||||
if (v >= upperBound) {
|
||||
out = 255;
|
||||
} else if (v <= lowerBound) {
|
||||
out = 0;
|
||||
} else {
|
||||
out = (v - lowerBound) / range * 255.0;
|
||||
}
|
||||
|
||||
res[y][x] = Math.clamp(out, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
return new GrayScaleMatrix(res);
|
||||
}
|
||||
|
||||
public Image toImage() {
|
||||
|
||||
Pixel[][] res = new Pixel[getHeight()][getWidth()];
|
||||
|
||||
double range = maxValue - minValue;
|
||||
if (range == 0) range = 1;
|
||||
|
||||
for (int y = 0; y < getHeight(); y++) {
|
||||
for (int x = 0; x < getWidth(); x++) {
|
||||
|
||||
double normalized = (matrix[y][x] - minValue) / range;
|
||||
int gray = (int) (normalized * 255);
|
||||
|
||||
res[y][x] = new Pixel(gray, gray, gray);
|
||||
}
|
||||
}
|
||||
|
||||
return new Image(res);
|
||||
}
|
||||
}
|
||||
126
src/main/java/domain/image/Image.java
Normal file
126
src/main/java/domain/image/Image.java
Normal file
@@ -0,0 +1,126 @@
|
||||
package domain.image;
|
||||
|
||||
/**
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public class Image {
|
||||
|
||||
private final Pixel[][] pixels;
|
||||
private GrayScaleMatrix grayScaleEquivalent;
|
||||
|
||||
public Image(Pixel[][] pixels) {
|
||||
if(pixels == null || pixels.length == 0 || pixels[0].length == 0)
|
||||
throw new IllegalArgumentException("Invalid dimensions");
|
||||
this.pixels = pixels;
|
||||
}
|
||||
|
||||
public Image(int red, int green, int blue, int height, int width) {
|
||||
pixels = new Pixel[height][width];
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
pixels[y][x] = new Pixel(red, green, blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getWidth(){
|
||||
return pixels[0].length;
|
||||
}
|
||||
|
||||
public int getHeight(){
|
||||
return pixels.length;
|
||||
}
|
||||
|
||||
public Pixel getPixel(int x, int y){
|
||||
if(x < 0 || y < 0 || x >= getWidth() || y >= getHeight())
|
||||
throw new IllegalArgumentException("Invalid coordinates");
|
||||
return pixels[y][x];
|
||||
}
|
||||
|
||||
public void setPixelColor(int x, int y, int red, int green, int blue){
|
||||
if(x < 0 || y < 0 || x >= getWidth() || y >= getHeight())
|
||||
throw new IllegalArgumentException("Invalid coordinates");
|
||||
Pixel p = new Pixel(red, green, blue);
|
||||
pixels[y][x] = p;
|
||||
grayScaleEquivalent = toGrayScale();
|
||||
}
|
||||
|
||||
public void setRectangleColor(int x1, int x2, int y1, int y2,
|
||||
int red, int green, int blue) {
|
||||
|
||||
int minX = Math.max(0, Math.min(x1, x2));
|
||||
int maxX = Math.min(pixels[0].length - 1, Math.max(x1, x2));
|
||||
|
||||
int minY = Math.max(0, Math.min(y1, y2));
|
||||
int maxY = Math.min(pixels.length - 1, Math.max(y1, y2));
|
||||
|
||||
Pixel p = new Pixel(red, green, blue);
|
||||
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
pixels[y][x] = p;
|
||||
}
|
||||
}
|
||||
|
||||
grayScaleEquivalent = toGrayScale();
|
||||
}
|
||||
|
||||
public void setLineColor(int x1, int x2, int y1, int y2,
|
||||
int red, int green, int blue) {
|
||||
|
||||
int dx = Math.abs(x2 - x1);
|
||||
int dy = Math.abs(y2 - y1);
|
||||
|
||||
int sx = x1 < x2 ? 1 : -1;
|
||||
int sy = y1 < y2 ? 1 : -1;
|
||||
|
||||
int err = dx - dy;
|
||||
|
||||
Pixel p = new Pixel(red, green, blue);
|
||||
|
||||
while (true) {
|
||||
if (x1 >= 0 && y1 >= 0 && x1 < getWidth() && y1 < getHeight()) {
|
||||
pixels[y1][x1] = p;
|
||||
}
|
||||
|
||||
if (x1 == x2 && y1 == y2) break;
|
||||
|
||||
int e2 = 2 * err;
|
||||
|
||||
if (e2 > -dy) {
|
||||
err -= dy;
|
||||
x1 += sx;
|
||||
}
|
||||
|
||||
if (e2 < dx) {
|
||||
err += dx;
|
||||
y1 += sy;
|
||||
}
|
||||
}
|
||||
|
||||
grayScaleEquivalent = toGrayScale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the corresponding gray scale matrix. Since this operation is destructive, the original image is not modified.
|
||||
* Instead, a new one is returned.
|
||||
* @return A newly converted image
|
||||
*/
|
||||
public GrayScaleMatrix toGrayScale() {
|
||||
|
||||
if(grayScaleEquivalent != null) return this.grayScaleEquivalent;
|
||||
|
||||
double[][] res = new double[getHeight()][getWidth()];
|
||||
|
||||
for (int y = 0; y < getHeight(); y++) {
|
||||
for (int x = 0; x < getWidth(); x++) {
|
||||
|
||||
Pixel p = pixels[y][x];
|
||||
res[y][x] = p.grayValue();
|
||||
}
|
||||
}
|
||||
|
||||
this.grayScaleEquivalent = new GrayScaleMatrix(res);
|
||||
return this.grayScaleEquivalent;
|
||||
}
|
||||
}
|
||||
62
src/main/java/domain/image/Pixel.java
Normal file
62
src/main/java/domain/image/Pixel.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package domain.image;
|
||||
|
||||
/**
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public class Pixel {
|
||||
|
||||
private int red, green, blue;
|
||||
|
||||
public Pixel(int red, int green, int blue) {
|
||||
|
||||
if(checkColorValidity(red))
|
||||
throw new IllegalArgumentException("Invalid red value"); // <-- here
|
||||
if(checkColorValidity(green)) throw new IllegalArgumentException("Invalid green value");
|
||||
if(checkColorValidity(blue)) throw new IllegalArgumentException("Invalid blue value");
|
||||
|
||||
this.red = red;
|
||||
this.green = green;
|
||||
this.blue = blue;
|
||||
}
|
||||
|
||||
public int getRed() {
|
||||
return red;
|
||||
}
|
||||
|
||||
public void setRed(int value) {
|
||||
if(checkColorValidity(value)) throw new IllegalArgumentException("Invalid value");
|
||||
this.red = value;
|
||||
}
|
||||
|
||||
public int getGreen() {
|
||||
return green;
|
||||
}
|
||||
|
||||
public void setGreen(int value) {
|
||||
if(checkColorValidity(value)) throw new IllegalArgumentException("Invalid value");
|
||||
this.green = value;
|
||||
}
|
||||
|
||||
public int getBlue() {
|
||||
return blue;
|
||||
}
|
||||
|
||||
public void setBlue(int value) {
|
||||
if(checkColorValidity(value)) throw new IllegalArgumentException("Invalid value");
|
||||
this.blue = value;
|
||||
}
|
||||
|
||||
public boolean checkColorValidity(int color) {
|
||||
return !(color >= 0 && color <= 255);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the current RGB combination into a gray value according to UIT-R BT 709 standard.
|
||||
* The current RGB values are not modified.
|
||||
* @return the corresponding gray scale value
|
||||
*/
|
||||
public int grayValue(){
|
||||
return (int) (0.2126 * red + 0.7152 * green + 0.0722 * blue);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package domain.image.processing.complex;
|
||||
|
||||
public class ComplexMatrix
|
||||
{
|
||||
private Complexe m[][];
|
||||
private int lignes;
|
||||
private int colonnes;
|
||||
|
||||
/** Creates a new instance of MatriceComplexe */
|
||||
public ComplexMatrix(int l, int c)
|
||||
{
|
||||
lignes = l;
|
||||
colonnes = c;
|
||||
m = new Complexe[l][c];
|
||||
for(int i=0 ; i<lignes ; i++)
|
||||
for(int j=0 ; j<colonnes ; j++)
|
||||
m[i][j] = new Complexe(0.0,0.0);
|
||||
}
|
||||
|
||||
public void set(int ligne,int colonne,Complexe complexe)
|
||||
{
|
||||
m[ligne][colonne] = complexe;
|
||||
}
|
||||
|
||||
public void set(int ligne,int colonne,double partieReelle,double partieImaginaire)
|
||||
{
|
||||
Complexe c = new Complexe(partieReelle,partieImaginaire);
|
||||
set(ligne,colonne,c);
|
||||
}
|
||||
|
||||
public Complexe get(int ligne,int colonne)
|
||||
{
|
||||
return m[ligne][colonne];
|
||||
}
|
||||
|
||||
public double[][] getPartieReelle()
|
||||
{
|
||||
double d[][] = new double[lignes][colonnes];
|
||||
for(int i=0 ; i<lignes ; i++)
|
||||
for(int j=0 ; j<colonnes ; j++)
|
||||
d[i][j] = m[i][j].getPartieReelle();
|
||||
return d;
|
||||
}
|
||||
|
||||
public double[][] getPartieImaginaire()
|
||||
{
|
||||
double d[][] = new double[lignes][colonnes];
|
||||
for(int i=0 ; i<lignes ; i++)
|
||||
for(int j=0 ; j<colonnes ; j++)
|
||||
d[i][j] = m[i][j].getPartieImaginaire();
|
||||
return d;
|
||||
}
|
||||
|
||||
public double[][] getModule()
|
||||
{
|
||||
double d[][] = new double[lignes][colonnes];
|
||||
for(int i=0 ; i<lignes ; i++)
|
||||
for(int j=0 ; j<colonnes ; j++)
|
||||
d[i][j] = m[i][j].getModule();
|
||||
return d;
|
||||
}
|
||||
|
||||
public double[][] getPhase()
|
||||
{
|
||||
double d[][] = new double[lignes][colonnes];
|
||||
for(int i=0 ; i<lignes ; i++)
|
||||
for(int j=0 ; j<colonnes ; j++)
|
||||
d[i][j] = m[i][j].getPhase();
|
||||
return d;
|
||||
}
|
||||
|
||||
public int getLignes() {
|
||||
return lignes;
|
||||
}
|
||||
|
||||
public int getColonnes() {
|
||||
return colonnes;
|
||||
}
|
||||
|
||||
}
|
||||
61
src/main/java/domain/image/processing/complex/Complexe.java
Normal file
61
src/main/java/domain/image/processing/complex/Complexe.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package domain.image.processing.complex;
|
||||
|
||||
public class Complexe
|
||||
{
|
||||
private double partieReelle;
|
||||
private double partieImaginaire;
|
||||
|
||||
/** Creates a new instance of Complexe */
|
||||
public Complexe(double pr,double pi)
|
||||
{
|
||||
partieReelle = pr;
|
||||
partieImaginaire = pi;
|
||||
}
|
||||
|
||||
public double getModule()
|
||||
{
|
||||
return Math.sqrt(partieReelle*partieReelle + partieImaginaire*partieImaginaire);
|
||||
}
|
||||
|
||||
public double getPhase()
|
||||
{
|
||||
return Math.atan2(partieImaginaire,partieReelle);
|
||||
}
|
||||
|
||||
public void additionne(Complexe c)
|
||||
{
|
||||
partieReelle += c.getPartieReelle();
|
||||
partieImaginaire += c.getPartieImaginaire();
|
||||
}
|
||||
|
||||
public void multiplie(Complexe c)
|
||||
{
|
||||
double r,i;
|
||||
r = partieReelle*c.getPartieReelle() - partieImaginaire*c.getPartieImaginaire();
|
||||
i = partieReelle*c.getPartieImaginaire() + partieImaginaire*c.getPartieReelle();
|
||||
partieReelle = r;
|
||||
partieImaginaire = i;
|
||||
}
|
||||
|
||||
public Complexe conjugue()
|
||||
{
|
||||
return new Complexe(partieReelle,-partieImaginaire);
|
||||
}
|
||||
|
||||
public double getPartieReelle() {
|
||||
return partieReelle;
|
||||
}
|
||||
|
||||
public void setPartieReelle(double partieReelle) {
|
||||
this.partieReelle = partieReelle;
|
||||
}
|
||||
|
||||
public double getPartieImaginaire() {
|
||||
return partieImaginaire;
|
||||
}
|
||||
|
||||
public void setPartieImaginaire(double partieImaginaire) {
|
||||
this.partieImaginaire = partieImaginaire;
|
||||
}
|
||||
|
||||
}
|
||||
173
src/main/java/domain/image/processing/fourier/Fourier.java
Normal file
173
src/main/java/domain/image/processing/fourier/Fourier.java
Normal file
@@ -0,0 +1,173 @@
|
||||
package domain.image.processing.fourier;
|
||||
|
||||
import domain.image.processing.complex.ComplexMatrix;
|
||||
|
||||
public class Fourier
|
||||
{
|
||||
public static ComplexMatrix Fourier2D(double f[][])
|
||||
{
|
||||
int M = f.length;
|
||||
int N = f[0].length;
|
||||
ComplexMatrix F = new ComplexMatrix(M,N);
|
||||
|
||||
//********** n --> v **********
|
||||
double pr1[][] = new double[M][N];
|
||||
double pi1[][] = new double[M][N];
|
||||
|
||||
for(int m=0 ; m<M ; m++)
|
||||
{
|
||||
for(int v=0 ; v<=N/2 ; v++)
|
||||
{
|
||||
pr1[m][v] = 0.0;
|
||||
pi1[m][v] = 0.0;
|
||||
double cosTheta = 1.0, newCosTheta;
|
||||
double sinTheta = 0.0, newSinTheta;
|
||||
double cosDTheta = Math.cos(-2.0*Math.PI*(double)v/(double)N);
|
||||
double sinDTheta = Math.sin(-2.0*Math.PI*(double)v/(double)N);
|
||||
for (int n=0 ; n<N ; n++)
|
||||
{
|
||||
pr1[m][v] += f[m][n] * cosTheta;
|
||||
pi1[m][v] += f[m][n] * sinTheta;
|
||||
newCosTheta = cosTheta*cosDTheta - sinTheta*sinDTheta;
|
||||
newSinTheta = sinTheta*cosDTheta + cosTheta*sinDTheta;
|
||||
cosTheta = newCosTheta;
|
||||
sinTheta = newSinTheta;
|
||||
}
|
||||
pr1[m][v] /= (double)N;
|
||||
pi1[m][v] /= (double)N;
|
||||
if (v > 0)
|
||||
{
|
||||
pr1[m][N-v] = pr1[m][v];
|
||||
pi1[m][N-v] = -pi1[m][v];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//********** m --> u **********
|
||||
double pr2[][] = new double[M][N];
|
||||
double pi2[][] = new double[M][N];
|
||||
|
||||
for(int v=0 ; v<N ; v++)
|
||||
{
|
||||
for(int u=0 ; u<M ; u++)
|
||||
{
|
||||
pr2[u][v] = 0.0;
|
||||
pi2[u][v] = 0.0;
|
||||
double cosTheta = 1.0, newCosTheta;
|
||||
double sinTheta = 0.0, newSinTheta;
|
||||
double cosDTheta = Math.cos(-2.0*Math.PI*(double)u/(double)M);
|
||||
double sinDTheta = Math.sin(-2.0*Math.PI*(double)u/(double)M);
|
||||
for (int m=0 ; m<M ; m++)
|
||||
{
|
||||
pr2[u][v] += pr1[m][v] * cosTheta - pi1[m][v] * sinTheta;
|
||||
pi2[u][v] += pr1[m][v] * sinTheta + pi1[m][v] * cosTheta;
|
||||
newCosTheta = cosTheta*cosDTheta - sinTheta*sinDTheta;
|
||||
newSinTheta = sinTheta*cosDTheta + cosTheta*sinDTheta;
|
||||
cosTheta = newCosTheta;
|
||||
sinTheta = newSinTheta;
|
||||
}
|
||||
pr2[u][v] /= (double)M;
|
||||
pi2[u][v] /= (double)M;
|
||||
}
|
||||
}
|
||||
|
||||
//********** Remplissage de F **********
|
||||
for(int u=0 ; u<M ; u++)
|
||||
for(int v=0 ; v<N ; v++)
|
||||
F.set(u,v,pr2[u][v],pi2[u][v]);
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
public static ComplexMatrix InverseFourier2D(ComplexMatrix F)
|
||||
{
|
||||
int M = F.getLignes();
|
||||
int N = F.getColonnes();
|
||||
ComplexMatrix f = new ComplexMatrix(M,N);
|
||||
|
||||
double pr0[][] = F.getPartieReelle();
|
||||
double pi0[][] = F.getPartieImaginaire();
|
||||
|
||||
//********** v --> n **********
|
||||
double pr1[][] = new double[M][N];
|
||||
double pi1[][] = new double[M][N];
|
||||
|
||||
for(int u=0 ; u<M ; u++)
|
||||
{
|
||||
for(int n=0 ; n<N ; n++)
|
||||
{
|
||||
pr1[u][n] = 0.0;
|
||||
pi1[u][n] = 0.0;
|
||||
double cosTheta = 1.0, newCosTheta;
|
||||
double sinTheta = 0.0, newSinTheta;
|
||||
double cosDTheta = Math.cos(2.0*Math.PI*(double)n/(double)N);
|
||||
double sinDTheta = Math.sin(2.0*Math.PI*(double)n/(double)N);
|
||||
for (int v=0 ; v<N ; v++)
|
||||
{
|
||||
pr1[u][n] += pr0[u][v] * cosTheta - pi0[u][v] * sinTheta;
|
||||
pi1[u][n] += pr0[u][v] * sinTheta + pi0[u][v] * cosTheta;
|
||||
newCosTheta = cosTheta*cosDTheta - sinTheta*sinDTheta;
|
||||
newSinTheta = sinTheta*cosDTheta + cosTheta*sinDTheta;
|
||||
cosTheta = newCosTheta;
|
||||
sinTheta = newSinTheta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//********** u --> m **********
|
||||
double pr2[][] = new double[M][N];
|
||||
double pi2[][] = new double[M][N];
|
||||
|
||||
for(int n=0 ; n<N ; n++)
|
||||
{
|
||||
for(int m=0 ; m<M ; m++)
|
||||
{
|
||||
pr2[m][n] = 0.0;
|
||||
pi2[m][n] = 0.0;
|
||||
double cosTheta = 1.0, newCosTheta;
|
||||
double sinTheta = 0.0, newSinTheta;
|
||||
double cosDTheta = Math.cos(2.0*Math.PI*(double)m/(double)M);
|
||||
double sinDTheta = Math.sin(2.0*Math.PI*(double)m/(double)M);
|
||||
for (int u=0 ; u<M ; u++)
|
||||
{
|
||||
pr2[m][n] += pr1[u][n] * cosTheta - pi1[u][n] * sinTheta;
|
||||
pi2[m][n] += pr1[u][n] * sinTheta + pi1[u][n] * cosTheta;
|
||||
newCosTheta = cosTheta*cosDTheta - sinTheta*sinDTheta;
|
||||
newSinTheta = sinTheta*cosDTheta + cosTheta*sinDTheta;
|
||||
cosTheta = newCosTheta;
|
||||
sinTheta = newSinTheta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//********** Remplissage de f **********
|
||||
for(int m=0 ; m<M ; m++)
|
||||
for(int n=0 ; n<N ; n++)
|
||||
f.set(m,n,pr2[m][n],pi2[m][n]);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public static ComplexMatrix decroise(ComplexMatrix F)
|
||||
{
|
||||
int M = F.getLignes();
|
||||
int N = F.getColonnes();
|
||||
ComplexMatrix mat = new ComplexMatrix(M,N);
|
||||
|
||||
int m,n;
|
||||
|
||||
for(m=0 ; m<M/2 ; m++)
|
||||
for(n=0 ; n<N/2 ; n++) mat.set(m,n,F.get(M/2+m,N/2+n));
|
||||
|
||||
for(m=M/2 ; m<M ; m++)
|
||||
for(n=0 ; n<N/2 ; n++) mat.set(m,n,F.get(m-M/2,n+N/2));
|
||||
|
||||
for(m=0 ; m<M/2 ; m++)
|
||||
for(n=N/2 ; n<N ; n++) mat.set(m,n,F.get(m+M/2,n-N/2));
|
||||
|
||||
for(m=M/2 ; m<M ; m++)
|
||||
for(n=N/2 ; n<N ; n++) mat.set(m,n,F.get(m-M/2,n-N/2));
|
||||
|
||||
return mat;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package domain.image.processing.histogram;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.Image;
|
||||
|
||||
public class Histogramme {
|
||||
public static int[] Histogramme256(GrayScaleMatrix mat) {
|
||||
int M = mat.getHeight();
|
||||
int N = mat.getWidth();
|
||||
int histo[] = new int[256];
|
||||
|
||||
for (int i = 0; i < 256; i++) histo[i] = 0;
|
||||
|
||||
Image grayScaleImage = mat.toImage();
|
||||
|
||||
int pixelGrayValue = 0;
|
||||
for (int i = 0; i < M; i++) {
|
||||
for (int j = 0; j < N; j++) {
|
||||
pixelGrayValue = grayScaleImage.getPixel(i, j).grayValue();
|
||||
if ((pixelGrayValue >= 0) && (pixelGrayValue <= 255)) {
|
||||
histo[pixelGrayValue]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return histo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package domain.image.processing.lineaire;
|
||||
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
|
||||
public class FiltrageLinaireGlobal {
|
||||
|
||||
public static int[][] filtrePasseBasIdeal(int[][] image,int frequenceCoupure){
|
||||
return null;
|
||||
}
|
||||
public static int[][] filtrePasseHautIdeal(int[][] image,int frequenceCoupure){
|
||||
return null;
|
||||
}
|
||||
public static int[][] filtrePasseBasButterworth(int[][] image,int frequenceCoupure,int ordre){
|
||||
return null;
|
||||
}
|
||||
public static int[][] filtrePasseHautButterworth(int[][] image,int frequenceCoupure, int ordre) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
39
src/main/java/infrastructure/image/io/ImageLoader.java
Normal file
39
src/main/java/infrastructure/image/io/ImageLoader.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package infrastructure.image.io;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import domain.image.Image;
|
||||
import domain.image.Pixel;
|
||||
|
||||
public class ImageLoader {
|
||||
|
||||
public static Image loadImage(File f) throws IOException {
|
||||
|
||||
BufferedImage buffered = ImageIO.read(f);
|
||||
|
||||
if (buffered == null) throw new IOException("Unsupported or invalid image file: " + f);
|
||||
|
||||
int width = buffered.getWidth();
|
||||
int height = buffered.getHeight();
|
||||
|
||||
Pixel[][] pixels = new Pixel[height][width];
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
|
||||
int rgb = buffered.getRGB(x, y);
|
||||
|
||||
int r = (rgb >> 16) & 0xFF;
|
||||
int g = (rgb >> 8) & 0xFF;
|
||||
int b = rgb & 0xFF;
|
||||
|
||||
pixels[y][x] = new Pixel(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
return new Image(pixels);
|
||||
}
|
||||
}
|
||||
12
src/main/java/infrastructure/image/io/ImageSaver.java
Normal file
12
src/main/java/infrastructure/image/io/ImageSaver.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package infrastructure.image.io;
|
||||
|
||||
import domain.image.Image;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ImageSaver {
|
||||
|
||||
public static void saveImage(Image image) throws IOException {
|
||||
}
|
||||
|
||||
}
|
||||
55
src/main/java/infrastructure/ui/ImageMapper.java
Normal file
55
src/main/java/infrastructure/ui/ImageMapper.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package infrastructure.ui;
|
||||
|
||||
import domain.image.Image;
|
||||
import domain.image.Pixel;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public final class ImageMapper {
|
||||
|
||||
public static BufferedImage toBufferedImage(Image image) {
|
||||
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
|
||||
BufferedImage out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
|
||||
Pixel p = image.getPixel(x, y);
|
||||
|
||||
int rgb = (p.getRed() << 16)
|
||||
| (p.getGreen() << 8)
|
||||
| p.getBlue();
|
||||
|
||||
out.setRGB(x, y, rgb);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
public static Image fromBufferedImage(BufferedImage img) {
|
||||
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
|
||||
Pixel[][] pixels = new Pixel[height][width];
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
|
||||
int rgb = img.getRGB(x, y);
|
||||
|
||||
int r = (rgb >> 16) & 0xFF;
|
||||
int g = (rgb >> 8) & 0xFF;
|
||||
int b = rgb & 0xFF;
|
||||
|
||||
pixels[y][x] = new Pixel(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
return new Image(pixels);
|
||||
}
|
||||
}
|
||||
126
src/main/java/presenters/DoubleMatrixPresenter.java
Normal file
126
src/main/java/presenters/DoubleMatrixPresenter.java
Normal file
@@ -0,0 +1,126 @@
|
||||
package presenters;
|
||||
|
||||
import app.state.DoubleMatrixState;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.inject.Inject;
|
||||
import domain.events.fourier.ImaginaryChangedEvent;
|
||||
import domain.events.fourier.ModuleChangedEvent;
|
||||
import domain.events.fourier.PhaseChangedEvent;
|
||||
import domain.events.fourier.RealChangedEvent;
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.Image;
|
||||
import domain.image.processing.complex.ComplexMatrix;
|
||||
import services.ImageService;
|
||||
import ui.interfaces.IDoubleMatrix;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public class DoubleMatrixPresenter {
|
||||
|
||||
private IDoubleMatrix view;
|
||||
private final DoubleMatrixState state;
|
||||
private final ImageService imageService;
|
||||
|
||||
@Inject
|
||||
public DoubleMatrixPresenter(ImageService imageService, DoubleMatrixState state) {
|
||||
this.imageService = imageService;
|
||||
this.state = state;
|
||||
this.state.register(this);
|
||||
}
|
||||
|
||||
public void setView(IDoubleMatrix view){
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public void saveImage(Image image) throws IOException {
|
||||
this.imageService.saveImage(image);
|
||||
}
|
||||
|
||||
public void loadModule(){
|
||||
double[][] module = getFourier().getModule();
|
||||
state.setModule(new GrayScaleMatrix(module));
|
||||
}
|
||||
|
||||
public void loadPhase(){
|
||||
double[][] phase = getFourier().getPhase();
|
||||
state.setPhase(new GrayScaleMatrix(phase));
|
||||
}
|
||||
|
||||
public void loadReal(){
|
||||
double[][] real = getFourier().getPartieReelle();
|
||||
state.setReal(new GrayScaleMatrix(real));
|
||||
}
|
||||
|
||||
public void loadImaginary(){
|
||||
double[][] imaginary = getFourier().getPartieImaginaire();
|
||||
state.setImaginary(new GrayScaleMatrix(imaginary));
|
||||
}
|
||||
|
||||
public double getValueAt(GrayScaleMatrix matrix, double normalized){
|
||||
return matrix.getValueAt(normalized);
|
||||
}
|
||||
|
||||
public void clipModule(double black, double white){
|
||||
GrayScaleMatrix module = new GrayScaleMatrix(getFourier().getModule());
|
||||
GrayScaleMatrix matrix = clip(module, black, white);
|
||||
state.setModule(matrix);
|
||||
}
|
||||
|
||||
public void clipPhase(double black, double white){
|
||||
GrayScaleMatrix phase = new GrayScaleMatrix(getFourier().getPhase());
|
||||
GrayScaleMatrix matrix = clip(phase, black, white);
|
||||
state.setPhase(matrix);
|
||||
}
|
||||
|
||||
public void clipReal(double black, double white){
|
||||
GrayScaleMatrix real = new GrayScaleMatrix(getFourier().getPartieReelle());
|
||||
GrayScaleMatrix matrix = clip(real, black, white);
|
||||
state.setReal(matrix);
|
||||
}
|
||||
|
||||
public void clipImaginary(double black, double white){
|
||||
GrayScaleMatrix imaginary = new GrayScaleMatrix(getFourier().getPartieImaginaire());
|
||||
GrayScaleMatrix matrix = clip(imaginary, black, white);
|
||||
state.setImaginary(matrix);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onModuleUpdate(ModuleChangedEvent event) {
|
||||
GrayScaleMatrix module = new GrayScaleMatrix(getFourier().getModule());
|
||||
view.updateModule(module, event.matrix());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPhaseUpdate(PhaseChangedEvent event) {
|
||||
GrayScaleMatrix phase = new GrayScaleMatrix(getFourier().getPhase());
|
||||
view.updatePhase(phase, event.matrix());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onRealUpdate(RealChangedEvent event) {
|
||||
GrayScaleMatrix real = new GrayScaleMatrix(getFourier().getPartieReelle());
|
||||
view.updateReal(real, event.matrix());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onImaginaryUpdate(ImaginaryChangedEvent event) {
|
||||
GrayScaleMatrix imaginary = new GrayScaleMatrix(getFourier().getPartieImaginaire());
|
||||
view.updateImaginary(imaginary, event.matrix());
|
||||
}
|
||||
|
||||
private GrayScaleMatrix clip(GrayScaleMatrix matrix, double black, double white){
|
||||
double lowerBound = matrix.getValueAt(black);
|
||||
double upperBound = matrix.getValueAt(white);
|
||||
return matrix.clip(lowerBound, upperBound);
|
||||
}
|
||||
|
||||
private ComplexMatrix getFourier() {
|
||||
if (state.getFourier() == null) {
|
||||
state.setFourier(imageService.computeFourier());
|
||||
}
|
||||
return state.getFourier();
|
||||
}
|
||||
}
|
||||
67
src/main/java/presenters/MainPresenter.java
Normal file
67
src/main/java/presenters/MainPresenter.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package presenters;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.inject.Inject;
|
||||
import domain.common.Mode;
|
||||
import domain.events.ImageChangedEvent;
|
||||
import domain.events.ModeChangedEvent;
|
||||
import domain.image.Image;
|
||||
import services.ImageService;
|
||||
import services.ModeService;
|
||||
import ui.interfaces.IMainView;
|
||||
|
||||
/**
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public class MainPresenter {
|
||||
|
||||
private IMainView view;
|
||||
private final ModeService modeService;
|
||||
private final ImageService imageService;
|
||||
|
||||
@Inject
|
||||
public MainPresenter(ModeService modeService, ImageService imageService, EventBus eventBus) {
|
||||
this.modeService = modeService;
|
||||
this.imageService = imageService;
|
||||
eventBus.register(this);
|
||||
}
|
||||
|
||||
public void setView(IMainView view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onImageChanged(ImageChangedEvent e){
|
||||
view.displayImage(e.image());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onModeChanged(ModeChangedEvent e){
|
||||
view.changeMode(e.mode());
|
||||
}
|
||||
|
||||
public void drawPixel(int x, int y, int red, int green, int blue){
|
||||
if(modeService.getMode() != Mode.DRAW_PIXEL) return;
|
||||
Image image = imageService.getImage();
|
||||
image.setPixelColor(x, y, red, green, blue);
|
||||
imageService.setImage(image);
|
||||
}
|
||||
|
||||
public void drawShape(int x1, int x2, int y1, int y2, int red, int green, int blue){
|
||||
Image image = imageService.getImage();
|
||||
switch (modeService.getMode()) {
|
||||
case DRAW_RECTANGLE:
|
||||
image.setRectangleColor(x1, x2, y1, y2, red, green, blue);
|
||||
break;
|
||||
case DRAW_LINE:
|
||||
image.setLineColor(x1, x2, y1, y2, red, green, blue);
|
||||
break;
|
||||
case DRAW_CIRCLE:
|
||||
break;
|
||||
}
|
||||
imageService.setImage(image);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
55
src/main/java/presenters/NavPresenter.java
Normal file
55
src/main/java/presenters/NavPresenter.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package presenters;
|
||||
|
||||
import app.INavigator;
|
||||
import com.google.inject.Inject;
|
||||
import domain.common.Mode;
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import services.ImageService;
|
||||
import services.ModeService;
|
||||
import ui.interfaces.INavBar;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public class NavPresenter {
|
||||
|
||||
private INavBar navBar;
|
||||
private INavigator navigator;
|
||||
private final ImageService imageService;
|
||||
private final ModeService modeService;
|
||||
|
||||
@Inject
|
||||
public NavPresenter(INavigator navigator, ImageService imageService, ModeService modeService) {
|
||||
this.navigator = navigator;
|
||||
this.imageService = imageService;
|
||||
this.modeService = modeService;
|
||||
}
|
||||
|
||||
public void setView(INavBar navBar) {
|
||||
this.navBar = navBar;
|
||||
}
|
||||
|
||||
public void createImage(int red, int green, int blue, int height, int width) {
|
||||
imageService.createImage(red, green, blue, height, width);
|
||||
}
|
||||
|
||||
public void loadImage(File f) throws IOException {
|
||||
imageService.loadImage(f);
|
||||
}
|
||||
|
||||
public void goToFourier(){
|
||||
navigator.showFourier();
|
||||
}
|
||||
|
||||
public GrayScaleMatrix getImageGrayMatrix() {
|
||||
//return ((CImageNG)appState.getImage()).getMatrice();
|
||||
return imageService.getImage().toGrayScale();
|
||||
}
|
||||
|
||||
public void setMode(Mode mode) {
|
||||
modeService.setMode(mode);
|
||||
}
|
||||
}
|
||||
55
src/main/java/services/ImageService.java
Normal file
55
src/main/java/services/ImageService.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package services;
|
||||
|
||||
import app.state.AppState;
|
||||
import com.google.inject.Inject;
|
||||
import domain.image.Image;
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.processing.complex.ComplexMatrix;
|
||||
import domain.image.processing.fourier.Fourier;
|
||||
import infrastructure.image.io.ImageLoader;
|
||||
import infrastructure.image.io.ImageSaver;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ImageService {
|
||||
|
||||
private final AppState appState;
|
||||
|
||||
@Inject
|
||||
public ImageService(AppState appState) {
|
||||
this.appState = appState;
|
||||
}
|
||||
|
||||
public void createImage(int red, int green, int blue, int height, int width) {
|
||||
Image image = new Image(red, green, blue, height, width);
|
||||
appState.setImage(image);
|
||||
}
|
||||
|
||||
public void loadImage(File f) throws IOException {
|
||||
Image image = ImageLoader.loadImage(f);
|
||||
appState.setImage(image);
|
||||
}
|
||||
|
||||
public void saveImage(Image image) throws IOException {
|
||||
ImageSaver.saveImage(image);
|
||||
}
|
||||
|
||||
public ComplexMatrix computeFourier(){
|
||||
GrayScaleMatrix matrix = appState.getImage().toGrayScale();
|
||||
ComplexMatrix fourier = Fourier.Fourier2D(matrix.getRawData());
|
||||
return Fourier.decroise(fourier);
|
||||
}
|
||||
|
||||
public Image getImage(){
|
||||
return appState.getImage();
|
||||
}
|
||||
|
||||
public void setImage(Image img){
|
||||
appState.setImage(img);
|
||||
}
|
||||
|
||||
public GrayScaleMatrix getGrayScale(){
|
||||
return appState.getImage().toGrayScale();
|
||||
}
|
||||
}
|
||||
22
src/main/java/services/ModeService.java
Normal file
22
src/main/java/services/ModeService.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package services;
|
||||
|
||||
import app.state.AppState;
|
||||
import com.google.inject.Inject;
|
||||
import domain.common.Mode;
|
||||
|
||||
public class ModeService {
|
||||
|
||||
private final AppState appState;
|
||||
|
||||
@Inject
|
||||
public ModeService(AppState appState) {
|
||||
this.appState = appState;
|
||||
}
|
||||
|
||||
public void setMode(Mode m){
|
||||
appState.setMode(m);
|
||||
}
|
||||
|
||||
public Mode getMode() { return this.appState.getMode(); }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package ui.implementation.components.image;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.Image;
|
||||
import infrastructure.ui.ImageMapper;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
|
||||
public class ImagePanel extends JPanel {
|
||||
private BufferedImage image;
|
||||
private double scale;
|
||||
private int drawW;
|
||||
private int drawH;
|
||||
private int offsetX;
|
||||
private int offsetY;
|
||||
|
||||
public ImagePanel() { }
|
||||
|
||||
public ImagePanel(BufferedImage image) {
|
||||
loadImage(image);
|
||||
}
|
||||
|
||||
public void loadImage(BufferedImage image){
|
||||
this.image = image;
|
||||
setPreferredSize(new Dimension(image.getWidth(null), image.getHeight(null)));
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void loadImage(GrayScaleMatrix matrix){
|
||||
this.image = ImageMapper.toBufferedImage(matrix.toImage());
|
||||
setPreferredSize(new Dimension(this.image.getWidth(null), this.image.getHeight(null)));
|
||||
repaint();
|
||||
}
|
||||
|
||||
public Point toImageCoordinates(int x, int y) {
|
||||
if (image == null) return null;
|
||||
|
||||
if (x < offsetX || x >= offsetX + drawW ||
|
||||
y < offsetY || y >= offsetY + drawH) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int imgX = (int) ((x - offsetX) / scale);
|
||||
int imgY = (int) ((y - offsetY) / scale);
|
||||
|
||||
return new Point(imgX, imgY);
|
||||
}
|
||||
|
||||
private void computeViewport() {
|
||||
if (image == null) return;
|
||||
|
||||
int imgW = image.getWidth();
|
||||
int imgH = image.getHeight();
|
||||
|
||||
scale = Math.min(
|
||||
(double) getWidth() / imgW,
|
||||
(double) getHeight() / imgH
|
||||
);
|
||||
|
||||
drawW = (int) (imgW * scale);
|
||||
drawH = (int) (imgH * scale);
|
||||
|
||||
offsetX = (getWidth() - drawW) / 2;
|
||||
offsetY = (getHeight() - drawH) / 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
if (image == null) return;
|
||||
computeViewport();
|
||||
g.drawImage(image, offsetX, offsetY, drawW, drawH, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ui.implementation.components.intent;
|
||||
|
||||
import javax.swing.*;
|
||||
public class FileChooser extends JFileChooser {
|
||||
|
||||
public FileChooser(String initialLocation) {
|
||||
super(initialLocation);
|
||||
}
|
||||
}
|
||||
32
src/main/java/ui/implementation/components/nav/Menu.java
Normal file
32
src/main/java/ui/implementation/components/nav/Menu.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package ui.implementation.components.nav;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.net.URL;
|
||||
|
||||
public class Menu extends JMenu {
|
||||
|
||||
public Menu(String title, JMenuItem... items)
|
||||
{
|
||||
this(title,null, items);
|
||||
}
|
||||
|
||||
public Menu(String title, String iconPath, JMenuItem... items)
|
||||
{
|
||||
super(title);
|
||||
|
||||
if (iconPath != null) {
|
||||
URL url = getClass().getResource(iconPath);
|
||||
if (url != null) {
|
||||
setIcon(new ImageIcon(url));
|
||||
}
|
||||
}
|
||||
|
||||
if (items != null) {
|
||||
for (JMenuItem item : items) {
|
||||
if (item != null) {
|
||||
this.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/main/java/ui/implementation/components/nav/MenuItem.java
Normal file
25
src/main/java/ui/implementation/components/nav/MenuItem.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package ui.implementation.components.nav;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.net.URL;
|
||||
|
||||
public class MenuItem extends JMenuItem {
|
||||
|
||||
public MenuItem(String title, ActionListener listener) {
|
||||
this(title, null, listener);
|
||||
}
|
||||
|
||||
public MenuItem(String title, String iconPath, ActionListener listener) {
|
||||
super(title);
|
||||
if(iconPath != null) {
|
||||
URL url = getClass().getResource(iconPath);
|
||||
if (url != null) {
|
||||
super.setIcon(new ImageIcon(url));
|
||||
}
|
||||
}
|
||||
if (listener != null) {
|
||||
addActionListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
301
src/main/java/ui/implementation/components/nav/NavBar.java
Normal file
301
src/main/java/ui/implementation/components/nav/NavBar.java
Normal file
@@ -0,0 +1,301 @@
|
||||
package ui.implementation.components.nav;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.processing.histogram.Histogramme;
|
||||
import domain.common.Mode;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.ChartFrame;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.ValueAxis;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
import presenters.NavPresenter;
|
||||
import ui.implementation.components.intent.FileChooser;
|
||||
import ui.implementation.dialogs.ImageCreatorDialog;
|
||||
import ui.implementation.dialogs.GreyScaleImageCreatorDialog;
|
||||
import ui.implementation.dialogs.RGBImageCreatorDialog;
|
||||
import ui.interfaces.INavBar;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Jean-Marc Wagner, Laurent Crema
|
||||
*/
|
||||
public class NavBar extends JMenuBar implements INavBar {
|
||||
|
||||
private JMenu imageMenu;
|
||||
private JMenu drawingMenu;
|
||||
private JMenu fourierMenu;
|
||||
private JMenu linearMenu;
|
||||
private JMenu histogramMenu;
|
||||
|
||||
private NavPresenter presenter;
|
||||
|
||||
@Inject
|
||||
public NavBar(NavPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
this.presenter.setView(this);
|
||||
initComponents();
|
||||
}
|
||||
|
||||
private void initComponents(){
|
||||
|
||||
imageMenu = new Menu("Image","/net_13_p1.jpg",
|
||||
new Menu("Nouvelle", "/file_65_p3.jpg",
|
||||
new MenuItem("RGB", e -> this.createImage(e, new RGBImageCreatorDialog(new JFrame(),true))),
|
||||
new MenuItem("NG", e -> this.createImage(e, new GreyScaleImageCreatorDialog(new JFrame(),true)))
|
||||
),
|
||||
new MenuItem("Ouvrir...", "/folder_036_p3.jpg", this::loadImage),
|
||||
new MenuItem("Enregistrer sous...","/dd_27_p3.jpg", e -> {}),
|
||||
new MenuItem("Quitter","/cp_59_p3.jpg", this::quit)
|
||||
);
|
||||
|
||||
drawingMenu = new Menu("Editer","/dd_28_p1.jpg",
|
||||
new Menu("Dessiner", "/display_14_p3.jpg",
|
||||
new MenuItem("Couleur", this::chooseColor),
|
||||
new Menu("Formes",
|
||||
new MenuItem("Pixel", e -> this.setMode(e, Mode.DRAW_PIXEL)),
|
||||
new MenuItem("Ligne", e -> this.setMode(e, Mode.DRAW_LINE)),
|
||||
new MenuItem("Rectangle",e -> this.setMode(e, Mode.DRAW_RECTANGLE)),
|
||||
new MenuItem("Cercle", e -> this.setMode(e, Mode.DRAW_CIRCLE))
|
||||
)
|
||||
),
|
||||
new Menu("Convertir",
|
||||
new MenuItem("RGB", e -> {}),
|
||||
new MenuItem("NG", e -> {})
|
||||
)
|
||||
);
|
||||
|
||||
fourierMenu = new Menu("Fourier","/cp_51_p1.jpg",
|
||||
new MenuItem("Afficher", "/cp_51_p3.jpg", this::displayFourier)
|
||||
);
|
||||
|
||||
linearMenu = new Menu("Linéaire","/cp_51_p1.jpg",
|
||||
new Menu("Global",
|
||||
new Menu("Formes",
|
||||
new MenuItem("PasseBasIdeal", e -> this.setMode(e, Mode.DRAW_PIXEL)),
|
||||
new MenuItem("PasseHautIdeal", e -> this.setMode(e, Mode.DRAW_LINE)),
|
||||
new MenuItem("PasseBasButterworth",e -> this.setMode(e, Mode.DRAW_RECTANGLE)),
|
||||
new MenuItem("PasseHautButterworth", e -> this.setMode(e, Mode.DRAW_CIRCLE))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
histogramMenu = new Menu("Histogramme","/report_48_hot.jpg",
|
||||
new MenuItem("Afficher", "/report_32_hot.jpg",this::displayHistogram)
|
||||
);
|
||||
|
||||
this.add(imageMenu);
|
||||
this.add(drawingMenu);
|
||||
this.add(fourierMenu);
|
||||
this.add(linearMenu);
|
||||
this.add(histogramMenu);
|
||||
|
||||
drawingMenu.setEnabled(false);
|
||||
fourierMenu.setEnabled(false);
|
||||
linearMenu.setEnabled(false);
|
||||
histogramMenu.setEnabled(false);
|
||||
}
|
||||
|
||||
//####################################################
|
||||
|
||||
private File chooseFile(){
|
||||
FileChooser chooser = new FileChooser("./");
|
||||
|
||||
int dialogResult = chooser.showOpenDialog(this);
|
||||
if (dialogResult != JFileChooser.APPROVE_OPTION) return null;
|
||||
|
||||
return chooser.getSelectedFile();
|
||||
}
|
||||
|
||||
private void loadImage(ActionEvent e) {
|
||||
try
|
||||
{
|
||||
File file = chooseFile();
|
||||
if(file == null) return;
|
||||
presenter.loadImage(file);
|
||||
activeMenusRGB();
|
||||
activeMenusNG();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
System.err.println("Erreur I/O : " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void quit(ActionEvent e) {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private void createImage(ActionEvent e, ImageCreatorDialog dialog) {
|
||||
dialog.setVisible(true);
|
||||
presenter.createImage(
|
||||
dialog.getRed(), dialog.getGreen(), dialog.getBlue(),
|
||||
dialog.getImageHeight(), dialog.getImageWidth());
|
||||
activeMenusRGB();
|
||||
activeMenusNG();
|
||||
}
|
||||
|
||||
private void setMode(ActionEvent e, Mode mode) {
|
||||
presenter.setMode(mode);
|
||||
}
|
||||
|
||||
private void chooseColor(ActionEvent e) {
|
||||
/*if (imageRGB != null)
|
||||
{
|
||||
Color newC = JColorChooser.showDialog(this,"Couleur du pinceau", couleurPinceauRGB);
|
||||
if (newC != null) couleurPinceauRGB = newC;
|
||||
observer.setCouleurPinceau(couleurPinceauRGB);
|
||||
}
|
||||
|
||||
if (imageNG != null)
|
||||
{
|
||||
GreyScalePicker dialog = new GreyScalePicker(new JFrame(),true, couleurPinceauNG);
|
||||
dialog.setVisible(true);
|
||||
couleurPinceauNG = dialog.getCouleur();
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
private void activeMenusNG()
|
||||
{
|
||||
drawingMenu.setEnabled(true);
|
||||
fourierMenu.setEnabled(true);
|
||||
linearMenu.setEnabled(true);
|
||||
histogramMenu.setEnabled(true);
|
||||
}
|
||||
|
||||
private void activeMenusRGB()
|
||||
{
|
||||
drawingMenu.setEnabled(true);
|
||||
fourierMenu.setEnabled(false);
|
||||
linearMenu.setEnabled(false);
|
||||
histogramMenu.setEnabled(false);
|
||||
}
|
||||
|
||||
//####################################################
|
||||
|
||||
private void displayHistogram(ActionEvent e) {
|
||||
GrayScaleMatrix i_graymatrix = presenter.getImageGrayMatrix();
|
||||
int[] histo = Histogramme.Histogramme256(i_graymatrix);
|
||||
|
||||
//Création du dataset
|
||||
XYSeries serie = new XYSeries("Histo");
|
||||
for(int i=0 ; i<256 ; i++) serie.add(i,histo[i]);
|
||||
XYSeriesCollection dataset = new XYSeriesCollection();
|
||||
dataset.addSeries(serie);
|
||||
|
||||
// Creation du chart
|
||||
JFreeChart chart = ChartFactory.createHistogram("Histogramme","Niveaux de gris",
|
||||
"Nombre de pixels", dataset, PlotOrientation.VERTICAL,false,false,false);
|
||||
|
||||
XYPlot plot = chart.getXYPlot();
|
||||
ValueAxis axeX = plot.getDomainAxis();
|
||||
axeX.setRange(0,255);
|
||||
plot.setDomainAxis(axeX);
|
||||
|
||||
// creation d'une frame
|
||||
ChartFrame frame = new ChartFrame("Histogramme de l'image",chart);
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
private void jMenuItemFourierAfficherPartieImaginaireActionPerformed(ActionEvent e) {
|
||||
// try
|
||||
// {
|
||||
// int f_int[][] = imageNG.getMatrice();
|
||||
// double f[][] = new double[imageNG.getLargeur()][imageNG.getHauteur()];
|
||||
// for(int i=0 ; i<imageNG.getLargeur() ; i++)
|
||||
// for(int j=0 ; j<imageNG.getHauteur() ; j++) f[i][j] = (double)(f_int[i][j]);
|
||||
//
|
||||
// System.out.println("Debut Fourier");
|
||||
// MatriceComplexe fourier = Fourier.Fourier2D(f);
|
||||
// System.out.println("Fin Fourier");
|
||||
// fourier = Fourier.decroise(fourier);
|
||||
// double partieImaginaire[][] = fourier.getPartieImaginaire();
|
||||
//
|
||||
// DoubleMatrix dialog = new DoubleMatrix(this,true,partieImaginaire,"Fourier : Affichage de la partie imaginaire");
|
||||
// dialog.setVisible(true);
|
||||
// }
|
||||
// catch (CImageNGException ex)
|
||||
// {
|
||||
// System.out.println("Erreur CImageNG : " + ex.getMessage());
|
||||
// }
|
||||
}
|
||||
|
||||
private void jMenuItemFourierAfficherPartieReelleActionPerformed(ActionEvent e) {
|
||||
// try
|
||||
// {
|
||||
// int f_int[][] = imageNG.getMatrice();
|
||||
// double f[][] = new double[imageNG.getLargeur()][imageNG.getHauteur()];
|
||||
// for(int i=0 ; i<imageNG.getLargeur() ; i++)
|
||||
// for(int j=0 ; j<imageNG.getHauteur() ; j++) f[i][j] = (double)(f_int[i][j]);
|
||||
//
|
||||
// System.out.println("Debut Fourier");
|
||||
// MatriceComplexe fourier = Fourier.Fourier2D(f);
|
||||
// System.out.println("Fin Fourier");
|
||||
// fourier = Fourier.decroise(fourier);
|
||||
// double partieReelle[][] = fourier.getPartieReelle();
|
||||
//
|
||||
// DoubleMatrix dialog = new DoubleMatrix(this,true,partieReelle,"Fourier : Affichage de la partie reelle");
|
||||
// dialog.setVisible(true);
|
||||
// }
|
||||
// catch (CImageNGException ex)
|
||||
// {
|
||||
// System.out.println("Erreur CImageNG : " + ex.getMessage());
|
||||
// }
|
||||
}
|
||||
|
||||
private void jMenuItemFourierAfficherPhaseActionPerformed(ActionEvent e) {
|
||||
// try
|
||||
// {
|
||||
// int f_int[][] = imageNG.getMatrice();
|
||||
// double f[][] = new double[imageNG.getLargeur()][imageNG.getHauteur()];
|
||||
// for(int i=0 ; i<imageNG.getLargeur() ; i++)
|
||||
// for(int j=0 ; j<imageNG.getHauteur() ; j++) f[i][j] = (double)(f_int[i][j]);
|
||||
//
|
||||
// System.out.println("Debut Fourier");
|
||||
// MatriceComplexe fourier = Fourier.Fourier2D(f);
|
||||
// System.out.println("Fin Fourier");
|
||||
// fourier = Fourier.decroise(fourier);
|
||||
// double phase[][] = fourier.getPhase();
|
||||
//
|
||||
// DoubleMatrix dialog = new DoubleMatrix(this,true,phase,"Fourier : Affichage de la phase");
|
||||
// dialog.setVisible(true);
|
||||
// }
|
||||
// catch (CImageNGException ex)
|
||||
// {
|
||||
// System.out.println("Erreur CImageNG : " + ex.getMessage());
|
||||
// }
|
||||
}
|
||||
|
||||
private void displayFourier(ActionEvent e) {
|
||||
try
|
||||
{
|
||||
presenter.goToFourier();
|
||||
// int f_int[][] = imageNG.getMatrice();
|
||||
// double f[][] = new double[imageNG.getLargeur()][imageNG.getHauteur()];
|
||||
// for(int i=0 ; i<imageNG.getLargeur() ; i++)
|
||||
// for(int j=0 ; j<imageNG.getHauteur() ; j++) f[i][j] = (double)(f_int[i][j]);
|
||||
//
|
||||
// System.out.println("Debut Fourier");
|
||||
// MatriceComplexe fourier = Fourier.Fourier2D(f);
|
||||
// System.out.println("Fin Fourier");
|
||||
// fourier = Fourier.decroise(fourier);
|
||||
// double module[][] = fourier.getModule();
|
||||
//
|
||||
// DoubleMatrix dialog = new DoubleMatrix(this,true,module,"Fourier : Affichage du module");
|
||||
// dialog.setVisible(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.out.println("Erreur CImageNG : " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package ui.implementation.dialogs;
|
||||
|
||||
import java.awt.Color;
|
||||
import javax.swing.*;
|
||||
|
||||
public class GreyScaleImageCreatorDialog extends ImageCreatorDialog
|
||||
{
|
||||
private JSlider slider;
|
||||
|
||||
public GreyScaleImageCreatorDialog(java.awt.Frame parent, boolean modal)
|
||||
{
|
||||
super(parent, modal);
|
||||
createColorPicker();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createColorPicker() {
|
||||
slider = new JSlider();
|
||||
slider.setValue(getValue());
|
||||
slider.setMajorTickSpacing(255);
|
||||
slider.setMaximum(255);
|
||||
slider.setMinorTickSpacing(15);
|
||||
slider.setPaintLabels(true);
|
||||
slider.setPaintTicks(true);
|
||||
slider.addChangeListener(this::jSliderStateChanged);
|
||||
colorPickerContainer.add(slider);
|
||||
}
|
||||
|
||||
private int getValue(){
|
||||
return color.getRed();
|
||||
}
|
||||
|
||||
private void jSliderStateChanged(javax.swing.event.ChangeEvent evt) {
|
||||
int value = slider.getValue();
|
||||
color = new Color(value, value, value);
|
||||
colorVisualizer.setBackground(color);
|
||||
}
|
||||
}
|
||||
122
src/main/java/ui/implementation/dialogs/GreyScalePicker.java
Normal file
122
src/main/java/ui/implementation/dialogs/GreyScalePicker.java
Normal file
@@ -0,0 +1,122 @@
|
||||
package ui.implementation.dialogs;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
public class GreyScalePicker extends javax.swing.JDialog
|
||||
{
|
||||
private int couleur;
|
||||
|
||||
/** Creates new form JDialogChoixCouleurNG */
|
||||
public GreyScalePicker(java.awt.Frame parent, boolean modal, int c)
|
||||
{
|
||||
super(parent, modal);
|
||||
couleur = c;
|
||||
|
||||
initComponents();
|
||||
couleur = c;
|
||||
jSlider.setValue(couleur);
|
||||
jPanel.setBackground(new Color(couleur,couleur,couleur));
|
||||
}
|
||||
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
jSlider = new javax.swing.JSlider();
|
||||
jPanel = new javax.swing.JPanel();
|
||||
jButtonOk = new javax.swing.JButton();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
|
||||
setTitle("Choix du niveau de gris");
|
||||
setResizable(false);
|
||||
jSlider.setMajorTickSpacing(255);
|
||||
jSlider.setMaximum(255);
|
||||
jSlider.setMinorTickSpacing(15);
|
||||
jSlider.setPaintLabels(true);
|
||||
jSlider.setPaintTicks(true);
|
||||
jSlider.addChangeListener(new javax.swing.event.ChangeListener() {
|
||||
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
||||
jSliderStateChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jPanel.setBorder(javax.swing.BorderFactory.createCompoundBorder(null, javax.swing.BorderFactory.createLineBorder(new Color(255, 0, 0))));
|
||||
javax.swing.GroupLayout jPanelLayout = new javax.swing.GroupLayout(jPanel);
|
||||
jPanel.setLayout(jPanelLayout);
|
||||
jPanelLayout.setHorizontalGroup(
|
||||
jPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 62, Short.MAX_VALUE)
|
||||
);
|
||||
jPanelLayout.setVerticalGroup(
|
||||
jPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 45, Short.MAX_VALUE)
|
||||
);
|
||||
|
||||
jButtonOk.setText("Ok");
|
||||
jButtonOk.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
jButtonOkActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(jSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(19, 19, 19)
|
||||
.addComponent(jPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 20, Short.MAX_VALUE)
|
||||
.addComponent(jButtonOk, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(jButtonOk, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 47, Short.MAX_VALUE)
|
||||
.addComponent(jPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(jSlider, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap())
|
||||
);
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void jButtonOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonOkActionPerformed
|
||||
couleur = jSlider.getValue();
|
||||
setVisible(false);
|
||||
dispose();
|
||||
}//GEN-LAST:event_jButtonOkActionPerformed
|
||||
|
||||
private void jSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSliderStateChanged
|
||||
int valeur = jSlider.getValue();
|
||||
Color c = new Color(valeur,valeur,valeur);
|
||||
jPanel.setBackground(c);
|
||||
}//GEN-LAST:event_jSliderStateChanged
|
||||
|
||||
public int getCouleur() { return couleur; }
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new GreyScalePicker(new javax.swing.JFrame(), true, 128).setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton jButtonOk;
|
||||
private javax.swing.JPanel jPanel;
|
||||
private javax.swing.JSlider jSlider;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
||||
167
src/main/java/ui/implementation/dialogs/ImageCreatorDialog.java
Normal file
167
src/main/java/ui/implementation/dialogs/ImageCreatorDialog.java
Normal file
@@ -0,0 +1,167 @@
|
||||
package ui.implementation.dialogs;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
|
||||
public abstract class ImageCreatorDialog extends JDialog
|
||||
{
|
||||
protected Color color;
|
||||
protected int height;
|
||||
protected int width;
|
||||
|
||||
protected JButton confirmButton;
|
||||
protected JPanel colorVisualizer;
|
||||
protected JComponent colorPickerContainer;
|
||||
|
||||
protected JTextField heightInput;
|
||||
protected JTextField widthInput;
|
||||
|
||||
public ImageCreatorDialog(Frame parent, boolean modal)
|
||||
{
|
||||
super(parent, modal);
|
||||
initComponents();
|
||||
|
||||
color = new Color(255,255,255);
|
||||
width = 256;
|
||||
height = 256;
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
colorVisualizer = new JPanel();
|
||||
confirmButton = new JButton();
|
||||
widthInput = new JTextField();
|
||||
heightInput = new JTextField();
|
||||
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
setTitle("Choix de la couleur");
|
||||
setResizable(false);
|
||||
|
||||
GroupLayout jPanelLayout = new GroupLayout(colorVisualizer);
|
||||
colorVisualizer.setBorder(
|
||||
BorderFactory.createCompoundBorder(null,
|
||||
BorderFactory.createLineBorder(new Color(255, 0, 0)))
|
||||
);
|
||||
colorVisualizer.setLayout(jPanelLayout);
|
||||
|
||||
jPanelLayout.setHorizontalGroup(
|
||||
jPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 62, Short.MAX_VALUE)
|
||||
);
|
||||
jPanelLayout.setVerticalGroup(
|
||||
jPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 55, Short.MAX_VALUE)
|
||||
);
|
||||
|
||||
confirmButton.setText("Ok");
|
||||
confirmButton.addActionListener(this::onConfirmClicked);
|
||||
|
||||
widthInput.setHorizontalAlignment(JTextField.CENTER);
|
||||
|
||||
heightInput.setHorizontalAlignment(JTextField.CENTER);
|
||||
|
||||
JLabel widthLabel = new JLabel("Largeur");
|
||||
JLabel heightLabel = new JLabel("Hauteur");
|
||||
|
||||
colorPickerContainer = new JPanel(new BorderLayout());
|
||||
|
||||
GroupLayout layout = new GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(27, 27, 27)
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(widthLabel)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(widthInput, GroupLayout.PREFERRED_SIZE, 97, GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(37, 37, 37)
|
||||
.addComponent(heightLabel)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(heightInput, GroupLayout.PREFERRED_SIZE, 96, GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(51, Short.MAX_VALUE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(colorVisualizer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(25, 25, 25)
|
||||
.addComponent(colorPickerContainer)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, 135, Short.MAX_VALUE)
|
||||
.addComponent(confirmButton, GroupLayout.PREFERRED_SIZE, 65, GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(26, 26, 26))))
|
||||
);
|
||||
|
||||
layout.linkSize(SwingConstants.HORIZONTAL, heightInput, widthInput);
|
||||
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGap(24, 24, 24)
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(heightInput, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(heightLabel)
|
||||
.addComponent(widthInput, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(widthLabel)
|
||||
)
|
||||
.addGap(37, 37, 37)
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(confirmButton, GroupLayout.DEFAULT_SIZE, 57, Short.MAX_VALUE)
|
||||
.addComponent(colorPickerContainer, GroupLayout.DEFAULT_SIZE, 57, Short.MAX_VALUE))
|
||||
.addComponent(colorVisualizer, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap())
|
||||
);
|
||||
pack();
|
||||
colorVisualizer.setBackground(color);
|
||||
widthInput.setText("256");
|
||||
heightInput.setText("256");
|
||||
}
|
||||
|
||||
protected void onColorChosen(ActionEvent e) {
|
||||
Color color = JColorChooser.showDialog(this,"Couleur de fond", this.color);
|
||||
if (color == null) return;
|
||||
this.color = color;
|
||||
colorVisualizer.setBackground(this.color);
|
||||
}
|
||||
|
||||
protected void onConfirmClicked(ActionEvent e) {
|
||||
try
|
||||
{
|
||||
height = Integer.parseInt(widthInput.getText());
|
||||
width = Integer.parseInt(heightInput.getText());
|
||||
|
||||
setVisible(false);
|
||||
dispose();
|
||||
} catch(NumberFormatException nfe)
|
||||
{
|
||||
JOptionPane.showMessageDialog(this,
|
||||
"Hauteur et Largeur doivent etre entiers !","Erreur",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
public Color getImageColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public int getRed() {
|
||||
return color.getRed();
|
||||
}
|
||||
|
||||
public int getGreen() {
|
||||
return color.getGreen();
|
||||
}
|
||||
|
||||
public int getBlue() {
|
||||
return color.getBlue();
|
||||
}
|
||||
|
||||
public int getImageWidth(){
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getImageHeight(){
|
||||
return height;
|
||||
}
|
||||
|
||||
protected abstract void createColorPicker();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package ui.implementation.dialogs;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
public class RGBImageCreatorDialog extends ImageCreatorDialog
|
||||
{
|
||||
|
||||
private JButton colorPickerButton;
|
||||
|
||||
public RGBImageCreatorDialog(Frame parent, boolean modal)
|
||||
{
|
||||
super(parent, modal);
|
||||
createColorPicker();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createColorPicker() {
|
||||
colorPickerButton = new JButton();
|
||||
colorPickerButton.setText("Choisir");
|
||||
colorPickerButton.addActionListener(this::onColorChosen);
|
||||
colorPickerContainer.add(colorPickerButton);
|
||||
}
|
||||
}
|
||||
374
src/main/java/ui/implementation/views/DoubleMatrix.java
Normal file
374
src/main/java/ui/implementation/views/DoubleMatrix.java
Normal file
@@ -0,0 +1,374 @@
|
||||
package ui.implementation.views;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.Image;
|
||||
import jakarta.inject.Inject;
|
||||
import presenters.DoubleMatrixPresenter;
|
||||
import ui.implementation.components.image.ImagePanel;
|
||||
import ui.implementation.components.intent.FileChooser;
|
||||
import ui.interfaces.IDoubleMatrix;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.*;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
|
||||
/**
|
||||
* @author Jean-Marc Wagner, Laurent Crema
|
||||
*/
|
||||
public class DoubleMatrix extends JFrame implements IDoubleMatrix
|
||||
{
|
||||
private double normalizedWhite;
|
||||
private double normalizedBlack;
|
||||
|
||||
private boolean isUpdating = false;
|
||||
|
||||
private JTabbedPane modeTab;
|
||||
private ImagePanel modulePreviewContainer;
|
||||
private ImagePanel phasePreviewContainer;
|
||||
private ImagePanel realPreviewContainer;
|
||||
private ImagePanel imaginaryPreviewContainer;
|
||||
|
||||
private JSlider whiteSlider;
|
||||
private JTextField whiteTextField;
|
||||
private JLabel maxLabel;
|
||||
|
||||
private JSlider blackSlider;
|
||||
private JTextField blackTextField;
|
||||
private JLabel minLabel;
|
||||
|
||||
private final DoubleMatrixPresenter presenter;
|
||||
|
||||
@Inject
|
||||
public DoubleMatrix(DoubleMatrixPresenter presenter)
|
||||
{
|
||||
this.presenter = presenter;
|
||||
initComponents();
|
||||
presenter.setView(this);
|
||||
initValues();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
|
||||
modulePreviewContainer = new ImagePanel();
|
||||
phasePreviewContainer = new ImagePanel();
|
||||
realPreviewContainer = new ImagePanel();
|
||||
imaginaryPreviewContainer = new ImagePanel();
|
||||
|
||||
blackSlider = buildSlider();
|
||||
whiteSlider = buildSlider();
|
||||
|
||||
blackTextField = buildTextField(Color.BLACK);
|
||||
whiteTextField = buildTextField(null);
|
||||
|
||||
minLabel = buildValueLabel();
|
||||
maxLabel = buildValueLabel();
|
||||
JLabel minValueText = new JLabel("Valeur MIN :");
|
||||
JLabel maxValueText = new JLabel("Valeur MAX :");
|
||||
|
||||
JButton saveButton = new JButton(new ImageIcon(Objects.requireNonNull(getClass().getResource("/dd_27_p3.jpg"))));
|
||||
saveButton.addActionListener(this::saveImage);
|
||||
|
||||
blackSlider.addChangeListener(this::onValueUpdate);
|
||||
whiteSlider.addChangeListener(this::onValueUpdate);
|
||||
|
||||
blackTextField.addActionListener(this::jTextFieldNoirActionPerformed);
|
||||
whiteTextField.addActionListener(this::jTextFieldBlancActionPerformed);
|
||||
|
||||
modeTab = buildModeTab();
|
||||
buildLayout(modeTab, maxValueText, minValueText, minLabel, maxLabel, saveButton);
|
||||
|
||||
setTitle("Fourier");
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
pack();
|
||||
}
|
||||
|
||||
private void initValues(){
|
||||
modeTab.setSelectedIndex(1);
|
||||
|
||||
blackSlider.setValue(0);
|
||||
whiteSlider.setValue(1000);
|
||||
}
|
||||
|
||||
private JSlider buildSlider() {
|
||||
return new JSlider(JSlider.VERTICAL);
|
||||
}
|
||||
|
||||
private JTextField buildTextField(Color background) {
|
||||
JTextField field = new JTextField();
|
||||
field.setFont(new Font("Tahoma", Font.BOLD, 11));
|
||||
field.setForeground(Color.RED);
|
||||
field.setHorizontalAlignment(JTextField.CENTER);
|
||||
if (background != null) field.setBackground(background);
|
||||
return field;
|
||||
}
|
||||
|
||||
private JLabel buildValueLabel() {
|
||||
JLabel label = new JLabel("0.0");
|
||||
label.setFont(new Font("Tahoma", Font.BOLD, 11));
|
||||
label.setForeground(Color.BLUE);
|
||||
return label;
|
||||
}
|
||||
|
||||
private JTabbedPane buildModeTab(){
|
||||
|
||||
JTabbedPane modeTabs = new JTabbedPane();
|
||||
modeTabs.addTab("Module", modulePreviewContainer);
|
||||
modeTabs.addTab("Phase", phasePreviewContainer);
|
||||
modeTabs.addTab("Partie réelle", realPreviewContainer);
|
||||
modeTabs.addTab("Partie imaginaire", imaginaryPreviewContainer);
|
||||
modeTabs.addChangeListener(e -> {
|
||||
switch (modeTabs.getSelectedIndex()) {
|
||||
case 0 -> presenter.loadModule();
|
||||
case 1 -> presenter.loadPhase();
|
||||
case 2 -> presenter.loadReal();
|
||||
case 3 -> presenter.loadImaginary();
|
||||
}
|
||||
});
|
||||
return modeTabs;
|
||||
}
|
||||
|
||||
private void buildLayout(JTabbedPane modeTab,
|
||||
JLabel labelMax, JLabel labelMin,
|
||||
JLabel valeurMin, JLabel valeurMax,
|
||||
JButton saveButton) {
|
||||
|
||||
JPanel rightPanel = new JPanel();
|
||||
GroupLayout rightLayout = new GroupLayout(rightPanel);
|
||||
rightPanel.setLayout(rightLayout);
|
||||
|
||||
rightLayout.setHorizontalGroup(
|
||||
rightLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addComponent(whiteTextField, GroupLayout.PREFERRED_SIZE, 90, GroupLayout.PREFERRED_SIZE)
|
||||
.addGroup(rightLayout.createSequentialGroup()
|
||||
.addComponent(blackSlider)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(whiteSlider)
|
||||
)
|
||||
.addComponent(blackTextField, GroupLayout.PREFERRED_SIZE, 90, GroupLayout.PREFERRED_SIZE)
|
||||
);
|
||||
|
||||
rightLayout.setVerticalGroup(
|
||||
rightLayout.createSequentialGroup()
|
||||
.addComponent(whiteTextField, GroupLayout.PREFERRED_SIZE,
|
||||
GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
|
||||
.addComponent(blackSlider)
|
||||
.addComponent(whiteSlider)
|
||||
)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(blackTextField, GroupLayout.PREFERRED_SIZE,
|
||||
GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||
);
|
||||
|
||||
// -------------------------
|
||||
// MAIN LAYOUT
|
||||
// -------------------------
|
||||
GroupLayout layout = new GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
|
||||
// TOP BAR
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(labelMin)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(valeurMin)
|
||||
.addGap(50)
|
||||
.addComponent(labelMax)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(valeurMax)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED,
|
||||
GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(saveButton)
|
||||
.addContainerGap()
|
||||
)
|
||||
|
||||
// MAIN ROW
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(rightPanel, GroupLayout.PREFERRED_SIZE,
|
||||
GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap()
|
||||
)
|
||||
);
|
||||
|
||||
layout.setVerticalGroup(
|
||||
layout.createSequentialGroup()
|
||||
|
||||
// TOP BAR
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(labelMin)
|
||||
.addComponent(valeurMin)
|
||||
.addComponent(labelMax)
|
||||
.addComponent(valeurMax)
|
||||
.addComponent(saveButton)
|
||||
)
|
||||
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
|
||||
// MAIN CONTENT
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addComponent(modeTab)
|
||||
.addComponent(rightPanel)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private File chooseFile(){
|
||||
FileChooser chooser = new FileChooser("./");
|
||||
|
||||
int dialogResult = chooser.showOpenDialog(this);
|
||||
if (dialogResult != JFileChooser.APPROVE_OPTION) return null;
|
||||
|
||||
return chooser.getSelectedFile();
|
||||
}
|
||||
|
||||
private void onValueUpdate(ChangeEvent e) {
|
||||
if (isUpdating) return;
|
||||
isUpdating = true;
|
||||
|
||||
try {
|
||||
int black = blackSlider.getValue();
|
||||
int white = whiteSlider.getValue();
|
||||
|
||||
int minGap = 1;
|
||||
if (white - black < minGap) {
|
||||
if (blackSlider.getValueIsAdjusting()) {
|
||||
black = white - minGap;
|
||||
blackSlider.setValue(black);
|
||||
} else {
|
||||
white = black + minGap;
|
||||
whiteSlider.setValue(white);
|
||||
}
|
||||
}
|
||||
|
||||
normalizedBlack = (double) black / blackSlider.getMaximum();
|
||||
normalizedWhite = (double) white / whiteSlider.getMaximum();
|
||||
|
||||
switch (modeTab.getSelectedIndex()) {
|
||||
case 0 -> presenter.clipModule(normalizedBlack, normalizedWhite);
|
||||
case 1 -> presenter.clipPhase(normalizedBlack, normalizedWhite);
|
||||
case 2 -> presenter.clipReal(normalizedBlack, normalizedWhite);
|
||||
case 3 -> presenter.clipImaginary(normalizedBlack, normalizedWhite);
|
||||
}
|
||||
|
||||
} finally {
|
||||
isUpdating = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateModule(GrayScaleMatrix source, GrayScaleMatrix clipped) {
|
||||
updatePreview(modulePreviewContainer, source, clipped);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePhase(GrayScaleMatrix source, GrayScaleMatrix clipped) {
|
||||
updatePreview(phasePreviewContainer, source, clipped);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateReal(GrayScaleMatrix source, GrayScaleMatrix clipped) {
|
||||
updatePreview(realPreviewContainer, source, clipped);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateImaginary(GrayScaleMatrix source, GrayScaleMatrix clipped) {
|
||||
updatePreview(imaginaryPreviewContainer, source, clipped);
|
||||
}
|
||||
|
||||
private void updatePreview(ImagePanel imagePanel, GrayScaleMatrix source, GrayScaleMatrix matrix) {
|
||||
try {
|
||||
imagePanel.loadImage(matrix);
|
||||
updateLabels(source.getMinValue(), source.getMaxValue());
|
||||
updateTextFields(
|
||||
presenter.getValueAt(source, normalizedBlack),
|
||||
presenter.getValueAt(source, normalizedWhite)
|
||||
);
|
||||
} catch (Exception e){
|
||||
displayErrorMessage("Oups !", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTextFields(double black, double white) {
|
||||
blackTextField.setText(String.format("%.5f", black));
|
||||
whiteTextField.setText(String.format("%.5f", white));
|
||||
}
|
||||
|
||||
private void updateLabels(double black, double white) {
|
||||
minLabel.setText(String.format("%.5f", black));
|
||||
maxLabel.setText(String.format("%.5f", white));
|
||||
}
|
||||
|
||||
private void saveImage(ActionEvent evt) {
|
||||
|
||||
File file = chooseFile();
|
||||
if (file != null) {
|
||||
try {
|
||||
presenter.saveImage(null);
|
||||
//image.enregistreFormatPNG(fichier);
|
||||
} catch (IOException ex) {
|
||||
System.err.println("Erreur I/O : " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void displayErrorMessage(String title, String message) {
|
||||
JOptionPane.showMessageDialog(
|
||||
this,
|
||||
message,
|
||||
title,
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
}
|
||||
|
||||
private void jTextFieldNoirActionPerformed(ActionEvent evt) {
|
||||
// double val = Double.parseDouble(jTextFieldNoir.getText());
|
||||
//
|
||||
// double black = presenter.getBlackLevel();
|
||||
// double white = presenter.getWhiteLevel();
|
||||
//
|
||||
// if (val < black)
|
||||
// {
|
||||
// jSliderNoir.setValue(0);
|
||||
// return;
|
||||
// }
|
||||
// if (val >= normalizedWhite)
|
||||
// {
|
||||
// jSliderNoir.setValue(jSliderBlanc.getValue()-1);
|
||||
// return;
|
||||
// }
|
||||
// int s = (int)((double)D*(val-black)/(white-black)+0.5);
|
||||
// jSliderNoir.setValue(s);
|
||||
|
||||
}
|
||||
|
||||
private void jTextFieldBlancActionPerformed(ActionEvent evt) {
|
||||
// double val = Double.parseDouble(jTextFieldBlanc.getText());
|
||||
// double black = presenter.getBlackLevel();
|
||||
// double white = presenter.getWhiteLevel();
|
||||
//
|
||||
// if (val > white)
|
||||
// {
|
||||
// jSliderBlanc.setValue(D);
|
||||
// return;
|
||||
// }
|
||||
// if (val <= normalizedBlack)
|
||||
// {
|
||||
// jSliderBlanc.setValue(jSliderNoir.getValue()+1);
|
||||
// return;
|
||||
// }
|
||||
// int s = (int)((double)D*(val-black)/(white-black)+0.5);
|
||||
// jSliderBlanc.setValue(s);
|
||||
}
|
||||
}
|
||||
201
src/main/java/ui/implementation/views/MainView.java
Normal file
201
src/main/java/ui/implementation/views/MainView.java
Normal file
@@ -0,0 +1,201 @@
|
||||
package ui.implementation.views;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import domain.common.Mode;
|
||||
import domain.image.Image;
|
||||
import infrastructure.ui.ImageMapper;
|
||||
import presenters.MainPresenter;
|
||||
import ui.implementation.components.image.ImagePanel;
|
||||
import ui.implementation.components.nav.NavBar;
|
||||
import ui.interfaces.IMainView;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionAdapter;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* @author Jean-Marc Wagner, Laurent Crema
|
||||
*/
|
||||
public class MainView extends JFrame implements IMainView
|
||||
{
|
||||
private Mode currentMode;
|
||||
private ImagePanel imagePreviewContainer;
|
||||
private final MainPresenter presenter;
|
||||
|
||||
@Inject
|
||||
public MainView(MainPresenter presenter){
|
||||
this.presenter = presenter;
|
||||
this.presenter.setView(this);
|
||||
initComponents();
|
||||
}
|
||||
|
||||
public void setNavBar(NavBar navBar) {
|
||||
setJMenuBar(navBar);
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
imagePreviewContainer = new ImagePanel();
|
||||
|
||||
imagePreviewContainer.addMouseMotionListener(new MouseMotionAdapter() {
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
drawPixel(e.getX(), e.getY(), 255, 0, 0);
|
||||
}
|
||||
});
|
||||
|
||||
imagePreviewContainer.addMouseListener(new MouseAdapter() {
|
||||
|
||||
private Point startPoint;
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
startPoint = new Point(e.getX(), e.getY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
Point endPoint = new Point(e.getX(), e.getY());
|
||||
if (startPoint == null) return;
|
||||
|
||||
drawShape(
|
||||
startPoint.x,
|
||||
endPoint.x,
|
||||
startPoint.y,
|
||||
endPoint.y,
|
||||
255, 0, 0
|
||||
);
|
||||
|
||||
startPoint = null;
|
||||
}
|
||||
});
|
||||
|
||||
GroupLayout layout = new GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(imagePreviewContainer)
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(imagePreviewContainer)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
setSize(new Dimension(500, 400));
|
||||
setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
public void drawPixel(int x, int y, int red, int green, int blue){
|
||||
try {
|
||||
Point p = imagePreviewContainer.toImageCoordinates(x, y);
|
||||
if(p == null) return;
|
||||
presenter.drawPixel((int)p.getX(), (int)p.getY(), red, green, blue);
|
||||
} catch (Exception e) {
|
||||
displayErrorMessage("Oups !",
|
||||
"Impossible de dessiner sur l'image pour le moment : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void drawShape(int x1, int x2, int y1, int y2, int red, int green, int blue){
|
||||
try {
|
||||
Point p1 = imagePreviewContainer.toImageCoordinates(x1, y1);
|
||||
Point p2 = imagePreviewContainer.toImageCoordinates(x2, y2);
|
||||
if(p1 == null || p2 == null) return;
|
||||
presenter.drawShape(
|
||||
(int)p1.getX(), (int)p2.getX(), (int) p1.getY(), (int) p2.getY(),
|
||||
red, green, blue);
|
||||
|
||||
} catch (Exception e) {
|
||||
displayErrorMessage("Oups !",
|
||||
"Impossible de dessiner sur l'image pour le moment : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// public void SelectCercleDetected(DeuxClicsEvent e)
|
||||
// {
|
||||
// if (presenter.isCircleModeActive())
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// if (imageRGB != null)
|
||||
// imageRGB.DessineCercle(e.getX1(),e.getY1(),e.getX2(),e.getY2(),couleurPinceauRGB);
|
||||
// if (imageNG != null)
|
||||
// imageNG.DessineCercle(e.getX1(),e.getY1(),e.getX2(),e.getY2(),couleurPinceauNG);
|
||||
// }
|
||||
// catch (CImageRGBException ex)
|
||||
// { System.out.println("Erreur RGB : " + ex.getMessage()); }
|
||||
// catch (CImageNGException ex)
|
||||
// { System.out.println("Erreur NG : " + ex.getMessage()); }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void SelectCercleFillDetected(DeuxClicsEvent e)
|
||||
// {
|
||||
// if (presenter.isPlainCircleModeActive())
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// if (imageRGB != null)
|
||||
// imageRGB.RemplitCercle(e.getX1(),e.getY1(),e.getX2(),e.getY2(),couleurPinceauRGB);
|
||||
// if (imageNG != null)
|
||||
// imageNG.RemplitCercle(e.getX1(),e.getY1(),e.getX2(),e.getY2(),couleurPinceauNG);
|
||||
// }
|
||||
// catch (CImageRGBException ex)
|
||||
// { System.out.println("Erreur RGB : " + ex.getMessage()); }
|
||||
// catch (CImageNGException ex)
|
||||
// { System.out.println("Erreur NG : " + ex.getMessage()); }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void SelectRectFillDetected(DeuxClicsEvent e)
|
||||
// {
|
||||
// if (presenter.isPlainRectangleActive())
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// if (imageRGB != null)
|
||||
// imageRGB.RemplitRect(e.getX1(),e.getY1(),e.getX2(),e.getY2(),couleurPinceauRGB);
|
||||
// if (imageNG != null)
|
||||
// imageNG.RemplitRect(e.getX1(),e.getY1(),e.getX2(),e.getY2(),couleurPinceauNG);
|
||||
// }
|
||||
// catch (CImageRGBException ex)
|
||||
// { System.out.println("Erreur RGB : " + ex.getMessage()); }
|
||||
// catch (CImageNGException ex)
|
||||
// { System.out.println("Erreur NG : " + ex.getMessage()); }
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void displayImage(Image image) {
|
||||
try {
|
||||
BufferedImage bufferedImage = ImageMapper.toBufferedImage(image);
|
||||
imagePreviewContainer.loadImage(bufferedImage);
|
||||
} catch (Exception ex) {
|
||||
displayErrorMessage("Oups !", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeMode(Mode m) {
|
||||
|
||||
}
|
||||
|
||||
private void displayErrorMessage(String title, String message) {
|
||||
JOptionPane.showMessageDialog(
|
||||
this,
|
||||
message,
|
||||
title,
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
11
src/main/java/ui/interfaces/IDoubleMatrix.java
Normal file
11
src/main/java/ui/interfaces/IDoubleMatrix.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package ui.interfaces;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
|
||||
public interface IDoubleMatrix {
|
||||
|
||||
void updateModule(GrayScaleMatrix source, GrayScaleMatrix clipped);
|
||||
void updatePhase(GrayScaleMatrix source, GrayScaleMatrix clipped);
|
||||
void updateReal(GrayScaleMatrix source, GrayScaleMatrix clipped);
|
||||
void updateImaginary(GrayScaleMatrix source, GrayScaleMatrix clipped);
|
||||
}
|
||||
15
src/main/java/ui/interfaces/IMainView.java
Normal file
15
src/main/java/ui/interfaces/IMainView.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package ui.interfaces;
|
||||
|
||||
import domain.common.Mode;
|
||||
import domain.image.Image;
|
||||
import presenters.DoubleMatrixPresenter;
|
||||
import presenters.MainPresenter;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public interface IMainView {
|
||||
|
||||
void changeMode(Mode m);
|
||||
void displayImage(Image image);
|
||||
|
||||
}
|
||||
8
src/main/java/ui/interfaces/INavBar.java
Normal file
8
src/main/java/ui/interfaces/INavBar.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package ui.interfaces;
|
||||
|
||||
import presenters.NavPresenter;
|
||||
|
||||
public interface INavBar {
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user