From 21faf82da650d2eaa814510908805f6d954d7783 Mon Sep 17 00:00:00 2001 From: Laurent Date: Tue, 29 Sep 2026 10:46:51 +0200 Subject: [PATCH] Add UI components for outline --- src/main/java/app/INavigator.java | 2 + src/main/java/app/SwingNavigator.java | 16 +- .../java/app/state/LinearOutlineState.java | 4 + .../processing/outline/LinearOutline.java | 127 ++++++++++++ src/main/java/presenters/NavPresenter.java | 4 + .../outline/LinearOutlineListener.java | 5 + .../outline/LinearOutlinePresenter.java | 43 ++++ src/main/java/services/OutlineService.java | 4 + .../ui/abstractions/ILinearOutlineView.java | 10 + .../implementation/components/nav/NavBar.java | 23 ++- .../ui/implementation/views/MainView.java | 2 +- .../views/outline/LinearOutlineView.java | 190 ++++++++++++++++++ 12 files changed, 425 insertions(+), 5 deletions(-) create mode 100644 src/main/java/app/state/LinearOutlineState.java create mode 100644 src/main/java/domain/image/processing/outline/LinearOutline.java create mode 100644 src/main/java/presenters/outline/LinearOutlineListener.java create mode 100644 src/main/java/presenters/outline/LinearOutlinePresenter.java create mode 100644 src/main/java/services/OutlineService.java create mode 100644 src/main/java/ui/abstractions/ILinearOutlineView.java create mode 100644 src/main/java/ui/implementation/views/outline/LinearOutlineView.java diff --git a/src/main/java/app/INavigator.java b/src/main/java/app/INavigator.java index 8f6b447..cb7e249 100644 --- a/src/main/java/app/INavigator.java +++ b/src/main/java/app/INavigator.java @@ -15,4 +15,6 @@ public interface INavigator { void showConvolutionFiltering(); void showBasicMorphology(); void showComplexMorphology(); + void showLinearOutline(); + void showNonLinearOutline(); } diff --git a/src/main/java/app/SwingNavigator.java b/src/main/java/app/SwingNavigator.java index fc51123..af9c6eb 100644 --- a/src/main/java/app/SwingNavigator.java +++ b/src/main/java/app/SwingNavigator.java @@ -11,6 +11,7 @@ import ui.implementation.views.ViewInitializer; 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; /** * Concrete implement of the INavigator interface. @@ -25,6 +26,7 @@ public class SwingNavigator implements INavigator { private final Provider convolutionFilteringProvider; private final Provider basicMorphologyProvider; private final Provider complexMorphologyProvider; + private Provider linearOutlineProvider; @Inject public SwingNavigator( @@ -33,7 +35,8 @@ public class SwingNavigator implements INavigator { Provider nonIdealFilteringProvider, Provider convolutionFilterProvider, Provider basicMorphologyProvider, - Provider complexMorphologyProvider + Provider complexMorphologyProvider, + Provider linearOutlineProvider ) { this.doubleMatrixProvider = doubleMatrixProvider; this.filteringProvider = filteringProvider; @@ -41,6 +44,7 @@ public class SwingNavigator implements INavigator { this.convolutionFilteringProvider = convolutionFilterProvider; this.basicMorphologyProvider = basicMorphologyProvider; this.complexMorphologyProvider = complexMorphologyProvider; + this.linearOutlineProvider = linearOutlineProvider; } @Override @@ -79,6 +83,16 @@ public class SwingNavigator implements INavigator { runView(view); } + @Override + public void showLinearOutline() { + LinearOutlineView view = linearOutlineProvider.get(); + runView(view); + } + + @Override + public void showNonLinearOutline() { + } + private void runView(AbstractView view) { ViewInitializer.Initialize(view); view.setVisible(true); diff --git a/src/main/java/app/state/LinearOutlineState.java b/src/main/java/app/state/LinearOutlineState.java new file mode 100644 index 0000000..4126913 --- /dev/null +++ b/src/main/java/app/state/LinearOutlineState.java @@ -0,0 +1,4 @@ +package app.state; + +public class LinearOutlineState extends State{ +} diff --git a/src/main/java/domain/image/processing/outline/LinearOutline.java b/src/main/java/domain/image/processing/outline/LinearOutline.java new file mode 100644 index 0000000..677e89b --- /dev/null +++ b/src/main/java/domain/image/processing/outline/LinearOutline.java @@ -0,0 +1,127 @@ +package domain.image.processing.outline; + +import domain.image.GrayScaleMatrix; +import domain.image.Image; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.imgproc.Imgproc; + +public class LinearOutline { + + /** + * + * @param image + * @param direction applied horizontally if 1, applied vertically if 2 + * @return + */ + public static GrayScaleMatrix prewittGradient(Image image, int direction) { + Mat kernel = new Mat(3, 3, CvType.CV_64F); + + if (direction == 1) { + kernel.put(0, 0, + -1, 0, 1, + -1, 0, 1, + -1, 0, 1 + ); + } else if (direction == 2) { + kernel.put(0, 0, + -1, -1, -1, + 0, 0, 0, + 1, 1, 1 + ); + } else { + throw new IllegalArgumentException("Direction must be 1 or 2"); + } + + return applyKernel(image, kernel); + } + + /** + * + * @param image + * @param direction applied horizontally if 1, applied vertically if 2 + * @return + */ + public static GrayScaleMatrix sobelGradient(Image image, int direction) { + Mat kernel = new Mat(3, 3, CvType.CV_64F); + + if (direction == 1) { + kernel.put(0, 0, + -1, 0, 1, + -2, 0, 2, + -1, 0, 1 + ); + } else if (direction == 2) { + kernel.put(0, 0, + -1, -2, -1, + 0, 0, 0, + 1, 2, 1 + ); + } else { + throw new IllegalArgumentException("Direction must be 1 or 2"); + } + + return applyKernel(image, kernel); + } + + public static GrayScaleMatrix laplacian4(Image image) { + Mat kernel = new Mat(3, 3, CvType.CV_64F); + + kernel.put(0, 0, + 0, -1, 0, + -1, 4, -1, + 0, -1, 0 + ); + + return applyKernel(image, kernel); + } + + public static GrayScaleMatrix laplacian8(Image image) { + Mat kernel = new Mat(3, 3, CvType.CV_64F); + + kernel.put(0, 0, + -1, -1, -1, + -1, 8, -1, + -1, -1, -1 + ); + + return applyKernel(image, kernel); + } + + private static GrayScaleMatrix applyKernel(Image image, Mat kernel) { + GrayScaleMatrix gray = image.toGrayScale(); + + Mat input = new Mat( + gray.getHeight(), + gray.getWidth(), + CvType.CV_64F + ); + + double[][] data = gray.getRawData(); + + for (int y = 0; y < gray.getHeight(); y++) { + input.put(y, 0, data[y]); + } + + Mat result = new Mat(); + + Imgproc.filter2D( + input, + result, + CvType.CV_64F, + kernel + ); + + double[][] output = new double[ + result.rows() + ][result.cols()]; + + for (int y = 0; y < result.rows(); y++) { + for (int x = 0; x < result.cols(); x++) { + output[y][x] = result.get(y, x)[0]; + } + } + + return new GrayScaleMatrix(output); + } +} \ No newline at end of file diff --git a/src/main/java/presenters/NavPresenter.java b/src/main/java/presenters/NavPresenter.java index fe5bdd8..a7d7897 100644 --- a/src/main/java/presenters/NavPresenter.java +++ b/src/main/java/presenters/NavPresenter.java @@ -54,6 +54,10 @@ public class NavPresenter { public void goToComplexMorphology(){ navigator.showComplexMorphology(); } + public void goToLinearOutline(){ navigator.showLinearOutline(); } + + public void goToNonLinearOutline() { navigator.showNonLinearOutline(); } + public GrayScaleMatrix getImageGrayMatrix() { return appState.getImage().toGrayScale(); } public void setMode(Mode mode) { modeService.setMode(mode); } diff --git a/src/main/java/presenters/outline/LinearOutlineListener.java b/src/main/java/presenters/outline/LinearOutlineListener.java new file mode 100644 index 0000000..e79fab9 --- /dev/null +++ b/src/main/java/presenters/outline/LinearOutlineListener.java @@ -0,0 +1,5 @@ +package presenters.outline; + +public interface LinearOutlineListener { + +} diff --git a/src/main/java/presenters/outline/LinearOutlinePresenter.java b/src/main/java/presenters/outline/LinearOutlinePresenter.java new file mode 100644 index 0000000..06e5992 --- /dev/null +++ b/src/main/java/presenters/outline/LinearOutlinePresenter.java @@ -0,0 +1,43 @@ +package presenters.outline; + +import app.state.AppState; +import app.state.LinearOutlineState; +import jakarta.inject.Inject; +import services.OutlineService; + +public class LinearOutlinePresenter implements LinearOutlineListener { + + private final AppState appState; + private final LinearOutlineState outlineState; + private final OutlineService outlineService; + + @Inject + public LinearOutlinePresenter( + AppState appState, + LinearOutlineState outlineState, + OutlineService outlineService + ) { + this.appState = appState; + this.outlineState = outlineState; + this.outlineService = outlineService; + } + + public void setView(Object o) { + } + + public void dispose() { + } + + public void computePrewittGradient(int direction) { + } + + public void computeSobelGradient(int direction) { + + } + + public void computeLaplacian4() { + } + + public void computeLaplacian8() { + } +} diff --git a/src/main/java/services/OutlineService.java b/src/main/java/services/OutlineService.java new file mode 100644 index 0000000..d152d8a --- /dev/null +++ b/src/main/java/services/OutlineService.java @@ -0,0 +1,4 @@ +package services; + +public class OutlineService { +} diff --git a/src/main/java/ui/abstractions/ILinearOutlineView.java b/src/main/java/ui/abstractions/ILinearOutlineView.java new file mode 100644 index 0000000..077954a --- /dev/null +++ b/src/main/java/ui/abstractions/ILinearOutlineView.java @@ -0,0 +1,10 @@ +package ui.abstractions; + +import domain.image.Image; + +public interface ILinearOutlineView { + void updatePrewitt(Image image); + void updateSobel(Image image); + void updateLaplacian4(Image image); + void updateLaplacian8(Image image); +} diff --git a/src/main/java/ui/implementation/components/nav/NavBar.java b/src/main/java/ui/implementation/components/nav/NavBar.java index 9bfada7..95c1fff 100644 --- a/src/main/java/ui/implementation/components/nav/NavBar.java +++ b/src/main/java/ui/implementation/components/nav/NavBar.java @@ -35,6 +35,7 @@ public class NavBar extends JMenuBar implements INavBar { private JMenu linearMenu; private JMenu histogramMenu; private JMenu morphologyMenu; + private Menu outlineMenu; private NavPresenter presenter; @@ -97,6 +98,12 @@ public class NavBar extends JMenuBar implements INavBar { new MenuItem("Complexe", this::displayComplexeMorphology) ); + outlineMenu = new Menu("Contours","/cp_51_p1.jpg", + new MenuItem("Linéair", this::displayLinearOutline), + new MenuItem("Non-linéair", this::displayNonLinearOutline) + ); + + histogramMenu = new Menu("Histogramme","/report_48_hot.jpg", new MenuItem("Afficher", "/report_32_hot.jpg",this::displayHistogram) ); @@ -106,12 +113,14 @@ public class NavBar extends JMenuBar implements INavBar { this.add(fourierMenu); this.add(linearMenu); this.add(morphologyMenu); + this.add(outlineMenu); this.add(histogramMenu); drawingMenu.setEnabled(false); fourierMenu.setEnabled(false); linearMenu.setEnabled(false); morphologyMenu.setEnabled(false); + outlineMenu.setEnabled(false); histogramMenu.setEnabled(false); } @@ -181,6 +190,7 @@ public class NavBar extends JMenuBar implements INavBar { fourierMenu.setEnabled(true); linearMenu.setEnabled(true); morphologyMenu.setEnabled(true); + outlineMenu.setEnabled(true); histogramMenu.setEnabled(true); } @@ -190,6 +200,7 @@ public class NavBar extends JMenuBar implements INavBar { fourierMenu.setEnabled(false); linearMenu.setEnabled(false); morphologyMenu.setEnabled(false); + outlineMenu.setEnabled(false); histogramMenu.setEnabled(false); } @@ -243,6 +254,15 @@ public class NavBar extends JMenuBar implements INavBar { presenter.goToConvolution(); } + private void displayBasicMorphology(ActionEvent actionEvent) { presenter.goToBasicMorphology(); } + + private void displayComplexeMorphology(ActionEvent actionEvent) { presenter.goToComplexMorphology(); } + + private void displayLinearOutline(ActionEvent actionEvent) { presenter.goToLinearOutline(); } + + private void displayNonLinearOutline(ActionEvent actionEvent) { presenter.goToNonLinearOutline();} + + private void displayErrorMessage(String title, String message) { JOptionPane.showMessageDialog( this, @@ -252,7 +272,4 @@ public class NavBar extends JMenuBar implements INavBar { ); } - private void displayBasicMorphology(ActionEvent actionEvent) { presenter.goToBasicMorphology(); } - - private void displayComplexeMorphology(ActionEvent actionEvent) { presenter.goToComplexMorphology(); } } diff --git a/src/main/java/ui/implementation/views/MainView.java b/src/main/java/ui/implementation/views/MainView.java index 9f4a5bd..fb8528f 100644 --- a/src/main/java/ui/implementation/views/MainView.java +++ b/src/main/java/ui/implementation/views/MainView.java @@ -89,7 +89,7 @@ public class MainView extends JFrame implements IMainView .addContainerGap()) ); - setSize(new Dimension(750, 500)); + setSize(new Dimension(850, 550)); setLocationRelativeTo(null); } diff --git a/src/main/java/ui/implementation/views/outline/LinearOutlineView.java b/src/main/java/ui/implementation/views/outline/LinearOutlineView.java new file mode 100644 index 0000000..a9fc0ea --- /dev/null +++ b/src/main/java/ui/implementation/views/outline/LinearOutlineView.java @@ -0,0 +1,190 @@ +package ui.implementation.views.outline; + +import domain.image.Image; +import jakarta.inject.Inject; +import presenters.outline.LinearOutlinePresenter; +import ui.abstractions.AbstractView; +import ui.abstractions.ILinearOutlineView; +import ui.implementation.components.controls.SaveButton; +import ui.implementation.components.image.TabbedImagePanel; + +import javax.swing.*; + +public class LinearOutlineView extends AbstractView implements ILinearOutlineView { + + private static final String PREWITT_TAB_TITLE = "Gradient Prewitt"; + private static final String SOBEL_TAB_TITLE = "Gradient Sobel"; + private static final String LAPLACIAN4_TAB_TITLE = "Laplacien 4"; + private static final String LAPLACIAN8_TAB_TITLE = "Laplacien 8"; + + private final LinearOutlinePresenter presenter; + + private TabbedImagePanel modeTab; + private JComboBox directionComboBox; + + @Inject + public LinearOutlineView(LinearOutlinePresenter presenter) { + this.presenter = presenter; + } + + @Override + public void initComponents() { + modeTab = new TabbedImagePanel(); + + modeTab.addPreviewTab(PREWITT_TAB_TITLE); + modeTab.addPreviewTab(SOBEL_TAB_TITLE); + modeTab.addPreviewTab(LAPLACIAN4_TAB_TITLE); + modeTab.addPreviewTab(LAPLACIAN8_TAB_TITLE); + + directionComboBox = new JComboBox<>( + new String[]{ + "Horizontale", + "Verticale" + } + ); + + 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 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); + + JLabel directionLabel = new JLabel("Direction :"); + + layout.setHorizontalGroup( + layout.createParallelGroup(GroupLayout.Alignment.CENTER) + .addComponent(directionLabel) + .addComponent( + directionComboBox, + GroupLayout.PREFERRED_SIZE, + 120, + GroupLayout.PREFERRED_SIZE + ) + .addComponent(applyButton) + ); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(directionLabel) + .addComponent( + directionComboBox, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE + ) + .addComponent(applyButton) + ); + + return panel; + } + + @Override + public void initValues() { + modeTab.addChangeListener(e -> updateControls()); + + presenter.setView(this); + + updateControls(); + applyOutline(); + } + + private void updateControls() { + boolean hasDirection = + modeTab.getSelectedIndex() == 0 + || modeTab.getSelectedIndex() == 1; + + directionComboBox.setEnabled(hasDirection); + } + + private void applyOutline() { + int operation = modeTab.getSelectedIndex(); + int direction = directionComboBox.getSelectedIndex() + 1; + + switch (operation) { + case 0 -> presenter.computePrewittGradient(direction); + case 1 -> presenter.computeSobelGradient(direction); + case 2 -> presenter.computeLaplacian4(); + case 3 -> presenter.computeLaplacian8(); + } + } + + @Override + public void updatePrewitt(Image image) { + modeTab.loadImage(PREWITT_TAB_TITLE, image); + } + + @Override + public void updateSobel(Image image) { + modeTab.loadImage(SOBEL_TAB_TITLE, image); + } + + @Override + public void updateLaplacian4(Image image) { + modeTab.loadImage(LAPLACIAN4_TAB_TITLE, image); + } + + @Override + public void updateLaplacian8(Image image) { + modeTab.loadImage(LAPLACIAN8_TAB_TITLE, image); + } + + @Override + public void disposeCore() { + presenter.setView(null); + presenter.dispose(); + } +} \ No newline at end of file