Add basic and complex morphologies
This commit is contained in:
@@ -13,4 +13,5 @@ public interface INavigator {
|
|||||||
void showIdealFiltering();
|
void showIdealFiltering();
|
||||||
void showButterworth();
|
void showButterworth();
|
||||||
void showConvolutionFiltering();
|
void showConvolutionFiltering();
|
||||||
|
void showBasicMorphology();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package app;
|
|||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
|
import ui.abstractions.AbstractView;
|
||||||
import ui.implementation.views.DoubleMatrix;
|
import ui.implementation.views.DoubleMatrix;
|
||||||
import ui.implementation.views.fitering.global.IdealFilteringView;
|
import ui.implementation.views.fitering.global.IdealFilteringView;
|
||||||
import ui.implementation.views.fitering.global.NonIdealFilteringView;
|
import ui.implementation.views.fitering.global.NonIdealFilteringView;
|
||||||
import ui.implementation.views.ViewInitializer;
|
import ui.implementation.views.ViewInitializer;
|
||||||
import ui.implementation.views.fitering.local.LocalFilteringView;
|
import ui.implementation.views.fitering.local.LocalFilteringView;
|
||||||
|
import ui.implementation.views.morphology.BasicMorphologyView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Concrete implement of the INavigator interface.
|
* Concrete implement of the INavigator interface.
|
||||||
@@ -19,46 +21,55 @@ public class SwingNavigator implements INavigator {
|
|||||||
private final Provider<IdealFilteringView> filteringProvider;
|
private final Provider<IdealFilteringView> filteringProvider;
|
||||||
private final Provider<NonIdealFilteringView> nonIdealFilteringProvider;
|
private final Provider<NonIdealFilteringView> nonIdealFilteringProvider;
|
||||||
private final Provider<LocalFilteringView> convolutionFilteringProvider;
|
private final Provider<LocalFilteringView> convolutionFilteringProvider;
|
||||||
|
private final Provider<BasicMorphologyView> basicMorphologyProvider;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public SwingNavigator(
|
public SwingNavigator(
|
||||||
Provider<DoubleMatrix> doubleMatrixProvider,
|
Provider<DoubleMatrix> doubleMatrixProvider,
|
||||||
Provider<IdealFilteringView> filteringProvider,
|
Provider<IdealFilteringView> filteringProvider,
|
||||||
Provider<NonIdealFilteringView> nonIdealFilteringProvider,
|
Provider<NonIdealFilteringView> nonIdealFilteringProvider,
|
||||||
Provider<LocalFilteringView> convolutionFilterProvider
|
Provider<LocalFilteringView> convolutionFilterProvider,
|
||||||
|
Provider<BasicMorphologyView> basicMorphologyProvider
|
||||||
) {
|
) {
|
||||||
this.doubleMatrixProvider = doubleMatrixProvider;
|
this.doubleMatrixProvider = doubleMatrixProvider;
|
||||||
this.filteringProvider = filteringProvider;
|
this.filteringProvider = filteringProvider;
|
||||||
this.nonIdealFilteringProvider = nonIdealFilteringProvider;
|
this.nonIdealFilteringProvider = nonIdealFilteringProvider;
|
||||||
this.convolutionFilteringProvider = convolutionFilterProvider;
|
this.convolutionFilteringProvider = convolutionFilterProvider;
|
||||||
|
this.basicMorphologyProvider = basicMorphologyProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showFourier() {
|
public void showFourier() {
|
||||||
DoubleMatrix view = doubleMatrixProvider.get();
|
DoubleMatrix view = doubleMatrixProvider.get();
|
||||||
ViewInitializer.Initialize(view);
|
runView(view);
|
||||||
view.setVisible(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showIdealFiltering() {
|
public void showIdealFiltering() {
|
||||||
IdealFilteringView view = filteringProvider.get();
|
IdealFilteringView view = filteringProvider.get();
|
||||||
ViewInitializer.Initialize(view);
|
runView(view);
|
||||||
view.setVisible(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showButterworth() {
|
public void showButterworth() {
|
||||||
NonIdealFilteringView view = nonIdealFilteringProvider.get();
|
NonIdealFilteringView view = nonIdealFilteringProvider.get();
|
||||||
ViewInitializer.Initialize(view);
|
runView(view);
|
||||||
view.setVisible(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showConvolutionFiltering() {
|
public void showConvolutionFiltering() {
|
||||||
LocalFilteringView view = convolutionFilteringProvider.get();
|
LocalFilteringView view = convolutionFilteringProvider.get();
|
||||||
|
runView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showBasicMorphology() {
|
||||||
|
BasicMorphologyView view = basicMorphologyProvider.get();
|
||||||
|
runView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runView(AbstractView view) {
|
||||||
ViewInitializer.Initialize(view);
|
ViewInitializer.Initialize(view);
|
||||||
view.setVisible(true);
|
view.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
65
src/main/java/app/state/MorphologyState.java
Normal file
65
src/main/java/app/state/MorphologyState.java
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package app.state;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import domain.image.Image;
|
||||||
|
import presenters.morphology.MorphologyListener;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MorphologyState extends State {
|
||||||
|
|
||||||
|
private Image erosion;
|
||||||
|
private Image dilation;
|
||||||
|
private Image opening;
|
||||||
|
private Image closing;
|
||||||
|
|
||||||
|
private final List<MorphologyListener> listeners = new ArrayList<>();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public MorphologyState() {}
|
||||||
|
|
||||||
|
public void subscribe(MorphologyListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsubscribe(MorphologyListener listener) {
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErosion(Image image) {
|
||||||
|
erosion = image;
|
||||||
|
listeners.forEach(listener -> listener.onErosionChanged(image));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDilation(Image image) {
|
||||||
|
dilation = image;
|
||||||
|
listeners.forEach(listener -> listener.onDilationChanged(image));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOpening(Image image) {
|
||||||
|
opening = image;
|
||||||
|
listeners.forEach(listener -> listener.onOpeningChanged(image));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClosing(Image image) {
|
||||||
|
closing = image;
|
||||||
|
listeners.forEach(listener -> listener.onClosingChanged(image));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image getErosion() {
|
||||||
|
return erosion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image getDilation() {
|
||||||
|
return dilation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image getOpening() {
|
||||||
|
return opening;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image getClosing() {
|
||||||
|
return closing;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
package domain.image.processing.filtering;
|
package domain.image.processing.filtering;
|
||||||
|
|
||||||
import domain.image.GrayScaleMatrix;
|
import domain.image.GrayScaleMatrix;
|
||||||
import domain.image.Image;
|
|
||||||
import domain.image.Pixel;
|
|
||||||
import org.opencv.core.Core;
|
import org.opencv.core.Core;
|
||||||
import org.opencv.core.CvType;
|
import org.opencv.core.CvType;
|
||||||
import org.opencv.core.Mat;
|
import org.opencv.core.Mat;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class GlobalLinearFiltering {
|
public class GlobalLinearFiltering {
|
||||||
|
|
||||||
public static GrayScaleMatrix lowPassFiltering(GrayScaleMatrix matrix, double cutoff) {
|
public static GrayScaleMatrix lowPassFiltering(GrayScaleMatrix matrix, double cutoff) {
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package domain.image.processing.morphology;
|
||||||
|
|
||||||
|
import domain.image.GrayScaleMatrix;
|
||||||
|
import domain.image.Image;
|
||||||
|
import org.opencv.core.CvType;
|
||||||
|
import org.opencv.core.Mat;
|
||||||
|
import org.opencv.core.Size;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
|
||||||
|
public class BasicMorphology {
|
||||||
|
|
||||||
|
public static GrayScaleMatrix erosion(Image image, int tailleMasque) {
|
||||||
|
Mat input = toMat(image);
|
||||||
|
Mat kernel = createKernel(tailleMasque);
|
||||||
|
Mat result = new Mat();
|
||||||
|
|
||||||
|
Imgproc.erode(input, result, kernel);
|
||||||
|
|
||||||
|
return toGrayScaleMatrix(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GrayScaleMatrix dilation(Image image, int tailleMasque) {
|
||||||
|
Mat input = toMat(image);
|
||||||
|
Mat kernel = createKernel(tailleMasque);
|
||||||
|
Mat result = new Mat();
|
||||||
|
|
||||||
|
Imgproc.dilate(input, result, kernel);
|
||||||
|
|
||||||
|
return toGrayScaleMatrix(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GrayScaleMatrix opening(Image image, int tailleMasque) {
|
||||||
|
Mat input = toMat(image);
|
||||||
|
Mat kernel = createKernel(tailleMasque);
|
||||||
|
Mat result = new Mat();
|
||||||
|
|
||||||
|
Imgproc.morphologyEx(
|
||||||
|
input,
|
||||||
|
result,
|
||||||
|
Imgproc.MORPH_OPEN,
|
||||||
|
kernel
|
||||||
|
);
|
||||||
|
|
||||||
|
return toGrayScaleMatrix(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GrayScaleMatrix closing(Image image, int tailleMasque) {
|
||||||
|
Mat input = toMat(image);
|
||||||
|
Mat kernel = createKernel(tailleMasque);
|
||||||
|
Mat result = new Mat();
|
||||||
|
|
||||||
|
Imgproc.morphologyEx(
|
||||||
|
input,
|
||||||
|
result,
|
||||||
|
Imgproc.MORPH_CLOSE,
|
||||||
|
kernel
|
||||||
|
);
|
||||||
|
|
||||||
|
return toGrayScaleMatrix(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Mat toMat(Image image) {
|
||||||
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
|
||||||
|
int width = gray.getWidth();
|
||||||
|
int height = gray.getHeight();
|
||||||
|
|
||||||
|
Mat mat = new Mat(height, width, CvType.CV_64F);
|
||||||
|
|
||||||
|
double[][] data = gray.getRawData();
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
mat.put(y, 0, data[y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Mat createKernel(int tailleMasque) {
|
||||||
|
return Imgproc.getStructuringElement(
|
||||||
|
Imgproc.MORPH_RECT,
|
||||||
|
new Size(tailleMasque, tailleMasque)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GrayScaleMatrix toGrayScaleMatrix(Mat mat) {
|
||||||
|
int width = mat.cols();
|
||||||
|
int height = mat.rows();
|
||||||
|
|
||||||
|
double[][] output = new double[height][width];
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
output[y][x] = mat.get(y, x)[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GrayScaleMatrix(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package domain.image.processing.morphology;
|
||||||
|
|
||||||
|
import domain.image.GrayScaleMatrix;
|
||||||
|
import domain.image.Image;
|
||||||
|
import org.opencv.core.Core;
|
||||||
|
import org.opencv.core.CvType;
|
||||||
|
import org.opencv.core.Mat;
|
||||||
|
import org.opencv.core.Size;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
|
||||||
|
public class ComplexMorphology {
|
||||||
|
|
||||||
|
public static GrayScaleMatrix geodesicDilation(Image image, Image mask, int size) {
|
||||||
|
Mat input = toMat(image);
|
||||||
|
Mat maskMat = toMat(mask);
|
||||||
|
Mat kernel = createKernel(size);
|
||||||
|
|
||||||
|
Mat dilated = new Mat();
|
||||||
|
Imgproc.dilate(input, dilated, kernel);
|
||||||
|
|
||||||
|
Mat result = new Mat();
|
||||||
|
Core.min(dilated, maskMat, result);
|
||||||
|
|
||||||
|
return toGrayScaleMatrix(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GrayScaleMatrix geodesicReconstruction(Image marker, Image mask, int size) {
|
||||||
|
Mat markerMat = toMat(marker);
|
||||||
|
Mat maskMat = toMat(mask);
|
||||||
|
Mat kernel = createKernel(size);
|
||||||
|
|
||||||
|
Mat current = markerMat.clone();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Mat dilated = new Mat();
|
||||||
|
Imgproc.dilate(current, dilated, kernel);
|
||||||
|
|
||||||
|
Mat next = new Mat();
|
||||||
|
Core.min(dilated, maskMat, next);
|
||||||
|
|
||||||
|
if (Core.norm(next, current, Core.NORM_INF) == 0) {
|
||||||
|
return toGrayScaleMatrix(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GrayScaleMatrix meanFilter(Image image, int size) {
|
||||||
|
Mat input = toMat(image);
|
||||||
|
Mat result = new Mat();
|
||||||
|
|
||||||
|
Imgproc.blur(input, result, new Size(size, size));
|
||||||
|
|
||||||
|
return toGrayScaleMatrix(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Mat toMat(Image image) {
|
||||||
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
|
||||||
|
int width = gray.getWidth();
|
||||||
|
int height = gray.getHeight();
|
||||||
|
|
||||||
|
Mat mat = new Mat(height, width, CvType.CV_64F);
|
||||||
|
|
||||||
|
double[][] data = gray.getRawData();
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
mat.put(y, 0, data[y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Mat createKernel(int size) {
|
||||||
|
return Imgproc.getStructuringElement(
|
||||||
|
Imgproc.MORPH_RECT,
|
||||||
|
new Size(size, size)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GrayScaleMatrix toGrayScaleMatrix(Mat mat) {
|
||||||
|
int width = mat.cols();
|
||||||
|
int height = mat.rows();
|
||||||
|
|
||||||
|
double[][] output = new double[height][width];
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
output[y][x] = mat.get(y, x)[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GrayScaleMatrix(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,28 +42,18 @@ public class NavPresenter {
|
|||||||
appState.setImage(image);
|
appState.setImage(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void goToFourier() {
|
public void goToFourier() { navigator.showFourier(); }
|
||||||
navigator.showFourier();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void goToFiltering() {
|
public void goToFiltering() { navigator.showIdealFiltering(); }
|
||||||
navigator.showIdealFiltering();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void goToConvolution() {
|
public void goToConvolution() { navigator.showConvolutionFiltering(); }
|
||||||
navigator.showConvolutionFiltering();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotToButterworth() {
|
public void gotToButterworth() { navigator.showButterworth(); }
|
||||||
navigator.showButterworth();
|
|
||||||
}
|
|
||||||
|
|
||||||
public GrayScaleMatrix getImageGrayMatrix() {
|
public void goToBasicMorphology(){ navigator.showBasicMorphology(); }
|
||||||
return appState.getImage().toGrayScale();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMode(Mode mode) {
|
public GrayScaleMatrix getImageGrayMatrix() { return appState.getImage().toGrayScale(); }
|
||||||
modeService.setMode(mode);
|
|
||||||
}
|
public void setMode(Mode mode) { modeService.setMode(mode); }
|
||||||
|
|
||||||
}
|
}
|
||||||
13
src/main/java/presenters/morphology/MorphologyListener.java
Normal file
13
src/main/java/presenters/morphology/MorphologyListener.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package presenters.morphology;
|
||||||
|
|
||||||
|
import domain.image.Image;
|
||||||
|
|
||||||
|
public interface MorphologyListener {
|
||||||
|
void onErosionChanged(Image image);
|
||||||
|
|
||||||
|
void onDilationChanged(Image image);
|
||||||
|
|
||||||
|
void onOpeningChanged(Image image);
|
||||||
|
|
||||||
|
void onClosingChanged(Image image);
|
||||||
|
}
|
||||||
102
src/main/java/presenters/morphology/MorphologyPresenter.java
Normal file
102
src/main/java/presenters/morphology/MorphologyPresenter.java
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package presenters.morphology;
|
||||||
|
|
||||||
|
import app.state.AppState;
|
||||||
|
import app.state.MorphologyState;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import domain.image.Image;
|
||||||
|
import services.MorphologyService;
|
||||||
|
import ui.abstractions.IBasicMorphologyView;
|
||||||
|
|
||||||
|
public class MorphologyPresenter implements MorphologyListener {
|
||||||
|
|
||||||
|
private final AppState appState;
|
||||||
|
private final MorphologyState morphologyState;
|
||||||
|
private final MorphologyService morphologyService;
|
||||||
|
private IBasicMorphologyView view;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public MorphologyPresenter(
|
||||||
|
AppState appState,
|
||||||
|
MorphologyState morphologyState,
|
||||||
|
MorphologyService morphologyService
|
||||||
|
) {
|
||||||
|
this.appState = appState;
|
||||||
|
this.morphologyState = morphologyState;
|
||||||
|
this.morphologyService = morphologyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setView(IBasicMorphologyView view) {
|
||||||
|
this.view = view;
|
||||||
|
|
||||||
|
if (view != null) {
|
||||||
|
morphologyState.subscribe(this);
|
||||||
|
} else {
|
||||||
|
morphologyState.unsubscribe(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void computeErosion(Integer maskSize) {
|
||||||
|
Image image = appState.getImage();
|
||||||
|
|
||||||
|
Image result = morphologyService.erosion(image, maskSize);
|
||||||
|
|
||||||
|
morphologyState.setErosion(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void computeDilation(Integer maskSize) {
|
||||||
|
Image image = appState.getImage();
|
||||||
|
|
||||||
|
Image result = morphologyService.dilation(image, maskSize);
|
||||||
|
|
||||||
|
morphologyState.setDilation(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void computeOpening(Integer maskSize) {
|
||||||
|
Image image = appState.getImage();
|
||||||
|
|
||||||
|
Image result = morphologyService.opening(image, maskSize);
|
||||||
|
|
||||||
|
morphologyState.setOpening(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void computeClosing(Integer maskSize) {
|
||||||
|
Image image = appState.getImage();
|
||||||
|
|
||||||
|
Image result = morphologyService.closing(image, maskSize);
|
||||||
|
|
||||||
|
morphologyState.setClosing(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
morphologyState.unsubscribe(this);
|
||||||
|
view = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onErosionChanged(Image image) {
|
||||||
|
if (view != null) {
|
||||||
|
view.updateErosion(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDilationChanged(Image image) {
|
||||||
|
if (view != null) {
|
||||||
|
view.updateDilation(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpeningChanged(Image image) {
|
||||||
|
if (view != null) {
|
||||||
|
view.updateOpening(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClosingChanged(Image image) {
|
||||||
|
if (view != null) {
|
||||||
|
view.updateClosing(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/main/java/services/MorphologyService.java
Normal file
43
src/main/java/services/MorphologyService.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package services;
|
||||||
|
|
||||||
|
import domain.image.Image;
|
||||||
|
import domain.image.processing.morphology.BasicMorphology;
|
||||||
|
import domain.image.processing.morphology.ComplexMorphology;
|
||||||
|
|
||||||
|
public class MorphologyService {
|
||||||
|
|
||||||
|
public Image erosion(Image image, int size) {
|
||||||
|
return BasicMorphology.erosion(image, size).toImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image dilation(Image image, int size) {
|
||||||
|
return BasicMorphology.dilation(image, size).toImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image opening(Image image, int size) {
|
||||||
|
return BasicMorphology.opening(image, size).toImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image closing(Image image, int size) {
|
||||||
|
return BasicMorphology.closing(image, size).toImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image geodesicDilation(Image image, Image mask, int size) {
|
||||||
|
return ComplexMorphology
|
||||||
|
.geodesicDilation(image, mask, size)
|
||||||
|
.toImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image geodesicReconstruction(Image marker, Image mask, int size) {
|
||||||
|
return ComplexMorphology
|
||||||
|
.geodesicReconstruction(marker, mask, size)
|
||||||
|
.toImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image meanFilter(Image image, int size) {
|
||||||
|
return ComplexMorphology
|
||||||
|
.meanFilter(image, size)
|
||||||
|
.toImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
10
src/main/java/ui/abstractions/IBasicMorphologyView.java
Normal file
10
src/main/java/ui/abstractions/IBasicMorphologyView.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package ui.abstractions;
|
||||||
|
|
||||||
|
import domain.image.Image;
|
||||||
|
|
||||||
|
public interface IBasicMorphologyView {
|
||||||
|
void updateErosion(Image image);
|
||||||
|
void updateDilation(Image image);
|
||||||
|
void updateOpening(Image image);
|
||||||
|
void updateClosing(Image image);
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
private JMenu fourierMenu;
|
private JMenu fourierMenu;
|
||||||
private JMenu linearMenu;
|
private JMenu linearMenu;
|
||||||
private JMenu histogramMenu;
|
private JMenu histogramMenu;
|
||||||
|
private JMenu morphologyMenu;
|
||||||
|
|
||||||
private NavPresenter presenter;
|
private NavPresenter presenter;
|
||||||
|
|
||||||
@@ -91,6 +92,11 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
morphologyMenu = new Menu("Morphologie","/cp_51_p1.jpg",
|
||||||
|
new MenuItem("Elementaire", this::displayBasicMorphology),
|
||||||
|
new MenuItem("Complexe", this::displayComplexeMorphology)
|
||||||
|
);
|
||||||
|
|
||||||
histogramMenu = new Menu("Histogramme","/report_48_hot.jpg",
|
histogramMenu = new Menu("Histogramme","/report_48_hot.jpg",
|
||||||
new MenuItem("Afficher", "/report_32_hot.jpg",this::displayHistogram)
|
new MenuItem("Afficher", "/report_32_hot.jpg",this::displayHistogram)
|
||||||
);
|
);
|
||||||
@@ -99,15 +105,16 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
this.add(drawingMenu);
|
this.add(drawingMenu);
|
||||||
this.add(fourierMenu);
|
this.add(fourierMenu);
|
||||||
this.add(linearMenu);
|
this.add(linearMenu);
|
||||||
|
this.add(morphologyMenu);
|
||||||
this.add(histogramMenu);
|
this.add(histogramMenu);
|
||||||
|
|
||||||
drawingMenu.setEnabled(false);
|
drawingMenu.setEnabled(false);
|
||||||
fourierMenu.setEnabled(false);
|
fourierMenu.setEnabled(false);
|
||||||
linearMenu.setEnabled(false);
|
linearMenu.setEnabled(false);
|
||||||
|
morphologyMenu.setEnabled(false);
|
||||||
histogramMenu.setEnabled(false);
|
histogramMenu.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//####################################################
|
//####################################################
|
||||||
|
|
||||||
private File chooseFile(){
|
private File chooseFile(){
|
||||||
@@ -173,6 +180,7 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
drawingMenu.setEnabled(true);
|
drawingMenu.setEnabled(true);
|
||||||
fourierMenu.setEnabled(true);
|
fourierMenu.setEnabled(true);
|
||||||
linearMenu.setEnabled(true);
|
linearMenu.setEnabled(true);
|
||||||
|
morphologyMenu.setEnabled(true);
|
||||||
histogramMenu.setEnabled(true);
|
histogramMenu.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +189,7 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
drawingMenu.setEnabled(true);
|
drawingMenu.setEnabled(true);
|
||||||
fourierMenu.setEnabled(false);
|
fourierMenu.setEnabled(false);
|
||||||
linearMenu.setEnabled(false);
|
linearMenu.setEnabled(false);
|
||||||
|
morphologyMenu.setEnabled(false);
|
||||||
histogramMenu.setEnabled(false);
|
histogramMenu.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,4 +252,8 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void displayBasicMorphology(ActionEvent actionEvent) { presenter.goToBasicMorphology(); }
|
||||||
|
|
||||||
|
private void displayComplexeMorphology(ActionEvent actionEvent) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,228 @@
|
|||||||
|
package ui.implementation.views.morphology;
|
||||||
|
|
||||||
|
import domain.image.Image;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import presenters.morphology.MorphologyPresenter;
|
||||||
|
import ui.abstractions.AbstractView;
|
||||||
|
import ui.abstractions.IBasicMorphologyView;
|
||||||
|
import ui.implementation.components.controls.SaveButton;
|
||||||
|
import ui.implementation.components.image.TabbedImagePanel;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.text.AbstractDocument;
|
||||||
|
import javax.swing.text.AttributeSet;
|
||||||
|
import javax.swing.text.BadLocationException;
|
||||||
|
import javax.swing.text.DocumentFilter;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class BasicMorphologyView extends AbstractView implements IBasicMorphologyView {
|
||||||
|
|
||||||
|
private static final String EROSION_TAB_TITLE = "Erosion";
|
||||||
|
private static final String DILATION_TAB_TITLE = "Dilatation";
|
||||||
|
private static final String OPENING_TAB_TITLE = "Ouverture";
|
||||||
|
private static final String CLOSING_TAB_TITLE = "Fermeture";
|
||||||
|
|
||||||
|
private final MorphologyPresenter presenter;
|
||||||
|
|
||||||
|
private TabbedImagePanel modeTab;
|
||||||
|
private JTextField maskSizeField;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public BasicMorphologyView(MorphologyPresenter presenter) {
|
||||||
|
this.presenter = presenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initComponents() {
|
||||||
|
modeTab = new TabbedImagePanel();
|
||||||
|
|
||||||
|
modeTab.addPreviewTab(EROSION_TAB_TITLE);
|
||||||
|
modeTab.addPreviewTab(DILATION_TAB_TITLE);
|
||||||
|
modeTab.addPreviewTab(OPENING_TAB_TITLE);
|
||||||
|
modeTab.addPreviewTab(CLOSING_TAB_TITLE);
|
||||||
|
|
||||||
|
maskSizeField = createPositiveIntegerField();
|
||||||
|
|
||||||
|
JButton applyButton = new JButton("Appliquer");
|
||||||
|
applyButton.addActionListener(e -> applyMorphology());
|
||||||
|
|
||||||
|
JButton saveButton = new SaveButton();
|
||||||
|
|
||||||
|
JPanel controlPanel = createControlPanel(
|
||||||
|
maskSizeField,
|
||||||
|
applyButton
|
||||||
|
);
|
||||||
|
|
||||||
|
JPanel rightPanel = new JPanel();
|
||||||
|
|
||||||
|
GroupLayout rightLayout = new GroupLayout(rightPanel);
|
||||||
|
rightPanel.setLayout(rightLayout);
|
||||||
|
rightLayout.setAutoCreateGaps(true);
|
||||||
|
rightLayout.setAutoCreateContainerGaps(true);
|
||||||
|
|
||||||
|
rightLayout.setHorizontalGroup(
|
||||||
|
rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
|
||||||
|
.addComponent(controlPanel)
|
||||||
|
.addComponent(saveButton)
|
||||||
|
);
|
||||||
|
|
||||||
|
rightLayout.setVerticalGroup(
|
||||||
|
rightLayout.createSequentialGroup()
|
||||||
|
.addComponent(controlPanel)
|
||||||
|
.addComponent(saveButton)
|
||||||
|
);
|
||||||
|
|
||||||
|
JPanel mainPanel = new JPanel();
|
||||||
|
|
||||||
|
GroupLayout mainLayout = new GroupLayout(mainPanel);
|
||||||
|
mainPanel.setLayout(mainLayout);
|
||||||
|
mainLayout.setAutoCreateGaps(true);
|
||||||
|
mainLayout.setAutoCreateContainerGaps(true);
|
||||||
|
|
||||||
|
mainLayout.setHorizontalGroup(
|
||||||
|
mainLayout.createSequentialGroup()
|
||||||
|
.addComponent(modeTab)
|
||||||
|
.addComponent(rightPanel)
|
||||||
|
);
|
||||||
|
|
||||||
|
mainLayout.setVerticalGroup(
|
||||||
|
mainLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
|
||||||
|
.addComponent(modeTab)
|
||||||
|
.addComponent(rightPanel)
|
||||||
|
);
|
||||||
|
|
||||||
|
setContentPane(mainPanel);
|
||||||
|
|
||||||
|
setTitle("Traitement morphologique élémentaire");
|
||||||
|
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initValues() {
|
||||||
|
this.modeTab.addChangeListener(e -> applyMorphology());
|
||||||
|
presenter.setView(this);
|
||||||
|
applyMorphology();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JPanel createControlPanel(JTextField sizeField, JButton applyButton) {
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
|
||||||
|
GroupLayout layout = new GroupLayout(panel);
|
||||||
|
panel.setLayout(layout);
|
||||||
|
layout.setAutoCreateGaps(true);
|
||||||
|
layout.setAutoCreateContainerGaps(true);
|
||||||
|
|
||||||
|
JLabel label = new JLabel("Taille du masque :");
|
||||||
|
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(GroupLayout.Alignment.CENTER)
|
||||||
|
.addComponent(label)
|
||||||
|
.addComponent(
|
||||||
|
sizeField,
|
||||||
|
GroupLayout.PREFERRED_SIZE,
|
||||||
|
60,
|
||||||
|
GroupLayout.PREFERRED_SIZE
|
||||||
|
)
|
||||||
|
.addComponent(applyButton)
|
||||||
|
);
|
||||||
|
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createSequentialGroup()
|
||||||
|
.addComponent(label)
|
||||||
|
.addComponent(
|
||||||
|
sizeField,
|
||||||
|
GroupLayout.PREFERRED_SIZE,
|
||||||
|
GroupLayout.DEFAULT_SIZE,
|
||||||
|
GroupLayout.PREFERRED_SIZE
|
||||||
|
)
|
||||||
|
.addComponent(applyButton)
|
||||||
|
);
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JTextField createPositiveIntegerField() {
|
||||||
|
JTextField field = new JTextField("1", 5);
|
||||||
|
((AbstractDocument) field.getDocument()).setDocumentFilter(new PositiveIntegerFilter());
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyMorphology() {
|
||||||
|
Integer size = getMaskSize();
|
||||||
|
|
||||||
|
if (size == null || size % 2 == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (modeTab.getSelectedIndex()) {
|
||||||
|
case 0 -> presenter.computeErosion(size);
|
||||||
|
case 1 -> presenter.computeDilation(size);
|
||||||
|
case 2 -> presenter.computeOpening(size);
|
||||||
|
case 3 -> presenter.computeClosing(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer getMaskSize() {
|
||||||
|
try {
|
||||||
|
int size = Integer.parseInt(maskSizeField.getText());
|
||||||
|
|
||||||
|
if (size <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateErosion(Image image) {
|
||||||
|
modeTab.loadImage(EROSION_TAB_TITLE, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateDilation(Image image) {
|
||||||
|
modeTab.loadImage(DILATION_TAB_TITLE, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateOpening(Image image) {
|
||||||
|
modeTab.loadImage(OPENING_TAB_TITLE, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateClosing(Image image) {
|
||||||
|
modeTab.loadImage(CLOSING_TAB_TITLE, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disposeCore() {
|
||||||
|
presenter.setView(null);
|
||||||
|
presenter.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PositiveIntegerFilter extends DocumentFilter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr
|
||||||
|
) throws BadLocationException {
|
||||||
|
if (isValid(fb.getDocument().getText(0, fb.getDocument().getLength()), offset, 0, string)) {
|
||||||
|
super.insertString(fb, offset, string, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
|
||||||
|
if (isValid(fb.getDocument().getText(0, fb.getDocument().getLength()), offset, length, text)) {
|
||||||
|
super.replace(fb, offset, length, text, attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValid(String current, int offset, int length, String replacement) {
|
||||||
|
String result = current.substring(0, offset) + replacement + current.substring(offset + length);
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.matches("[1-9][0-9]*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user