Add non-linear outline

This commit is contained in:
2026-09-29 12:06:44 +02:00
parent fa9887051b
commit 2d417990ec
10 changed files with 473 additions and 5 deletions

View File

@@ -12,6 +12,8 @@ import presenters.filtering.local.LocalFilteringPresenter;
import presenters.morphology.BasicMorphologyPresenter;
import presenters.morphology.ComplexMorphologyPresenter;
import presenters.outline.LinearOutlinePresenter;
import presenters.outline.NonLinearOutlineListener;
import presenters.outline.NonLinearOutlinePresenter;
import services.GlobalFilteringService;
import services.ImageService;
import services.MorphologyService;
@@ -25,6 +27,7 @@ import ui.implementation.views.fitering.local.LocalFilteringView;
import ui.implementation.views.morphology.BasicMorphologyView;
import ui.implementation.views.morphology.ComplexMorphologyView;
import ui.implementation.views.outline.LinearOutlineView;
import ui.implementation.views.outline.NonLinearOutlineView;
/**
* Gathers some configurations in order to set the dependency injection container up
@@ -43,6 +46,7 @@ public class AppModule extends AbstractModule {
bind(BasicMorphologyState.class);
bind(ComplexMorphologyState.class);
bind(LinearOutlineState.class);
bind(NonLinearOutlineState.class);
//--- Application layer ---
bind(EventBus.class).in(Scopes.SINGLETON);
@@ -57,6 +61,7 @@ public class AppModule extends AbstractModule {
bind(IBasicMorphologyView.class).to(BasicMorphologyView.class);
bind(IComplexMorphologyView.class).to(ComplexMorphologyView.class);
bind(ILinearOutlineView.class).to(LinearOutlineView.class);
bind(INonLinearOutlineView.class).to(NonLinearOutlineView.class);
//--- Presentation layer ---
bind(MainPresenter.class);
@@ -67,6 +72,7 @@ public class AppModule extends AbstractModule {
bind(BasicMorphologyPresenter.class);
bind(ComplexMorphologyPresenter.class);
bind(LinearOutlinePresenter.class);
bind(NonLinearOutlinePresenter.class);
//--- Service layer layer ---
bind(ImageService.class);

View File

@@ -12,6 +12,7 @@ import ui.implementation.views.fitering.local.LocalFilteringView;
import ui.implementation.views.morphology.BasicMorphologyView;
import ui.implementation.views.morphology.ComplexMorphologyView;
import ui.implementation.views.outline.LinearOutlineView;
import ui.implementation.views.outline.NonLinearOutlineView;
/**
* Concrete implement of the INavigator interface.
@@ -26,7 +27,8 @@ public class SwingNavigator implements INavigator {
private final Provider<LocalFilteringView> convolutionFilteringProvider;
private final Provider<BasicMorphologyView> basicMorphologyProvider;
private final Provider<ComplexMorphologyView> complexMorphologyProvider;
private Provider<LinearOutlineView> linearOutlineProvider;
private final Provider<LinearOutlineView> linearOutlineProvider;
private final Provider<NonLinearOutlineView> nonLinearOutlineProvider;
@Inject
public SwingNavigator(
@@ -36,7 +38,8 @@ public class SwingNavigator implements INavigator {
Provider<LocalFilteringView> convolutionFilterProvider,
Provider<BasicMorphologyView> basicMorphologyProvider,
Provider<ComplexMorphologyView> complexMorphologyProvider,
Provider<LinearOutlineView> linearOutlineProvider
Provider<LinearOutlineView> linearOutlineProvider,
Provider<NonLinearOutlineView> nonLinearOutlineProvider
) {
this.doubleMatrixProvider = doubleMatrixProvider;
this.filteringProvider = filteringProvider;
@@ -45,6 +48,7 @@ public class SwingNavigator implements INavigator {
this.basicMorphologyProvider = basicMorphologyProvider;
this.complexMorphologyProvider = complexMorphologyProvider;
this.linearOutlineProvider = linearOutlineProvider;
this.nonLinearOutlineProvider = nonLinearOutlineProvider;
}
@Override
@@ -91,6 +95,8 @@ public class SwingNavigator implements INavigator {
@Override
public void showNonLinearOutline() {
NonLinearOutlineView view = nonLinearOutlineProvider.get();
runView(view);
}
private void runView(AbstractView view) {

View File

@@ -0,0 +1,74 @@
package app.state;
import com.google.inject.Inject;
import domain.image.Image;
import presenters.outline.NonLinearOutlineListener;
import java.util.ArrayList;
import java.util.List;
public class NonLinearOutlineState extends State {
private Image erosionGradient;
private Image dilationGradient;
private Image beucherGradient;
private Image nonLinearLaplacian;
private final List<NonLinearOutlineListener> listeners = new ArrayList<>();
@Inject
public NonLinearOutlineState() {
}
public void subscribe(NonLinearOutlineListener listener) {
listeners.add(listener);
}
public void unsubscribe(NonLinearOutlineListener listener) {
listeners.remove(listener);
}
public void setErosionGradient(Image image) {
erosionGradient = image;
listeners.forEach(listener ->
listener.onErosionGradientChanged(image)
);
}
public void setDilationGradient(Image image) {
dilationGradient = image;
listeners.forEach(listener ->
listener.onDilationGradientChanged(image)
);
}
public void setBeucherGradient(Image image) {
beucherGradient = image;
listeners.forEach(listener ->
listener.onBeucherGradientChanged(image)
);
}
public void setNonLinearLaplacian(Image image) {
nonLinearLaplacian = image;
listeners.forEach(listener ->
listener.onNonLinearLaplacianChanged(image)
);
}
public Image getErosionGradient() {
return erosionGradient;
}
public Image getDilationGradient() {
return dilationGradient;
}
public Image getBeucherGradient() {
return beucherGradient;
}
public Image getNonLinearLaplacian() {
return nonLinearLaplacian;
}
}

View File

@@ -0,0 +1,74 @@
package domain.image.processing.outline;
import domain.image.GrayScaleMatrix;
import domain.image.Image;
import domain.image.processing.morphology.BasicMorphology;
public class NonLinearOutline {
public static GrayScaleMatrix gradientErosion(Image image) {
GrayScaleMatrix original = image.toGrayScale();
GrayScaleMatrix erosion = BasicMorphology.erosion(image, 3);
return subtract(original, erosion);
}
public static GrayScaleMatrix gradientDilation(Image image) {
GrayScaleMatrix original = image.toGrayScale();
GrayScaleMatrix dilation = BasicMorphology.dilation(image, 3);
return subtract(dilation, original);
}
public static GrayScaleMatrix beucherGradient(Image image) {
GrayScaleMatrix erosion = BasicMorphology.erosion(image, 3);
GrayScaleMatrix dilation = BasicMorphology.dilation(image, 3);
return subtract(dilation, erosion);
}
public static GrayScaleMatrix nonLinearLaplacian(Image image) {
GrayScaleMatrix original = image.toGrayScale();
GrayScaleMatrix erosion = BasicMorphology.erosion(image, 3);
GrayScaleMatrix dilation = BasicMorphology.dilation(image, 3);
int height = original.getHeight();
int width = original.getWidth();
double[][] result = new double[height][width];
double[][] originalData = original.getRawData();
double[][] erosionData = erosion.getRawData();
double[][] dilationData = dilation.getRawData();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
result[y][x] =
dilationData[y][x]
+ erosionData[y][x]
- 2 * originalData[y][x];
}
}
return new GrayScaleMatrix(result);
}
private static GrayScaleMatrix subtract(GrayScaleMatrix first, GrayScaleMatrix second) {
int height = first.getHeight();
int width = first.getWidth();
double[][] firstData = first.getRawData();
double[][] secondData = second.getRawData();
double[][] result = new double[height][width];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
result[y][x] =
firstData[y][x] - secondData[y][x];
}
}
return new GrayScaleMatrix(result);
}
}

View File

@@ -0,0 +1,14 @@
package presenters.outline;
import domain.image.Image;
public interface NonLinearOutlineListener {
void onErosionGradientChanged(Image image);
void onDilationGradientChanged(Image image);
void onBeucherGradientChanged(Image image);
void onNonLinearLaplacianChanged(Image image);
}

View File

@@ -0,0 +1,99 @@
package presenters.outline;
import app.state.AppState;
import app.state.NonLinearOutlineState;
import domain.image.Image;
import jakarta.inject.Inject;
import services.OutlineService;
import ui.abstractions.INonLinearOutlineView;
public class NonLinearOutlinePresenter implements NonLinearOutlineListener {
private final AppState appState;
private final NonLinearOutlineState outlineState;
private final OutlineService outlineService;
private INonLinearOutlineView view;
@Inject
public NonLinearOutlinePresenter(
AppState appState,
NonLinearOutlineState outlineState,
OutlineService outlineService
) {
this.appState = appState;
this.outlineState = outlineState;
this.outlineService = outlineService;
outlineState.subscribe(this);
}
public void setView(INonLinearOutlineView view) {
this.view = view;
}
public void dispose() {
view = null;
outlineState.unsubscribe(this);
}
public void computeErosionGradient() {
Image image = appState.getImage();
Image result = outlineService.gradientErosion(image);
outlineState.setErosionGradient(result);
}
public void computeDilationGradient() {
Image image = appState.getImage();
Image result = outlineService.gradientDilation(image);
outlineState.setDilationGradient(result);
}
public void computeBeucherGradient() {
Image image = appState.getImage();
Image result = outlineService.beucherGradient(image);
outlineState.setBeucherGradient(result);
}
public void computeNonLinearLaplacian() {
Image image = appState.getImage();
Image result = outlineService.nonLinearLaplacian(image);
outlineState.setNonLinearLaplacian(result);
}
@Override
public void onErosionGradientChanged(Image image) {
if (view != null) {
view.updateErosionGradient(image);
}
}
@Override
public void onDilationGradientChanged(Image image) {
if (view != null) {
view.updateDilationGradient(image);
}
}
@Override
public void onBeucherGradientChanged(Image image) {
if (view != null) {
view.updateBeucherGradient(image);
}
}
@Override
public void onNonLinearLaplacianChanged(Image image) {
if (view != null) {
view.updateNonLinearLaplacian(image);
}
}
}

View File

@@ -2,6 +2,7 @@ package services;
import domain.image.Image;
import domain.image.processing.outline.LinearOutline;
import domain.image.processing.outline.NonLinearOutline;
public class OutlineService {
@@ -29,4 +30,31 @@ public class OutlineService {
.toImage();
}
public Image gradientErosion(Image image) {
return NonLinearOutline
.gradientErosion(image)
.toImage();
}
public Image gradientDilation(Image image) {
return NonLinearOutline
.gradientDilation(image)
.toImage();
}
public Image beucherGradient(Image image) {
return NonLinearOutline
.beucherGradient(image)
.toImage();
}
public Image nonLinearLaplacian(Image image) {
return NonLinearOutline
.nonLinearLaplacian(image)
.toImage();
}
}

View File

@@ -0,0 +1,14 @@
package ui.abstractions;
import domain.image.Image;
public interface INonLinearOutlineView {
void updateErosionGradient(Image image);
void updateDilationGradient(Image image);
void updateBeucherGradient(Image image);
void updateNonLinearLaplacian(Image image);
}

View File

@@ -99,11 +99,10 @@ public class NavBar extends JMenuBar implements INavBar {
);
outlineMenu = new Menu("Contours","/cp_51_p1.jpg",
new MenuItem("Linéair", this::displayLinearOutline),
new MenuItem("Non-linéair", this::displayNonLinearOutline)
new MenuItem("Linéaire", this::displayLinearOutline),
new MenuItem("Non-linéaire", this::displayNonLinearOutline)
);
histogramMenu = new Menu("Histogramme","/report_48_hot.jpg",
new MenuItem("Afficher", "/report_32_hot.jpg",this::displayHistogram)
);

View File

@@ -0,0 +1,154 @@
package ui.implementation.views.outline;
import domain.image.Image;
import jakarta.inject.Inject;
import presenters.outline.NonLinearOutlinePresenter;
import ui.abstractions.AbstractView;
import ui.abstractions.INonLinearOutlineView;
import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.TabbedImagePanel;
import javax.swing.*;
public class NonLinearOutlineView extends AbstractView implements INonLinearOutlineView {
private static final String EROSION_GRADIENT_TAB_TITLE = "Gradient d'érosion";
private static final String DILATION_GRADIENT_TAB_TITLE = "Gradient de dilatation";
private static final String BEUCHER_GRADIENT_TAB_TITLE = "Gradient de Beucher";
private static final String NON_LINEAR_LAPLACIAN_TAB_TITLE = "Laplacien non-linéaire";
private final NonLinearOutlinePresenter presenter;
private TabbedImagePanel modeTab;
@Inject
public NonLinearOutlineView(NonLinearOutlinePresenter presenter) {
this.presenter = presenter;
}
@Override
public void initComponents() {
modeTab = new TabbedImagePanel();
modeTab.addPreviewTab(EROSION_GRADIENT_TAB_TITLE);
modeTab.addPreviewTab(DILATION_GRADIENT_TAB_TITLE);
modeTab.addPreviewTab(BEUCHER_GRADIENT_TAB_TITLE);
modeTab.addPreviewTab(NON_LINEAR_LAPLACIAN_TAB_TITLE);
JButton applyButton = new JButton("Appliquer");
applyButton.addActionListener(e -> applyOutline());
JButton saveButton = new SaveButton();
JPanel controlPanel = createControlPanel(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("Contours non-linéaires");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
pack();
}
private JPanel createControlPanel(JButton applyButton) {
JPanel panel = new JPanel();
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(applyButton)
);
layout.setVerticalGroup(
layout.createSequentialGroup()
.addComponent(applyButton)
);
return panel;
}
@Override
public void initValues() {
presenter.setView(this);
applyOutline();
}
private void applyOutline() {
int operation = modeTab.getSelectedIndex();
switch (operation) {
case 0 -> presenter.computeErosionGradient();
case 1 -> presenter.computeDilationGradient();
case 2 -> presenter.computeBeucherGradient();
case 3 -> presenter.computeNonLinearLaplacian();
}
}
@Override
public void updateErosionGradient(Image image) {
modeTab.loadImage(EROSION_GRADIENT_TAB_TITLE, image);
}
@Override
public void updateDilationGradient(Image image) {
modeTab.loadImage(DILATION_GRADIENT_TAB_TITLE, image);
}
@Override
public void updateBeucherGradient(Image image) {
modeTab.loadImage(BEUCHER_GRADIENT_TAB_TITLE, image);
}
@Override
public void updateNonLinearLaplacian(Image image) {
modeTab.loadImage(NON_LINEAR_LAPLACIAN_TAB_TITLE, image);
}
@Override
public void disposeCore() {
presenter.setView(null);
presenter.dispose();
}
}