From 541a1440a3f09bb1499e79686f41314eef3260d8 Mon Sep 17 00:00:00 2001 From: Laurent Date: Sun, 4 Oct 2026 15:20:25 +0200 Subject: [PATCH] Add some use cases --- .../java/presenters/UseCasePresenter.java | 24 ++++- src/main/java/services/UseCaseService.java | 100 ++++++++++++++---- .../views/useCase/UseCaseView.java | 87 +++++---------- 3 files changed, 127 insertions(+), 84 deletions(-) diff --git a/src/main/java/presenters/UseCasePresenter.java b/src/main/java/presenters/UseCasePresenter.java index 0ec06c7..834250e 100644 --- a/src/main/java/presenters/UseCasePresenter.java +++ b/src/main/java/presenters/UseCasePresenter.java @@ -10,6 +10,7 @@ import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.util.Objects; +import java.util.function.Supplier; public class UseCasePresenter { @@ -38,7 +39,12 @@ public class UseCasePresenter { public void computeNoiseReduction() { Image image1 = loadImage(NOISE_1_IMAGE); Image image2 = loadImage(NOISE_2_IMAGE); - Image[] results = {service.reduceNoise(image1), service.reduceNoise(image2)}; + + Image reduced1 = measureTime("Reduction 1", () -> service.reduceNoise(image1, 0.5f, 7)); + Image reduced2 = measureTime("Reduction 2", () -> service.reduceNoise(image2, 1f, 5)); + + Image[] results = { reduced1, reduced2 }; + view.updateNoiseReduction(results[0], results[1]); } @@ -50,13 +56,13 @@ public class UseCasePresenter { public void computePeasSegmentation() { Image image = loadImage(PEAS_IMAGE); - Image[] results = service.segmentPeas(image); + Image[] results = measureTime("Peas segmentation", () -> service.segmentPeas(image)); view.updatePeasSegmentation(results[0], results[1]); } public void computeBarnacleSegmentation() { Image image = loadImage(BARNACLES_IMAGE); - Image[] results = service.segmentBarnacles(image); + Image[] results =measureTime("Barnacle segmentation", () -> service.segmentBarnacles(image)); view.updateBarnacleSegmentation(results[0], results[1]); } @@ -95,4 +101,16 @@ public class UseCasePresenter { public void dispose() { view = null; } + + public T measureTime(String name, Supplier operation) { + long start = System.nanoTime(); + + T result = operation.get(); + + long elapsed = (System.nanoTime() - start) / 1_000_000; + System.out.println(name + " took " + elapsed + " ms"); + + return result; + } + } \ No newline at end of file diff --git a/src/main/java/services/UseCaseService.java b/src/main/java/services/UseCaseService.java index 95359a9..df60b8c 100644 --- a/src/main/java/services/UseCaseService.java +++ b/src/main/java/services/UseCaseService.java @@ -2,23 +2,26 @@ package services; import domain.image.GrayScaleMatrix; import domain.image.Image; +import domain.image.Pixel; import domain.image.processing.filtering.GlobalLinearFiltering; +import domain.image.processing.morphology.BasicMorphology; import domain.image.processing.morphology.ComplexMorphology; +import domain.image.processing.threshold.Thresholding; import java.util.function.Supplier; public class UseCaseService { - public Image reduceNoise(Image i0) { + public Image reduceNoise(Image i0, float cutOffPercentage, int maskSize) { - double cutoff = 0.7 * getMaxCutoff(i0.getWidth(), i0.getHeight()); + double cutoff = cutOffPercentage * getMaxCutoff(i0.getWidth(), i0.getHeight()); GrayScaleMatrix m0 = i0.toGrayScale(); - GrayScaleMatrix m1 = measureTime("Butterworth low pass", () -> GlobalLinearFiltering.butterworthLowPassFiltering(m0, cutoff, 1)); + GrayScaleMatrix m1 = GlobalLinearFiltering.butterworthLowPassFiltering(m0, cutoff, 1); Image i1 = m1.toImage(); - return measureTime("Median filter", () -> ComplexMorphology.medianFilter(i1, 5).toImage()); + return ComplexMorphology.medianFilter(i1, maskSize).toImage(); } public Image[] equalizeHistogram(Image image) { @@ -28,15 +31,81 @@ public class UseCaseService { } public Image[] segmentPeas(Image image) { - Image bluePeas = extractBluePeas(image); - Image redPeas = extractRedPeas(image); - return new Image[]{bluePeas, redPeas}; + int width = image.getWidth(); + int height = image.getHeight(); + Pixel[][] bluePixels = new Pixel[height][width]; + Pixel[][] redPixels = new Pixel[height][width]; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + Pixel pixel = image.getPixel(x, y); + int red = pixel.getRed(); + int green = pixel.getGreen(); + int blue = pixel.getBlue(); + + boolean isBlue = blue > red * 1.2 && blue > green * 1.2; + boolean isRed = red > blue * 1.2 && red > green * 1.2; + + bluePixels[y][x] = isBlue ? new Pixel(255, 255, 255) : new Pixel(0, 0, 0); + redPixels[y][x] = isRed ? new Pixel(255, 255, 255) : new Pixel(0, 0, 0); + } + } + + return new Image[]{ + new Image(bluePixels), + new Image(redPixels) + }; } public Image[] segmentBarnacles(Image image) { - Image largeBarnacles = extractLargeBarnacles(image); - Image smallBarnacles = extractSmallBarnacles(image); - return new Image[]{largeBarnacles, smallBarnacles}; + GrayScaleMatrix base = image.toGrayScale(); + + Image largeThreshold = Thresholding.simpleThreshold(image, 128).toImage(); + Image largeClosing = BasicMorphology.closing(largeThreshold, 7).toImage(); + Image largeOpening = BasicMorphology.opening(largeClosing, 31).toImage(); + GrayScaleMatrix largeMask = BasicMorphology.dilation(largeOpening, 11); + double[][] baseData = base.getRawData(); + double[][] largeMaskData = largeMask.getRawData(); + double[][] largeResult = new double[base.getHeight()][base.getWidth()]; + + for (int y = 0; y < base.getHeight(); y++) { + for (int x = 0; x < base.getWidth(); x++) { + largeResult[y][x] = largeMaskData[y][x] > 0 ? baseData[y][x] : 0; + } + } + + // Small barnacles + GrayScaleMatrix small = Thresholding.simpleThreshold(image, 198); + GrayScaleMatrix smallMask = BasicMorphology.closing(small.toImage(), 9); + + double[][] smallMaskData = smallMask.getRawData(); + + for (int y = 0; y < base.getHeight(); y++) { + for (int x = 0; x < base.getWidth(); x++) { + if (largeMaskData[y][x] > 0) { + smallMaskData[y][x] = 0; + } + } + } + + smallMask = new GrayScaleMatrix(smallMaskData); + Image smallMaskImage = smallMask.toImage(); + Image smallOpening = BasicMorphology.opening(smallMaskImage, 5).toImage(); + smallMask =BasicMorphology.dilation(smallOpening, 5); + + smallMaskData = smallMask.getRawData(); + double[][] smallResult = new double[base.getHeight()][base.getWidth()]; + + for (int y = 0; y < base.getHeight(); y++) { + for (int x = 0; x < base.getWidth(); x++) { + smallResult[y][x] = smallMaskData[y][x] > 0 ? baseData[y][x] : 0; + } + } + + return new Image[]{ + new GrayScaleMatrix(largeResult).toImage(), + new GrayScaleMatrix(smallResult).toImage() + }; } public Image segmentTools(Image image) { @@ -93,17 +162,6 @@ public class UseCaseService { return image; } - public T measureTime(String name, Supplier operation) { - long start = System.nanoTime(); - - T result = operation.get(); - - long elapsed = (System.nanoTime() - start) / 1_000_000; - System.out.println(name + " took " + elapsed + " ms"); - - return result; - } - private double getMaxCutoff(int width, int height) { return Math.sqrt(Math.pow(width / 2.0, 2) + Math.pow(height / 2.0, 2)); } diff --git a/src/main/java/ui/implementation/views/useCase/UseCaseView.java b/src/main/java/ui/implementation/views/useCase/UseCaseView.java index 42548c4..3945859 100644 --- a/src/main/java/ui/implementation/views/useCase/UseCaseView.java +++ b/src/main/java/ui/implementation/views/useCase/UseCaseView.java @@ -12,39 +12,23 @@ import javax.swing.*; import java.awt.*; public class UseCaseView extends AbstractView implements IUseCaseView { - - private static final String NOISE_1_TAB_TITLE = "Bruit 1"; - private static final String NOISE_2_TAB_TITLE = "Bruit 2"; - - private static final String HISTOGRAM_RGB_TAB_TITLE = "Égalisation RGB"; - private static final String HISTOGRAM_LUMINANCE_TAB_TITLE = "Égalisation luminance"; - - private static final String PEAS_BLUE_TAB_TITLE = "Pois bleus"; - private static final String PEAS_RED_TAB_TITLE = "Pois rouges"; - - private static final String BARNACLE_LARGE_TAB_TITLE = "Balanes grandes"; - private static final String BARNACLE_SMALL_TAB_TITLE = "Balanes petites"; - - private static final String TOOLS_TAB_TITLE = "Outils"; - - private static final String SPACECRAFT_TAB_TITLE = "Synthèse"; - private static final String SPACECRAFT_CONTOUR_TAB_TITLE = "Synthèse contour"; - - private static final String TOAST_TAB_TITLE = "Tartines"; + private static final String NOISE_1_TAB_TITLE = "1. Bruit 1"; + private static final String NOISE_2_TAB_TITLE = "1. Bruit 2"; + private static final String HISTOGRAM_RGB_TAB_TITLE = "2. Égalisation RGB"; + private static final String HISTOGRAM_LUMINANCE_TAB_TITLE = "2. Égalisation luminance"; + private static final String PEAS_BLUE_TAB_TITLE = "3. Pois bleus"; + private static final String PEAS_RED_TAB_TITLE = "3. Pois rouges"; + private static final String BARNACLE_LARGE_TAB_TITLE = "4. Balanes grandes"; + private static final String BARNACLE_SMALL_TAB_TITLE = "4. Balanes petites"; + private static final String TOOLS_TAB_TITLE = "5. Outils"; + private static final String SPACECRAFT_TAB_TITLE = "6. Synthèse"; + private static final String SPACECRAFT_CONTOUR_TAB_TITLE = "6. Synthèse contour"; + private static final String TOAST_TAB_TITLE = "7. Tartines"; private final UseCasePresenter presenter; private final TabbedPanelFactory tabbedPanelFactory; - private TabbedImagePanel resultPanel; - private JButton noiseButton; - private JButton histogramButton; - private JButton peasButton; - private JButton barnacleButton; - private JButton toolsButton; - private JButton spacecraftButton; - private JButton toastButton; - @Inject public UseCaseView(UseCasePresenter presenter, TabbedPanelFactory tabbedPanelFactory) { this.presenter = presenter; @@ -68,54 +52,37 @@ public class UseCaseView extends AbstractView implements IUseCaseView { TOAST_TAB_TITLE ); - noiseButton = new JButton("Bruit"); - histogramButton = new JButton("Histogramme"); - peasButton = new JButton("Petits pois"); - barnacleButton = new JButton("Balanes"); - toolsButton = new JButton("Outils"); - spacecraftButton = new JButton("Vaisseau"); - toastButton = new JButton("Tartines"); + resultPanel.addChangeListener(e -> computeSelectedExercise()); - noiseButton.addActionListener(e -> presenter.computeNoiseReduction()); - histogramButton.addActionListener(e -> presenter.computeHistogramEqualization()); - peasButton.addActionListener(e -> presenter.computePeasSegmentation()); - barnacleButton.addActionListener(e -> presenter.computeBarnacleSegmentation()); - toolsButton.addActionListener(e -> presenter.computeToolsSegmentation()); - spacecraftButton.addActionListener(e -> presenter.computeSpacecraftExtraction()); - toastButton.addActionListener(e -> presenter.computeToastOutline()); - - JPanel controlPanel = createControlPanel(); - - JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + JPanel mainPanel = new JPanel(new BorderLayout()); mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - mainPanel.add(resultPanel, BorderLayout.CENTER); - mainPanel.add(controlPanel, BorderLayout.SOUTH); setContentPane(mainPanel); - setTitle("Applications"); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); setSize(1200, 800); + setLocationRelativeTo(null); } - private JPanel createControlPanel() { - JPanel panel = new JPanel(new GridLayout(1, 7, 5, 5)); + private void computeSelectedExercise() { + int index = resultPanel.getSelectedIndex(); - panel.add(noiseButton); - panel.add(histogramButton); - panel.add(peasButton); - panel.add(barnacleButton); - panel.add(toolsButton); - panel.add(spacecraftButton); - panel.add(toastButton); - - return panel; + switch (index) { + case 0, 1 -> presenter.computeNoiseReduction(); + case 2, 3 -> presenter.computeHistogramEqualization(); + case 4, 5 -> presenter.computePeasSegmentation(); + case 6, 7 -> presenter.computeBarnacleSegmentation(); + case 8 -> presenter.computeToolsSegmentation(); + case 9, 10 -> presenter.computeSpacecraftExtraction(); + case 11 -> presenter.computeToastOutline(); + } } @Override public void initValues() { presenter.setView(this); + presenter.computeNoiseReduction(); } @Override