Update architecture
This commit is contained in:
@@ -5,14 +5,14 @@ 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.FilteringPresenter;
|
||||
import presenters.doubleMatrix.DoubleMatrixPresenter;
|
||||
import presenters.filtering.FilteringPresenter;
|
||||
import presenters.MainPresenter;
|
||||
import presenters.NavPresenter;
|
||||
import services.ImageService;
|
||||
import ui.implementation.components.nav.NavBar;
|
||||
import ui.implementation.views.DoubleMatrix;
|
||||
import ui.implementation.views.FilteringView;
|
||||
import ui.implementation.views.IdealFilteringView;
|
||||
import ui.implementation.views.MainView;
|
||||
import ui.abstractions.IDoubleMatrix;
|
||||
import ui.abstractions.IFilteringView;
|
||||
@@ -40,7 +40,7 @@ public class AppModule extends AbstractModule {
|
||||
bind(INavBar.class).to(NavBar.class);
|
||||
bind(IMainView.class).to(MainView.class);
|
||||
bind(IDoubleMatrix.class).to(DoubleMatrix.class);
|
||||
bind(IFilteringView.class).to(FilteringView.class);
|
||||
bind(IFilteringView.class).to(IdealFilteringView.class);
|
||||
|
||||
//--- Presentation layer ---
|
||||
bind(MainPresenter.class);
|
||||
|
||||
@@ -3,11 +3,9 @@ package app;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import ui.implementation.views.DoubleMatrix;
|
||||
import ui.implementation.views.FilteringView;
|
||||
import ui.implementation.views.IdealFilteringView;
|
||||
import ui.implementation.views.ViewInitializer;
|
||||
|
||||
import javax.swing.text.View;
|
||||
|
||||
/**
|
||||
* Concrete implement of the INavigator interface.
|
||||
* Implements abstract endpoints to displays views in a Swing way
|
||||
@@ -16,12 +14,12 @@ import javax.swing.text.View;
|
||||
public class SwingNavigator implements INavigator {
|
||||
|
||||
private final Provider<DoubleMatrix> doubleMatrixProvider;
|
||||
private final Provider<FilteringView> filteringProvider;
|
||||
private final Provider<IdealFilteringView> filteringProvider;
|
||||
|
||||
@Inject
|
||||
public SwingNavigator(
|
||||
Provider<DoubleMatrix> doubleMatrixProvider,
|
||||
Provider<FilteringView> filteringProvider
|
||||
Provider<IdealFilteringView> filteringProvider
|
||||
) {
|
||||
this.doubleMatrixProvider = doubleMatrixProvider;
|
||||
this.filteringProvider = filteringProvider;
|
||||
@@ -36,7 +34,7 @@ public class SwingNavigator implements INavigator {
|
||||
|
||||
@Override
|
||||
public void showFiltering() {
|
||||
FilteringView filteringView = filteringProvider.get();
|
||||
IdealFilteringView filteringView = filteringProvider.get();
|
||||
ViewInitializer.Initialize(filteringView);
|
||||
filteringView.setVisible(true);
|
||||
}
|
||||
|
||||
@@ -6,35 +6,47 @@ import com.google.inject.Singleton;
|
||||
import domain.common.Mode;
|
||||
import domain.events.ImageChangedEvent;
|
||||
import domain.events.ModeChangedEvent;
|
||||
import domain.events.listeners.Listener;
|
||||
import domain.image.Image;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the global state of the app
|
||||
*/
|
||||
@Singleton
|
||||
public class AppState extends State {
|
||||
|
||||
private Mode mode;
|
||||
private Image rgbImage;
|
||||
private final List<AppStateListener> listeners = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
public AppState(EventBus eventBus) {
|
||||
super(eventBus);
|
||||
public AppState() {}
|
||||
|
||||
public void subscribe(AppStateListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void unsubscribe(AppStateListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
public void setMode(Mode mode) {
|
||||
this.mode = mode;
|
||||
this.eventBus.post(new ModeChangedEvent(mode));
|
||||
listeners.forEach(listener -> listener.onModeChanged(mode));
|
||||
}
|
||||
|
||||
public void setImage(Image image) {
|
||||
this.rgbImage = image;
|
||||
this.eventBus.post(new ImageChangedEvent(image));
|
||||
listeners.forEach(listener -> listener.onImageChanged(image));
|
||||
}
|
||||
|
||||
public Image getImage(){
|
||||
return this.rgbImage;
|
||||
public Image getImage() {
|
||||
return rgbImage;
|
||||
}
|
||||
|
||||
public Mode getMode() { return this.mode; }
|
||||
public Mode getMode() {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
9
src/main/java/app/state/AppStateListener.java
Normal file
9
src/main/java/app/state/AppStateListener.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package app.state;
|
||||
|
||||
import domain.common.Mode;
|
||||
import domain.image.Image;
|
||||
|
||||
public interface AppStateListener {
|
||||
void onModeChanged(Mode mode);
|
||||
void onImageChanged(Image image);
|
||||
}
|
||||
@@ -1,22 +1,32 @@
|
||||
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;
|
||||
import presenters.doubleMatrix.DoubleMatrixListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DoubleMatrixState extends State {
|
||||
|
||||
private ComplexMatrix fourier;
|
||||
private GrayScaleMatrix module;
|
||||
private GrayScaleMatrix phase;
|
||||
private GrayScaleMatrix real;
|
||||
private GrayScaleMatrix imaginary;
|
||||
|
||||
private final List<DoubleMatrixListener> listeners = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
public DoubleMatrixState() { super(new EventBus()); }
|
||||
public DoubleMatrixState() {}
|
||||
|
||||
public void subscribe(DoubleMatrixListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void unsubscribe(DoubleMatrixListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
public ComplexMatrix getFourier() {
|
||||
return fourier;
|
||||
@@ -24,26 +34,42 @@ public class DoubleMatrixState extends State {
|
||||
|
||||
public void setFourier(ComplexMatrix fourier) {
|
||||
this.fourier = fourier;
|
||||
this.eventBus.post(new ComplexMatrixChanged(fourier));
|
||||
listeners.forEach(listener -> listener.onFourierChanged(fourier));
|
||||
}
|
||||
|
||||
public void setModule(GrayScaleMatrix matrix) {
|
||||
this.module = matrix;
|
||||
this.eventBus.post(new ModuleChangedEvent(matrix));
|
||||
listeners.forEach(listener -> listener.onModuleChanged(matrix));
|
||||
}
|
||||
|
||||
public void setPhase(GrayScaleMatrix matrix) {
|
||||
this.phase = matrix;
|
||||
this.eventBus.post(new PhaseChangedEvent(matrix));
|
||||
listeners.forEach(listener -> listener.onPhaseChanged(matrix));
|
||||
}
|
||||
|
||||
public void setReal(GrayScaleMatrix matrix) {
|
||||
this.real = matrix;
|
||||
this.eventBus.post(new RealChangedEvent(matrix));
|
||||
listeners.forEach(listener -> listener.onRealChanged(matrix));
|
||||
}
|
||||
|
||||
public void setImaginary(GrayScaleMatrix matrix) {
|
||||
this.imaginary = matrix;
|
||||
this.eventBus.post(new ImaginaryChangedEvent(matrix));
|
||||
listeners.forEach(listener -> listener.onImaginaryChanged(matrix));
|
||||
}
|
||||
|
||||
public GrayScaleMatrix getModule() {
|
||||
return module;
|
||||
}
|
||||
|
||||
public GrayScaleMatrix getPhase() {
|
||||
return phase;
|
||||
}
|
||||
|
||||
public GrayScaleMatrix getReal() {
|
||||
return real;
|
||||
}
|
||||
|
||||
public GrayScaleMatrix getImaginary() {
|
||||
return imaginary;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,64 @@
|
||||
package app.state;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.Inject;
|
||||
import domain.events.filtering.HighPassChangedEvent;
|
||||
import domain.events.filtering.LowPassChangedEvent;
|
||||
import domain.events.fourier.ModuleChangedEvent;
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.Image;
|
||||
import presenters.filtering.FilteringListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FilteringState extends State {
|
||||
|
||||
private Image lowPass;
|
||||
private Image highPass;
|
||||
private Image butterworthLowPass;
|
||||
private Image butterworthHighPass;
|
||||
|
||||
private final List<FilteringListener> listeners = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
public FilteringState() { super(new EventBus()); }
|
||||
public FilteringState() {}
|
||||
|
||||
public void subscribe(FilteringListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void unsubscribe(FilteringListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
public void setLowPass(Image image) {
|
||||
this.eventBus.post(new LowPassChangedEvent(image));
|
||||
lowPass = image;
|
||||
listeners.forEach(listener -> listener.onLowPassChanged(image));
|
||||
}
|
||||
|
||||
public void setHighPass(Image image) {
|
||||
this.eventBus.post(new HighPassChangedEvent(image));
|
||||
highPass = image;
|
||||
listeners.forEach(listener -> listener.onHighPassChanged(image));
|
||||
}
|
||||
|
||||
public void setButterworthLowPass(Image image) {
|
||||
butterworthLowPass = image;
|
||||
listeners.forEach(listener -> listener.onButterworthLowPassChanged(image));
|
||||
}
|
||||
|
||||
public void setButterworthHighPass(Image image) {
|
||||
butterworthHighPass = image;
|
||||
listeners.forEach(listener -> listener.onButterworthHighPassChanged(image));
|
||||
}
|
||||
|
||||
public Image getLowPass() {
|
||||
return lowPass;
|
||||
}
|
||||
|
||||
public Image getHighPass() {
|
||||
return highPass;
|
||||
}
|
||||
|
||||
public Image getButterworthLowPass() {
|
||||
return butterworthLowPass;
|
||||
}
|
||||
|
||||
public Image getButterworthHighPass() {
|
||||
return butterworthHighPass;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,10 @@ package app.state;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Represents any states that could ever exist.
|
||||
* In order to notify the caller about any change made to internal properties of a children state, the caller
|
||||
@@ -9,18 +13,4 @@ import com.google.common.eventbus.EventBus;
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public abstract class State {
|
||||
|
||||
protected EventBus eventBus;
|
||||
|
||||
public State(EventBus eventBus) {
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the caller so it can be notifed from changes within the state
|
||||
* @param obj the caller itself
|
||||
*/
|
||||
public void register(Object obj) {
|
||||
eventBus.register(obj);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package domain.events.filtering;
|
||||
|
||||
import domain.image.Image;
|
||||
|
||||
public record HighPassChangedEvent(Image image) { }
|
||||
@@ -1,5 +0,0 @@
|
||||
package domain.events.filtering;
|
||||
|
||||
import domain.image.Image;
|
||||
|
||||
public record LowPassChangedEvent(Image image) { }
|
||||
5
src/main/java/domain/events/listeners/Listener.java
Normal file
5
src/main/java/domain/events/listeners/Listener.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package domain.events.listeners;
|
||||
|
||||
public interface Listener {
|
||||
|
||||
}
|
||||
@@ -13,136 +13,96 @@ import java.util.List;
|
||||
public class GlobalLinearFiltering {
|
||||
|
||||
public static GrayScaleMatrix lowPassFiltering(GrayScaleMatrix matrix, double cutoff) {
|
||||
|
||||
int width = matrix.getWidth();
|
||||
int height = matrix.getHeight();
|
||||
|
||||
double minCutoff = 0;
|
||||
double maxCutoff = Math.sqrt(Math.pow(width / 2.0, 2) + Math.pow(height / 2.0, 2));
|
||||
validateCutoff(cutoff, width, height);
|
||||
|
||||
if(cutoff < minCutoff || cutoff > maxCutoff){
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cutoff value is out of bond (%f - %f)", minCutoff, maxCutoff)
|
||||
);
|
||||
Mat mat = toMat(matrix);
|
||||
Mat spectrum = fourierTransform(mat);
|
||||
|
||||
shiftSpectrum(spectrum);
|
||||
applyIdealLowPassFilter(spectrum, cutoff);
|
||||
shiftSpectrum(spectrum);
|
||||
|
||||
Mat filtered = inverseFourierTransform(spectrum);
|
||||
|
||||
return toGrayScaleMatrix(filtered);
|
||||
}
|
||||
|
||||
Mat mat = new Mat(height, width, CvType.CV_64F);
|
||||
public static GrayScaleMatrix highPassFiltering(GrayScaleMatrix matrix, double cutoff) {
|
||||
int width = matrix.getWidth();
|
||||
int height = matrix.getHeight();
|
||||
|
||||
double[][] data = matrix.getRawData();
|
||||
validateCutoff(cutoff, width, height);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
mat.put(y, 0, data[y]);
|
||||
Mat mat = toMat(matrix);
|
||||
Mat spectrum = fourierTransform(mat);
|
||||
|
||||
shiftSpectrum(spectrum);
|
||||
applyIdealHighPassFilter(spectrum, cutoff);
|
||||
shiftSpectrum(spectrum);
|
||||
|
||||
Mat filtered = inverseFourierTransform(spectrum);
|
||||
|
||||
return toGrayScaleMatrix(filtered);
|
||||
}
|
||||
|
||||
// Fourier transform
|
||||
Mat spectrum = new Mat();
|
||||
Core.dft(mat, spectrum, Core.DFT_COMPLEX_OUTPUT);
|
||||
public static GrayScaleMatrix butterworthLowPassFiltering(GrayScaleMatrix matrix, double cutoff, int order) {
|
||||
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
|
||||
|
||||
Mat spectrum = fourierTransform(toMat(matrix));
|
||||
|
||||
shiftSpectrum(spectrum);
|
||||
applyButterworthLowPassFilter(spectrum, cutoff, order);
|
||||
shiftSpectrum(spectrum);
|
||||
|
||||
return toGrayScaleMatrix(inverseFourierTransform(spectrum));
|
||||
}
|
||||
|
||||
public static GrayScaleMatrix butterworthHighPassFiltering(GrayScaleMatrix matrix, double cutoff, int order) {
|
||||
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
|
||||
|
||||
Mat spectrum = fourierTransform(toMat(matrix));
|
||||
|
||||
shiftSpectrum(spectrum);
|
||||
applyButterworthHighPassFilter(spectrum, cutoff, order);
|
||||
shiftSpectrum(spectrum);
|
||||
|
||||
return toGrayScaleMatrix(inverseFourierTransform(spectrum));
|
||||
}
|
||||
|
||||
private static void applyIdealLowPassFilter(Mat spectrum, double cutoff) {
|
||||
int width = spectrum.cols();
|
||||
int height = spectrum.rows();
|
||||
|
||||
// Shift zero frequency to the center
|
||||
int cx = width / 2;
|
||||
int cy = height / 2;
|
||||
|
||||
Mat q0 = spectrum.submat(0, cy, 0, cx);
|
||||
Mat q1 = spectrum.submat(0, cy, cx, width);
|
||||
Mat q2 = spectrum.submat(cy, height, 0, cx);
|
||||
Mat q3 = spectrum.submat(cy, height, cx, width);
|
||||
|
||||
Mat tmp = new Mat();
|
||||
|
||||
q0.copyTo(tmp);
|
||||
q3.copyTo(q0);
|
||||
tmp.copyTo(q3);
|
||||
|
||||
q1.copyTo(tmp);
|
||||
q2.copyTo(q1);
|
||||
tmp.copyTo(q2);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
|
||||
|
||||
double distance = Math.sqrt(
|
||||
Math.pow(x - cx, 2) + Math.pow(y - cy, 2)
|
||||
);
|
||||
|
||||
if (distance > cutoff) {
|
||||
spectrum.put(y, x, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shift back
|
||||
q0.copyTo(tmp);
|
||||
q3.copyTo(q0);
|
||||
tmp.copyTo(q3);
|
||||
|
||||
q1.copyTo(tmp);
|
||||
q2.copyTo(q1);
|
||||
tmp.copyTo(q2);
|
||||
|
||||
// Inverse Fourier transform
|
||||
Mat filtered = new Mat();
|
||||
|
||||
Core.idft(
|
||||
spectrum,
|
||||
filtered,
|
||||
Core.DFT_REAL_OUTPUT | Core.DFT_SCALE
|
||||
);
|
||||
|
||||
// Convert result back to your Image
|
||||
double[][] pixels = new double[height][width];
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
pixels[y][x] = Math.clamp(filtered.get(y, x)[0], 0.0, 255.0);
|
||||
}
|
||||
}
|
||||
|
||||
return new GrayScaleMatrix(pixels);
|
||||
}
|
||||
private static void applyIdealHighPassFilter(Mat spectrum, double cutoff) {
|
||||
int width = spectrum.cols();
|
||||
int height = spectrum.rows();
|
||||
|
||||
public static GrayScaleMatrix highPassFiltering(GrayScaleMatrix matrix, double cutoff){
|
||||
int width = matrix.getWidth();
|
||||
int height = matrix.getHeight();
|
||||
|
||||
double minCutoff = 0;
|
||||
double maxCutoff = Math.sqrt(Math.pow(width / 2.0, 2) + Math.pow(height / 2.0, 2));
|
||||
|
||||
if(cutoff < minCutoff || cutoff > maxCutoff){
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cutoff value is out of bond (%f - %f)", minCutoff, maxCutoff)
|
||||
);
|
||||
}
|
||||
|
||||
Mat mat = new Mat(height, width, CvType.CV_64F);
|
||||
|
||||
double[][] data = matrix.getRawData();
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
mat.put(y, 0, data[y]);
|
||||
}
|
||||
|
||||
// Fourier transform
|
||||
Mat spectrum = new Mat();
|
||||
Core.dft(mat, spectrum, Core.DFT_COMPLEX_OUTPUT);
|
||||
|
||||
// Shift zero frequency to the center
|
||||
int cx = width / 2;
|
||||
int cy = height / 2;
|
||||
|
||||
Mat q0 = spectrum.submat(0, cy, 0, cx);
|
||||
Mat q1 = spectrum.submat(0, cy, cx, width);
|
||||
Mat q2 = spectrum.submat(cy, height, 0, cx);
|
||||
Mat q3 = spectrum.submat(cy, height, cx, width);
|
||||
|
||||
Mat tmp = new Mat();
|
||||
|
||||
q0.copyTo(tmp);
|
||||
q3.copyTo(q0);
|
||||
tmp.copyTo(q3);
|
||||
|
||||
q1.copyTo(tmp);
|
||||
q2.copyTo(q1);
|
||||
tmp.copyTo(q2);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
|
||||
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
|
||||
|
||||
if (distance <= cutoff) {
|
||||
@@ -150,8 +110,94 @@ public class GlobalLinearFiltering {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyButterworthLowPassFilter(Mat spectrum, double cutoff, int order) {
|
||||
int width = spectrum.cols();
|
||||
int height = spectrum.rows();
|
||||
|
||||
int cx = width / 2;
|
||||
int cy = height / 2;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
|
||||
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2) );
|
||||
|
||||
double coefficient = 1.0 / (1.0 + Math.pow(distance / cutoff, 2 * order));
|
||||
|
||||
double[] value = spectrum.get(y, x);
|
||||
|
||||
spectrum.put(y, x, value[0] * coefficient, value[1] * coefficient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyButterworthHighPassFilter(Mat spectrum, double cutoff, int order) {
|
||||
int width = spectrum.cols();
|
||||
int height = spectrum.rows();
|
||||
|
||||
int cx = width / 2;
|
||||
int cy = height / 2;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
|
||||
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
|
||||
|
||||
double coefficient;
|
||||
|
||||
if (distance == 0) {
|
||||
coefficient = 0;
|
||||
} else {
|
||||
coefficient = 1.0 / (1.0 + Math.pow(cutoff / distance, 2 * order));
|
||||
}
|
||||
|
||||
double[] value = spectrum.get(y, x);
|
||||
|
||||
spectrum.put(y, x, value[0] * coefficient, value[1] * coefficient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateCutoff(double cutoff, int width, int height) {
|
||||
double minCutoff = 0;
|
||||
double maxCutoff = Math.sqrt(
|
||||
Math.pow(width / 2.0, 2) +
|
||||
Math.pow(height / 2.0, 2)
|
||||
);
|
||||
|
||||
if (cutoff < minCutoff || cutoff > maxCutoff) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Cutoff value is out of bounds (%f - %f)",
|
||||
minCutoff,
|
||||
maxCutoff
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static Mat fourierTransform(Mat mat) {
|
||||
Mat spectrum = new Mat();
|
||||
Core.dft(mat, spectrum, Core.DFT_COMPLEX_OUTPUT);
|
||||
return spectrum;
|
||||
}
|
||||
|
||||
private static void shiftSpectrum(Mat spectrum) {
|
||||
int width = spectrum.cols();
|
||||
int height = spectrum.rows();
|
||||
|
||||
int cx = width / 2;
|
||||
int cy = height / 2;
|
||||
|
||||
Mat q0 = spectrum.submat(0, cy, 0, cx);
|
||||
Mat q1 = spectrum.submat(0, cy, cx, width);
|
||||
Mat q2 = spectrum.submat(cy, height, 0, cx);
|
||||
Mat q3 = spectrum.submat(cy, height, cx, width);
|
||||
|
||||
Mat tmp = new Mat();
|
||||
|
||||
// Shift back
|
||||
q0.copyTo(tmp);
|
||||
q3.copyTo(q0);
|
||||
tmp.copyTo(q3);
|
||||
@@ -159,8 +205,9 @@ public class GlobalLinearFiltering {
|
||||
q1.copyTo(tmp);
|
||||
q2.copyTo(q1);
|
||||
tmp.copyTo(q2);
|
||||
}
|
||||
|
||||
// Inverse Fourier transform
|
||||
private static Mat inverseFourierTransform(Mat spectrum) {
|
||||
Mat filtered = new Mat();
|
||||
|
||||
Core.idft(
|
||||
@@ -169,23 +216,41 @@ public class GlobalLinearFiltering {
|
||||
Core.DFT_REAL_OUTPUT | Core.DFT_SCALE
|
||||
);
|
||||
|
||||
// Convert result back to your Image
|
||||
return filtered;
|
||||
}
|
||||
|
||||
private static GrayScaleMatrix toGrayScaleMatrix(Mat filtered) {
|
||||
int width = filtered.cols();
|
||||
int height = filtered.rows();
|
||||
|
||||
double[][] pixels = new double[height][width];
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
pixels[y][x] = Math.clamp(filtered.get(y, x)[0], 0.0, 255.0);
|
||||
pixels[y][x] = Math.clamp(
|
||||
filtered.get(y, x)[0],
|
||||
0.0,
|
||||
255.0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new GrayScaleMatrix(pixels);
|
||||
}
|
||||
|
||||
public static void butterworthLowPassFiltering(){
|
||||
private static Mat toMat(GrayScaleMatrix matrix) {
|
||||
int width = matrix.getWidth();
|
||||
int height = matrix.getHeight();
|
||||
|
||||
Mat mat = new Mat(height, width, CvType.CV_64F);
|
||||
|
||||
double[][] data = matrix.getRawData();
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
mat.put(y, 0, data[y]);
|
||||
}
|
||||
|
||||
public static void butterworthHighPassFiltering(){
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package presenters;
|
||||
|
||||
import app.state.FilteringState;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.inject.Inject;
|
||||
import domain.events.filtering.HighPassChangedEvent;
|
||||
import domain.events.filtering.LowPassChangedEvent;
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.Image;
|
||||
import services.FilteringService;
|
||||
import services.ImageService;
|
||||
import ui.abstractions.IFilteringView;
|
||||
|
||||
public class FilteringPresenter {
|
||||
|
||||
private final FilteringState state;
|
||||
private final ImageService imageService;
|
||||
private final FilteringService filteringService;
|
||||
private IFilteringView view;
|
||||
|
||||
@Inject
|
||||
public FilteringPresenter(FilteringState state, ImageService imageService, FilteringService filteringService) {
|
||||
this.state = state;
|
||||
this.state.register(this);
|
||||
|
||||
this.imageService = imageService;
|
||||
this.filteringService = filteringService;
|
||||
}
|
||||
|
||||
public void setView(IFilteringView view){
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public void computeLowPassFiltering(int percentage){
|
||||
GrayScaleMatrix matrix = imageService.getGrayScale();
|
||||
Image image = filteringService.lowPassFiltering(matrix, (double) percentage /100);
|
||||
this.state.setLowPass(image);
|
||||
}
|
||||
|
||||
public void computeHighPassFiltering(int percentage){
|
||||
GrayScaleMatrix matrix = imageService.getGrayScale();
|
||||
Image image = filteringService.highPassFiltering(matrix, (double) percentage /100);
|
||||
this.state.setHighPass(image);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onLowPassUpdate(LowPassChangedEvent event){
|
||||
view.updateLowPassFiltering(event.image());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onHighPassUpdate(HighPassChangedEvent event){
|
||||
view.updateHighPassFiltering(event.image());
|
||||
}
|
||||
}
|
||||
@@ -1,67 +1,63 @@
|
||||
package presenters;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import app.state.AppState;
|
||||
import app.state.AppStateListener;
|
||||
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.abstractions.IMainView;
|
||||
|
||||
/**
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public class MainPresenter {
|
||||
|
||||
public class MainPresenter implements AppStateListener {
|
||||
private IMainView view;
|
||||
private final AppState appState;
|
||||
private final ModeService modeService;
|
||||
private final ImageService imageService;
|
||||
|
||||
@Inject
|
||||
public MainPresenter(ModeService modeService, ImageService imageService, EventBus eventBus) {
|
||||
public MainPresenter(AppState appState, ModeService modeService, ImageService imageService) {
|
||||
this.appState = appState;
|
||||
this.modeService = modeService;
|
||||
this.imageService = imageService;
|
||||
eventBus.register(this);
|
||||
this.appState.subscribe(this);
|
||||
}
|
||||
|
||||
public void setView(IMainView view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onImageChanged(ImageChangedEvent e){
|
||||
view.displayImage(e.image());
|
||||
@Override
|
||||
public void onImageChanged(Image image) {
|
||||
view.displayImage(image);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onModeChanged(ModeChangedEvent e){
|
||||
view.changeMode(e.mode());
|
||||
@Override
|
||||
public void onModeChanged(Mode mode) {
|
||||
view.changeMode(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();
|
||||
public void drawPixel(int x, int y, int red, int green, int blue) {
|
||||
if (modeService.getMode() != Mode.DRAW_PIXEL) return;
|
||||
|
||||
Image image = appState.getImage();
|
||||
image.setPixelColor(x, y, red, green, blue);
|
||||
imageService.setImage(image);
|
||||
appState.setImage(image);
|
||||
}
|
||||
|
||||
public void drawShape(int x1, int x2, int y1, int y2, int red, int green, int blue){
|
||||
Image image = imageService.getImage();
|
||||
public void drawShape(int x1, int x2, int y1, int y2, int red, int green, int blue) {
|
||||
Image image = appState.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);
|
||||
case DRAW_RECTANGLE -> image.setRectangleColor(x1, x2, y1, y2, red, green, blue);
|
||||
case DRAW_LINE -> image.setLineColor(x1, x2, y1, y2, red, green, blue);
|
||||
case DRAW_CIRCLE -> {}
|
||||
}
|
||||
|
||||
appState.setImage(image);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
appState.unsubscribe(this);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package presenters;
|
||||
|
||||
import app.INavigator;
|
||||
import app.state.AppState;
|
||||
import com.google.inject.Inject;
|
||||
import domain.common.Mode;
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.Image;
|
||||
import services.ImageService;
|
||||
import services.ModeService;
|
||||
import ui.abstractions.INavBar;
|
||||
@@ -11,19 +13,17 @@ import ui.abstractions.INavBar;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public class NavPresenter {
|
||||
|
||||
private INavBar navBar;
|
||||
private INavigator navigator;
|
||||
private final INavigator navigator;
|
||||
private final AppState appState;
|
||||
private final ImageService imageService;
|
||||
private final ModeService modeService;
|
||||
|
||||
@Inject
|
||||
public NavPresenter(INavigator navigator, ImageService imageService, ModeService modeService) {
|
||||
public NavPresenter(INavigator navigator, AppState appState, ImageService imageService, ModeService modeService) {
|
||||
this.navigator = navigator;
|
||||
this.appState = appState;
|
||||
this.imageService = imageService;
|
||||
this.modeService = modeService;
|
||||
}
|
||||
@@ -33,24 +33,25 @@ public class NavPresenter {
|
||||
}
|
||||
|
||||
public void createImage(int red, int green, int blue, int height, int width) {
|
||||
imageService.createImage(red, green, blue, height, width);
|
||||
Image image = imageService.createImage(red, green, blue, height, width);
|
||||
appState.setImage(image);
|
||||
}
|
||||
|
||||
public void loadImage(File f) throws IOException {
|
||||
imageService.loadImage(f);
|
||||
public void loadImage(File file) throws IOException {
|
||||
Image image = imageService.loadImage(file);
|
||||
appState.setImage(image);
|
||||
}
|
||||
|
||||
public void goToFourier(){
|
||||
public void goToFourier() {
|
||||
navigator.showFourier();
|
||||
}
|
||||
|
||||
public void goToFiltering(){
|
||||
public void goToFiltering() {
|
||||
navigator.showFiltering();
|
||||
}
|
||||
|
||||
public GrayScaleMatrix getImageGrayMatrix() {
|
||||
//return ((CImageNG)appState.getImage()).getMatrice();
|
||||
return imageService.getImage().toGrayScale();
|
||||
return appState.getImage().toGrayScale();
|
||||
}
|
||||
|
||||
public void setMode(Mode mode) {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package presenters.doubleMatrix;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.processing.complex.ComplexMatrix;
|
||||
|
||||
public interface DoubleMatrixListener {
|
||||
void onFourierChanged(ComplexMatrix fourier);
|
||||
void onModuleChanged(GrayScaleMatrix matrix);
|
||||
void onPhaseChanged(GrayScaleMatrix matrix);
|
||||
void onRealChanged(GrayScaleMatrix matrix);
|
||||
void onImaginaryChanged(GrayScaleMatrix matrix);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package presenters;
|
||||
package presenters.doubleMatrix;
|
||||
|
||||
import app.state.AppState;
|
||||
import app.state.DoubleMatrixState;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.inject.Inject;
|
||||
@@ -18,25 +19,26 @@ import java.io.IOException;
|
||||
/**
|
||||
* @author Laurent Crema
|
||||
*/
|
||||
public class DoubleMatrixPresenter {
|
||||
|
||||
public class DoubleMatrixPresenter implements DoubleMatrixListener {
|
||||
private IDoubleMatrix view;
|
||||
private final AppState appState;
|
||||
private final DoubleMatrixState state;
|
||||
private final ImageService imageService;
|
||||
|
||||
@Inject
|
||||
public DoubleMatrixPresenter(ImageService imageService, DoubleMatrixState state) {
|
||||
public DoubleMatrixPresenter(AppState appState, ImageService imageService, DoubleMatrixState state) {
|
||||
this.appState = appState;
|
||||
this.imageService = imageService;
|
||||
this.state = state;
|
||||
this.state.register(this);
|
||||
this.state.subscribe(this);
|
||||
}
|
||||
|
||||
public void setView(IDoubleMatrix view){
|
||||
public void setView(IDoubleMatrix view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public void saveImage(Image image) throws IOException {
|
||||
this.imageService.saveImage(image);
|
||||
imageService.saveImage(image);
|
||||
}
|
||||
|
||||
public void loadModule(){
|
||||
@@ -87,28 +89,32 @@ public class DoubleMatrixPresenter {
|
||||
state.setImaginary(matrix);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onModuleUpdate(ModuleChangedEvent event) {
|
||||
@Override
|
||||
public void onModuleChanged(GrayScaleMatrix matrix) {
|
||||
GrayScaleMatrix module = new GrayScaleMatrix(getFourier().getModule());
|
||||
view.updateModule(module, event.matrix());
|
||||
view.updateModule(module, matrix);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPhaseUpdate(PhaseChangedEvent event) {
|
||||
@Override
|
||||
public void onPhaseChanged(GrayScaleMatrix matrix) {
|
||||
GrayScaleMatrix phase = new GrayScaleMatrix(getFourier().getPhase());
|
||||
view.updatePhase(phase, event.matrix());
|
||||
view.updatePhase(phase, matrix);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onRealUpdate(RealChangedEvent event) {
|
||||
@Override
|
||||
public void onRealChanged(GrayScaleMatrix matrix) {
|
||||
GrayScaleMatrix real = new GrayScaleMatrix(getFourier().getPartieReelle());
|
||||
view.updateReal(real, event.matrix());
|
||||
view.updateReal(real, matrix);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onImaginaryUpdate(ImaginaryChangedEvent event) {
|
||||
@Override
|
||||
public void onFourierChanged(ComplexMatrix fourier) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImaginaryChanged(GrayScaleMatrix matrix) {
|
||||
GrayScaleMatrix imaginary = new GrayScaleMatrix(getFourier().getPartieImaginaire());
|
||||
view.updateImaginary(imaginary, event.matrix());
|
||||
view.updateImaginary(imaginary, matrix);
|
||||
}
|
||||
|
||||
private GrayScaleMatrix clip(GrayScaleMatrix matrix, double black, double white){
|
||||
@@ -119,7 +125,7 @@ public class DoubleMatrixPresenter {
|
||||
|
||||
private ComplexMatrix getFourier() {
|
||||
if (state.getFourier() == null) {
|
||||
state.setFourier(imageService.computeFourier());
|
||||
state.setFourier(imageService.computeFourier(appState.getImage()));
|
||||
}
|
||||
return state.getFourier();
|
||||
}
|
||||
11
src/main/java/presenters/filtering/FilteringListener.java
Normal file
11
src/main/java/presenters/filtering/FilteringListener.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package presenters.filtering;
|
||||
|
||||
import domain.events.listeners.Listener;
|
||||
import domain.image.Image;
|
||||
|
||||
public interface FilteringListener extends Listener {
|
||||
void onLowPassChanged(Image image);
|
||||
void onHighPassChanged(Image image);
|
||||
void onButterworthLowPassChanged(Image image);
|
||||
void onButterworthHighPassChanged(Image image);
|
||||
}
|
||||
79
src/main/java/presenters/filtering/FilteringPresenter.java
Normal file
79
src/main/java/presenters/filtering/FilteringPresenter.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package presenters.filtering;
|
||||
|
||||
import app.state.AppState;
|
||||
import app.state.FilteringState;
|
||||
import com.google.inject.Inject;
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.Image;
|
||||
import services.FilteringService;
|
||||
import services.ImageService;
|
||||
import ui.abstractions.IFilteringView;
|
||||
|
||||
public class FilteringPresenter implements FilteringListener {
|
||||
private final AppState appState;
|
||||
private final FilteringState state;
|
||||
private final ImageService imageService;
|
||||
private final FilteringService filteringService;
|
||||
private IFilteringView view;
|
||||
|
||||
@Inject
|
||||
public FilteringPresenter(AppState appState, FilteringState state, ImageService imageService, FilteringService filteringService) {
|
||||
this.appState = appState;
|
||||
this.state = state;
|
||||
this.imageService = imageService;
|
||||
this.filteringService = filteringService;
|
||||
this.state.subscribe(this);
|
||||
}
|
||||
|
||||
public void setView(IFilteringView view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public void computeLowPassFiltering(float percentage) {
|
||||
GrayScaleMatrix matrix = imageService.getGrayScale(appState.getImage());
|
||||
Image image = filteringService.lowPassFiltering(matrix, percentage / 100);
|
||||
state.setLowPass(image);
|
||||
}
|
||||
|
||||
public void computeHighPassFiltering(float percentage) {
|
||||
GrayScaleMatrix matrix = imageService.getGrayScale(appState.getImage());
|
||||
Image image = filteringService.highPassFiltering(matrix, percentage / 100);
|
||||
state.setHighPass(image);
|
||||
}
|
||||
|
||||
public void computeButterworthLowPassFiltering(float percentage) {
|
||||
GrayScaleMatrix matrix = imageService.getGrayScale(appState.getImage());
|
||||
Image image = filteringService.butterworthLowPassFiltering(matrix, percentage / 100);
|
||||
state.setButterworthLowPass(image);
|
||||
}
|
||||
|
||||
public void computeButterworthHighPassFiltering(float percentage) {
|
||||
GrayScaleMatrix matrix = imageService.getGrayScale(appState.getImage());
|
||||
Image image = filteringService.butterworthHighPassFiltering(matrix, percentage / 100);
|
||||
state.setButterworthHighPass(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowPassChanged(Image image) {
|
||||
view.updateLowPassFiltering(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHighPassChanged(Image image) {
|
||||
view.updateHighPassFiltering(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onButterworthLowPassChanged(Image image) {
|
||||
view.updateButterworthLowPassFiltering(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onButterworthHighPassChanged(Image image) {
|
||||
view.updateButterworthHighPassFiltering(image);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
state.unsubscribe(this);
|
||||
}
|
||||
}
|
||||
@@ -22,4 +22,11 @@ public class FilteringService {
|
||||
return Math.sqrt(Math.pow(width / 2.0, 2) + Math.pow(height / 2.0, 2));
|
||||
}
|
||||
|
||||
public Image butterworthLowPassFiltering(GrayScaleMatrix matrix, float v) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Image butterworthHighPassFiltering(GrayScaleMatrix matrix, float v) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package services;
|
||||
|
||||
import app.state.AppState;
|
||||
import com.google.inject.Inject;
|
||||
import domain.image.Image;
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import domain.image.Image;
|
||||
import domain.image.processing.complex.ComplexMatrix;
|
||||
import domain.image.processing.fourier.Fourier;
|
||||
import infrastructure.image.io.ImageLoader;
|
||||
@@ -17,42 +15,25 @@ import java.io.IOException;
|
||||
*/
|
||||
public class ImageService {
|
||||
|
||||
private final AppState appState;
|
||||
|
||||
@Inject
|
||||
public ImageService(AppState appState) {
|
||||
this.appState = appState;
|
||||
public Image createImage(int red, int green, int blue, int height, int width) {
|
||||
return new Image(red, green, blue, height, width);
|
||||
}
|
||||
|
||||
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 Image loadImage(File file) throws IOException {
|
||||
return ImageLoader.loadImage(file);
|
||||
}
|
||||
|
||||
public void saveImage(Image image) throws IOException {
|
||||
ImageSaver.saveImage(image);
|
||||
}
|
||||
|
||||
public ComplexMatrix computeFourier(){
|
||||
GrayScaleMatrix matrix = appState.getImage().toGrayScale();
|
||||
public ComplexMatrix computeFourier(Image image) {
|
||||
GrayScaleMatrix matrix = image.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();
|
||||
public GrayScaleMatrix getGrayScale(Image image) {
|
||||
return image.toGrayScale();
|
||||
}
|
||||
}
|
||||
@@ -5,4 +5,11 @@ import javax.swing.*;
|
||||
public abstract class AbstractView extends JFrame {
|
||||
public abstract void initComponents();
|
||||
public abstract void initValues();
|
||||
public abstract void disposeCore();
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposeCore();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package ui.implementation.components.controls;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class IntensitySlider extends JSlider {
|
||||
|
||||
public IntensitySlider() {
|
||||
super();
|
||||
setMinimum(0);
|
||||
setMaximum(1000);
|
||||
}
|
||||
|
||||
public float getPercentage(){
|
||||
return (float) getValue() /10;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package ui.implementation.components.button;
|
||||
package ui.implementation.components.controls;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.net.URL;
|
||||
@@ -0,0 +1,29 @@
|
||||
package ui.implementation.components.image;
|
||||
|
||||
import domain.image.Image;
|
||||
import infrastructure.ui.ImageMapper;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TabbedImagePanel extends JTabbedPane {
|
||||
|
||||
private final Map<String, ImagePanel> tabs;
|
||||
|
||||
public TabbedImagePanel() {
|
||||
this.tabs = new HashMap<>();
|
||||
}
|
||||
|
||||
public void addPreviewTab(String title) {
|
||||
ImagePanel panel = new ImagePanel();
|
||||
tabs.put(title, panel);
|
||||
addTab(title, panel);
|
||||
}
|
||||
|
||||
public void loadImage(String title, Image image) {
|
||||
BufferedImage bufferedImage = ImageMapper.toBufferedImage(image);
|
||||
tabs.get(title).loadImage(bufferedImage);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package ui.implementation.views;
|
||||
|
||||
import domain.image.GrayScaleMatrix;
|
||||
import jakarta.inject.Inject;
|
||||
import presenters.DoubleMatrixPresenter;
|
||||
import presenters.doubleMatrix.DoubleMatrixPresenter;
|
||||
import ui.abstractions.AbstractView;
|
||||
import ui.implementation.components.button.SaveButton;
|
||||
import ui.implementation.components.controls.SaveButton;
|
||||
import ui.implementation.components.image.ImagePanel;
|
||||
import ui.implementation.components.intent.FileChooser;
|
||||
import ui.abstractions.IDoubleMatrix;
|
||||
@@ -96,6 +96,11 @@ public class DoubleMatrix extends AbstractView implements IDoubleMatrix
|
||||
this.whiteTextField.addActionListener(this::jTextFieldBlancActionPerformed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeCore() {
|
||||
this.presenter.setView(null);
|
||||
}
|
||||
|
||||
private JSlider buildSlider() {
|
||||
return new JSlider(JSlider.VERTICAL);
|
||||
}
|
||||
|
||||
@@ -2,39 +2,42 @@ package ui.implementation.views;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import domain.image.Image;
|
||||
import infrastructure.ui.ImageMapper;
|
||||
import presenters.FilteringPresenter;
|
||||
import presenters.filtering.FilteringPresenter;
|
||||
import ui.abstractions.AbstractView;
|
||||
import ui.implementation.components.button.SaveButton;
|
||||
import ui.implementation.components.image.ImagePanel;
|
||||
import ui.implementation.components.controls.IntensitySlider;
|
||||
import ui.implementation.components.controls.SaveButton;
|
||||
import ui.abstractions.IFilteringView;
|
||||
import ui.implementation.components.image.TabbedImagePanel;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
|
||||
public class FilteringView extends AbstractView implements IFilteringView {
|
||||
public class IdealFilteringView extends AbstractView implements IFilteringView {
|
||||
|
||||
private ImagePanel lowPassContainer;
|
||||
private ImagePanel highPassContainer;
|
||||
private JTabbedPane modeTab;
|
||||
private JSlider intensitySlider;
|
||||
private final static String LOW_PASS_TAB_TITLE = "Passe-haut";
|
||||
private final static String HIGH_PASS_TAB_TITLE = "Passe-bas";
|
||||
|
||||
private TabbedImagePanel modeTab;
|
||||
private IntensitySlider intensitySlider;
|
||||
private JLabel intensityLabel;
|
||||
private final FilteringPresenter presenter;
|
||||
private boolean isUpdating;
|
||||
|
||||
@Inject
|
||||
public FilteringView(FilteringPresenter presenter) {
|
||||
public IdealFilteringView(FilteringPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initComponents(){
|
||||
this.lowPassContainer = new ImagePanel();
|
||||
this.highPassContainer = new ImagePanel();
|
||||
this.modeTab = buildModeTab();
|
||||
this.intensitySlider = new JSlider(0,100,0);
|
||||
this.intensitySlider.setOrientation(JSlider.VERTICAL);
|
||||
this.intensityLabel = new JLabel();
|
||||
this.intensitySlider = new IntensitySlider();
|
||||
this.intensitySlider.setOrientation(JSlider.VERTICAL);
|
||||
|
||||
this.modeTab = new TabbedImagePanel();
|
||||
this.modeTab.addPreviewTab(LOW_PASS_TAB_TITLE);
|
||||
this.modeTab.addPreviewTab(HIGH_PASS_TAB_TITLE);
|
||||
|
||||
JButton saveButton = new SaveButton();
|
||||
|
||||
saveButton.addActionListener(e -> {});
|
||||
@@ -45,33 +48,7 @@ public class FilteringView extends AbstractView implements IFilteringView {
|
||||
pack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initValues(){
|
||||
this.presenter.setView(this);
|
||||
|
||||
this.intensitySlider.setMinimum(0);
|
||||
this.intensitySlider.setMaximum(100);
|
||||
this.intensitySlider.setValue(50);
|
||||
this.intensitySlider.addChangeListener(this::onCutoffUpdate);
|
||||
|
||||
this.intensityLabel.setText(String.valueOf(intensitySlider.getValue()));
|
||||
|
||||
this.modeTab.addChangeListener(e -> {
|
||||
switch (modeTab.getSelectedIndex()) {
|
||||
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getValue());
|
||||
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
this.presenter.computeLowPassFiltering(intensitySlider.getValue());
|
||||
}
|
||||
|
||||
private JTabbedPane buildModeTab(){
|
||||
JTabbedPane modeTabs = new JTabbedPane();
|
||||
modeTabs.addTab("Passe-bas", lowPassContainer);
|
||||
modeTabs.addTab("Passe-haut", highPassContainer);
|
||||
return modeTabs;
|
||||
}
|
||||
|
||||
private void buildLayout(JTabbedPane modeTab,
|
||||
JLabel valueTextField,
|
||||
@@ -158,10 +135,10 @@ public class FilteringView extends AbstractView implements IFilteringView {
|
||||
if (isUpdating) return;
|
||||
isUpdating = true;
|
||||
try {
|
||||
this.intensityLabel.setText(String.valueOf(intensitySlider.getValue()));
|
||||
this.intensityLabel.setText(String.valueOf(intensitySlider.getPercentage()));
|
||||
switch (modeTab.getSelectedIndex()) {
|
||||
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getValue());
|
||||
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getValue());
|
||||
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getPercentage());
|
||||
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getPercentage());
|
||||
}
|
||||
} finally {
|
||||
isUpdating = false;
|
||||
@@ -170,12 +147,12 @@ public class FilteringView extends AbstractView implements IFilteringView {
|
||||
|
||||
@Override
|
||||
public void updateLowPassFiltering(Image image) {
|
||||
lowPassContainer.loadImage(ImageMapper.toBufferedImage(image));
|
||||
modeTab.loadImage(LOW_PASS_TAB_TITLE, image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateHighPassFiltering(Image image) {
|
||||
highPassContainer.loadImage(ImageMapper.toBufferedImage(image));
|
||||
modeTab.loadImage(HIGH_PASS_TAB_TITLE, image);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -187,4 +164,27 @@ public class FilteringView extends AbstractView implements IFilteringView {
|
||||
public void updateButterworthLowPassFiltering(Image image) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initValues(){
|
||||
this.presenter.setView(this);
|
||||
|
||||
this.intensitySlider.addChangeListener(this::onCutoffUpdate);
|
||||
this.intensityLabel.setText(String.valueOf(intensitySlider.getValue()));
|
||||
|
||||
this.modeTab.addChangeListener(e -> {
|
||||
switch (modeTab.getSelectedIndex()) {
|
||||
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getPercentage());
|
||||
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getPercentage());
|
||||
}
|
||||
});
|
||||
|
||||
this.presenter.computeLowPassFiltering(intensitySlider.getPercentage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeCore() {
|
||||
this.presenter.setView(null);
|
||||
this.presenter.dispose();
|
||||
}
|
||||
}
|
||||
190
src/main/java/ui/implementation/views/NonIdealFilteringView.java
Normal file
190
src/main/java/ui/implementation/views/NonIdealFilteringView.java
Normal file
@@ -0,0 +1,190 @@
|
||||
package ui.implementation.views;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import domain.image.Image;
|
||||
import presenters.filtering.FilteringPresenter;
|
||||
import ui.abstractions.AbstractView;
|
||||
import ui.abstractions.IFilteringView;
|
||||
import ui.implementation.components.controls.IntensitySlider;
|
||||
import ui.implementation.components.controls.SaveButton;
|
||||
import ui.implementation.components.image.TabbedImagePanel;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
|
||||
public class NonIdealFilteringView extends AbstractView implements IFilteringView {
|
||||
|
||||
private final static String LOW_PASS_TAB_TITLE = "Passe-haut";
|
||||
private final static String HIGH_PASS_TAB_TITLE = "Passe-bas";
|
||||
|
||||
private TabbedImagePanel modeTab;
|
||||
private IntensitySlider intensitySlider;
|
||||
private JLabel intensityLabel;
|
||||
private final FilteringPresenter presenter;
|
||||
private boolean isUpdating;
|
||||
|
||||
@Inject
|
||||
public NonIdealFilteringView(FilteringPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void buildLayout(JTabbedPane modeTab,
|
||||
JLabel valueTextField,
|
||||
JSlider intensitySlider,
|
||||
JButton saveButton) {
|
||||
|
||||
JPanel rightPanel = new JPanel();
|
||||
GroupLayout rightLayout = new GroupLayout(rightPanel);
|
||||
rightPanel.setLayout(rightLayout);
|
||||
|
||||
rightLayout.setHorizontalGroup(
|
||||
rightLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addComponent(valueTextField, GroupLayout.PREFERRED_SIZE, 90, GroupLayout.PREFERRED_SIZE)
|
||||
.addGroup(rightLayout.createSequentialGroup()
|
||||
.addComponent(intensitySlider)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
)
|
||||
);
|
||||
|
||||
rightLayout.setVerticalGroup(
|
||||
rightLayout.createSequentialGroup()
|
||||
.addComponent(valueTextField, GroupLayout.PREFERRED_SIZE,
|
||||
GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
|
||||
.addComponent(intensitySlider)
|
||||
)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
);
|
||||
|
||||
// -------------------------
|
||||
// MAIN LAYOUT
|
||||
// -------------------------
|
||||
GroupLayout layout = new GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
|
||||
// TOP BAR
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
//.addComponent(valeurMin)
|
||||
.addGap(50)
|
||||
.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(saveButton)
|
||||
)
|
||||
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
|
||||
// MAIN CONTENT
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addComponent(modeTab)
|
||||
.addComponent(rightPanel)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private void onCutoffUpdate(ChangeEvent e) {
|
||||
if (isUpdating) return;
|
||||
isUpdating = true;
|
||||
try {
|
||||
this.intensityLabel.setText(String.valueOf(intensitySlider.getPercentage()));
|
||||
switch (modeTab.getSelectedIndex()) {
|
||||
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getPercentage());
|
||||
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getPercentage());
|
||||
}
|
||||
} finally {
|
||||
isUpdating = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLowPassFiltering(Image image) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateHighPassFiltering(Image image) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateButterworthHighPassFiltering(Image image) {
|
||||
modeTab.loadImage(LOW_PASS_TAB_TITLE, image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateButterworthLowPassFiltering(Image image) {
|
||||
modeTab.loadImage(HIGH_PASS_TAB_TITLE, image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initComponents(){
|
||||
this.intensityLabel = new JLabel();
|
||||
this.intensitySlider = new IntensitySlider();
|
||||
this.intensitySlider.setOrientation(JSlider.VERTICAL);
|
||||
|
||||
this.modeTab = new TabbedImagePanel();
|
||||
this.modeTab.addPreviewTab(LOW_PASS_TAB_TITLE);
|
||||
this.modeTab.addPreviewTab(HIGH_PASS_TAB_TITLE);
|
||||
|
||||
JButton saveButton = new SaveButton();
|
||||
|
||||
saveButton.addActionListener(e -> {});
|
||||
|
||||
buildLayout(modeTab, intensityLabel, intensitySlider, saveButton);
|
||||
setTitle("Filtering");
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
pack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initValues(){
|
||||
this.presenter.setView(this);
|
||||
|
||||
this.intensitySlider.addChangeListener(this::onCutoffUpdate);
|
||||
this.intensityLabel.setText(String.valueOf(intensitySlider.getValue()));
|
||||
|
||||
this.modeTab.addChangeListener(e -> {
|
||||
switch (modeTab.getSelectedIndex()) {
|
||||
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getPercentage());
|
||||
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getPercentage());
|
||||
}
|
||||
});
|
||||
|
||||
this.presenter.computeLowPassFiltering(intensitySlider.getPercentage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeCore() {
|
||||
this.presenter.setView(null);
|
||||
this.presenter.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user