Add UI components for outline

This commit is contained in:
2026-09-29 10:46:51 +02:00
parent 4a5f1a864e
commit 21faf82da6
12 changed files with 425 additions and 5 deletions

View File

@@ -15,4 +15,6 @@ public interface INavigator {
void showConvolutionFiltering(); void showConvolutionFiltering();
void showBasicMorphology(); void showBasicMorphology();
void showComplexMorphology(); void showComplexMorphology();
void showLinearOutline();
void showNonLinearOutline();
} }

View File

@@ -11,6 +11,7 @@ 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; import ui.implementation.views.morphology.BasicMorphologyView;
import ui.implementation.views.morphology.ComplexMorphologyView; import ui.implementation.views.morphology.ComplexMorphologyView;
import ui.implementation.views.outline.LinearOutlineView;
/** /**
* Concrete implement of the INavigator interface. * Concrete implement of the INavigator interface.
@@ -25,6 +26,7 @@ public class SwingNavigator implements INavigator {
private final Provider<LocalFilteringView> convolutionFilteringProvider; private final Provider<LocalFilteringView> convolutionFilteringProvider;
private final Provider<BasicMorphologyView> basicMorphologyProvider; private final Provider<BasicMorphologyView> basicMorphologyProvider;
private final Provider<ComplexMorphologyView> complexMorphologyProvider; private final Provider<ComplexMorphologyView> complexMorphologyProvider;
private Provider<LinearOutlineView> linearOutlineProvider;
@Inject @Inject
public SwingNavigator( public SwingNavigator(
@@ -33,7 +35,8 @@ public class SwingNavigator implements INavigator {
Provider<NonIdealFilteringView> nonIdealFilteringProvider, Provider<NonIdealFilteringView> nonIdealFilteringProvider,
Provider<LocalFilteringView> convolutionFilterProvider, Provider<LocalFilteringView> convolutionFilterProvider,
Provider<BasicMorphologyView> basicMorphologyProvider, Provider<BasicMorphologyView> basicMorphologyProvider,
Provider<ComplexMorphologyView> complexMorphologyProvider Provider<ComplexMorphologyView> complexMorphologyProvider,
Provider<LinearOutlineView> linearOutlineProvider
) { ) {
this.doubleMatrixProvider = doubleMatrixProvider; this.doubleMatrixProvider = doubleMatrixProvider;
this.filteringProvider = filteringProvider; this.filteringProvider = filteringProvider;
@@ -41,6 +44,7 @@ public class SwingNavigator implements INavigator {
this.convolutionFilteringProvider = convolutionFilterProvider; this.convolutionFilteringProvider = convolutionFilterProvider;
this.basicMorphologyProvider = basicMorphologyProvider; this.basicMorphologyProvider = basicMorphologyProvider;
this.complexMorphologyProvider = complexMorphologyProvider; this.complexMorphologyProvider = complexMorphologyProvider;
this.linearOutlineProvider = linearOutlineProvider;
} }
@Override @Override
@@ -79,6 +83,16 @@ public class SwingNavigator implements INavigator {
runView(view); runView(view);
} }
@Override
public void showLinearOutline() {
LinearOutlineView view = linearOutlineProvider.get();
runView(view);
}
@Override
public void showNonLinearOutline() {
}
private void runView(AbstractView view) { private void runView(AbstractView view) {
ViewInitializer.Initialize(view); ViewInitializer.Initialize(view);
view.setVisible(true); view.setVisible(true);

View File

@@ -0,0 +1,4 @@
package app.state;
public class LinearOutlineState extends State{
}

View File

@@ -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);
}
}

View File

@@ -54,6 +54,10 @@ public class NavPresenter {
public void goToComplexMorphology(){ navigator.showComplexMorphology(); } public void goToComplexMorphology(){ navigator.showComplexMorphology(); }
public void goToLinearOutline(){ navigator.showLinearOutline(); }
public void goToNonLinearOutline() { navigator.showNonLinearOutline(); }
public GrayScaleMatrix getImageGrayMatrix() { return appState.getImage().toGrayScale(); } public GrayScaleMatrix getImageGrayMatrix() { return appState.getImage().toGrayScale(); }
public void setMode(Mode mode) { modeService.setMode(mode); } public void setMode(Mode mode) { modeService.setMode(mode); }

View File

@@ -0,0 +1,5 @@
package presenters.outline;
public interface LinearOutlineListener {
}

View File

@@ -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() {
}
}

View File

@@ -0,0 +1,4 @@
package services;
public class OutlineService {
}

View File

@@ -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);
}

View File

@@ -35,6 +35,7 @@ public class NavBar extends JMenuBar implements INavBar {
private JMenu linearMenu; private JMenu linearMenu;
private JMenu histogramMenu; private JMenu histogramMenu;
private JMenu morphologyMenu; private JMenu morphologyMenu;
private Menu outlineMenu;
private NavPresenter presenter; private NavPresenter presenter;
@@ -97,6 +98,12 @@ public class NavBar extends JMenuBar implements INavBar {
new MenuItem("Complexe", this::displayComplexeMorphology) 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", 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)
); );
@@ -106,12 +113,14 @@ public class NavBar extends JMenuBar implements INavBar {
this.add(fourierMenu); this.add(fourierMenu);
this.add(linearMenu); this.add(linearMenu);
this.add(morphologyMenu); this.add(morphologyMenu);
this.add(outlineMenu);
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); morphologyMenu.setEnabled(false);
outlineMenu.setEnabled(false);
histogramMenu.setEnabled(false); histogramMenu.setEnabled(false);
} }
@@ -181,6 +190,7 @@ public class NavBar extends JMenuBar implements INavBar {
fourierMenu.setEnabled(true); fourierMenu.setEnabled(true);
linearMenu.setEnabled(true); linearMenu.setEnabled(true);
morphologyMenu.setEnabled(true); morphologyMenu.setEnabled(true);
outlineMenu.setEnabled(true);
histogramMenu.setEnabled(true); histogramMenu.setEnabled(true);
} }
@@ -190,6 +200,7 @@ public class NavBar extends JMenuBar implements INavBar {
fourierMenu.setEnabled(false); fourierMenu.setEnabled(false);
linearMenu.setEnabled(false); linearMenu.setEnabled(false);
morphologyMenu.setEnabled(false); morphologyMenu.setEnabled(false);
outlineMenu.setEnabled(false);
histogramMenu.setEnabled(false); histogramMenu.setEnabled(false);
} }
@@ -243,6 +254,15 @@ public class NavBar extends JMenuBar implements INavBar {
presenter.goToConvolution(); 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) { private void displayErrorMessage(String title, String message) {
JOptionPane.showMessageDialog( JOptionPane.showMessageDialog(
this, 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(); }
} }

View File

@@ -89,7 +89,7 @@ public class MainView extends JFrame implements IMainView
.addContainerGap()) .addContainerGap())
); );
setSize(new Dimension(750, 500)); setSize(new Dimension(850, 550));
setLocationRelativeTo(null); setLocationRelativeTo(null);
} }

View File

@@ -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<String> 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();
}
}