Add thresholding
This commit is contained in:
@@ -17,4 +17,5 @@ public interface INavigator {
|
|||||||
void showComplexMorphology();
|
void showComplexMorphology();
|
||||||
void showLinearOutline();
|
void showLinearOutline();
|
||||||
void showNonLinearOutline();
|
void showNonLinearOutline();
|
||||||
|
void showThresholding();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import ui.implementation.views.morphology.BasicMorphologyView;
|
|||||||
import ui.implementation.views.morphology.ComplexMorphologyView;
|
import ui.implementation.views.morphology.ComplexMorphologyView;
|
||||||
import ui.implementation.views.outline.LinearOutlineView;
|
import ui.implementation.views.outline.LinearOutlineView;
|
||||||
import ui.implementation.views.outline.NonLinearOutlineView;
|
import ui.implementation.views.outline.NonLinearOutlineView;
|
||||||
|
import ui.implementation.views.threshold.ThresholdingView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Concrete implement of the INavigator interface.
|
* Concrete implement of the INavigator interface.
|
||||||
@@ -29,6 +30,7 @@ public class SwingNavigator implements INavigator {
|
|||||||
private final Provider<ComplexMorphologyView> complexMorphologyProvider;
|
private final Provider<ComplexMorphologyView> complexMorphologyProvider;
|
||||||
private final Provider<LinearOutlineView> linearOutlineProvider;
|
private final Provider<LinearOutlineView> linearOutlineProvider;
|
||||||
private final Provider<NonLinearOutlineView> nonLinearOutlineProvider;
|
private final Provider<NonLinearOutlineView> nonLinearOutlineProvider;
|
||||||
|
private final Provider<ThresholdingView> thresholdingProvider;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public SwingNavigator(
|
public SwingNavigator(
|
||||||
@@ -39,7 +41,8 @@ public class SwingNavigator implements INavigator {
|
|||||||
Provider<BasicMorphologyView> basicMorphologyProvider,
|
Provider<BasicMorphologyView> basicMorphologyProvider,
|
||||||
Provider<ComplexMorphologyView> complexMorphologyProvider,
|
Provider<ComplexMorphologyView> complexMorphologyProvider,
|
||||||
Provider<LinearOutlineView> linearOutlineProvider,
|
Provider<LinearOutlineView> linearOutlineProvider,
|
||||||
Provider<NonLinearOutlineView> nonLinearOutlineProvider
|
Provider<NonLinearOutlineView> nonLinearOutlineProvider,
|
||||||
|
Provider<ThresholdingView> thresholdingProvider
|
||||||
) {
|
) {
|
||||||
this.doubleMatrixProvider = doubleMatrixProvider;
|
this.doubleMatrixProvider = doubleMatrixProvider;
|
||||||
this.filteringProvider = filteringProvider;
|
this.filteringProvider = filteringProvider;
|
||||||
@@ -49,6 +52,7 @@ public class SwingNavigator implements INavigator {
|
|||||||
this.complexMorphologyProvider = complexMorphologyProvider;
|
this.complexMorphologyProvider = complexMorphologyProvider;
|
||||||
this.linearOutlineProvider = linearOutlineProvider;
|
this.linearOutlineProvider = linearOutlineProvider;
|
||||||
this.nonLinearOutlineProvider = nonLinearOutlineProvider;
|
this.nonLinearOutlineProvider = nonLinearOutlineProvider;
|
||||||
|
this.thresholdingProvider = thresholdingProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -99,6 +103,12 @@ public class SwingNavigator implements INavigator {
|
|||||||
runView(view);
|
runView(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showThresholding() {
|
||||||
|
ThresholdingView view = thresholdingProvider.get();
|
||||||
|
runView(view);
|
||||||
|
}
|
||||||
|
|
||||||
private void runView(AbstractView view) {
|
private void runView(AbstractView view) {
|
||||||
ViewInitializer.Initialize(view);
|
ViewInitializer.Initialize(view);
|
||||||
view.setVisible(true);
|
view.setVisible(true);
|
||||||
|
|||||||
65
src/main/java/app/state/ThresholdingState.java
Normal file
65
src/main/java/app/state/ThresholdingState.java
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package app.state;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import domain.image.Image;
|
||||||
|
import presenters.threshold.ThresholdingListener;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ThresholdingState extends State {
|
||||||
|
|
||||||
|
private Image simpleThreshold;
|
||||||
|
private Image doubleThreshold;
|
||||||
|
private Image automaticThreshold;
|
||||||
|
|
||||||
|
private final List<ThresholdingListener> listeners = new ArrayList<>();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ThresholdingState() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribe(ThresholdingListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsubscribe(ThresholdingListener listener) {
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSimpleThreshold(Image image) {
|
||||||
|
simpleThreshold = image;
|
||||||
|
|
||||||
|
listeners.forEach(listener ->
|
||||||
|
listener.onSimpleThresholdChanged(image)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDoubleThreshold(Image image) {
|
||||||
|
doubleThreshold = image;
|
||||||
|
|
||||||
|
listeners.forEach(listener ->
|
||||||
|
listener.onDoubleThresholdChanged(image)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutomaticThreshold(Image image) {
|
||||||
|
automaticThreshold = image;
|
||||||
|
|
||||||
|
listeners.forEach(listener ->
|
||||||
|
listener.onAutomaticThresholdChanged(image)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image getSimpleThreshold() {
|
||||||
|
return simpleThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image getDoubleThreshold() {
|
||||||
|
return doubleThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image getAutomaticThreshold() {
|
||||||
|
return automaticThreshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package domain.image.processing.threshold;
|
||||||
|
|
||||||
|
import domain.image.GrayScaleMatrix;
|
||||||
|
import domain.image.Image;
|
||||||
|
|
||||||
|
public class Thresholding {
|
||||||
|
|
||||||
|
public static GrayScaleMatrix simpleThreshold(
|
||||||
|
Image image,
|
||||||
|
int threshold
|
||||||
|
) {
|
||||||
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
|
||||||
|
int height = gray.getHeight();
|
||||||
|
int width = gray.getWidth();
|
||||||
|
|
||||||
|
double[][] data = gray.getRawData();
|
||||||
|
double[][] result = new double[height][width];
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
result[y][x] = data[y][x] >= threshold
|
||||||
|
? 255
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GrayScaleMatrix(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GrayScaleMatrix doubleThreshold(
|
||||||
|
Image image,
|
||||||
|
int threshold1,
|
||||||
|
int threshold2
|
||||||
|
) {
|
||||||
|
if (threshold1 > threshold2) {
|
||||||
|
int temp = threshold1;
|
||||||
|
threshold1 = threshold2;
|
||||||
|
threshold2 = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
|
||||||
|
int height = gray.getHeight();
|
||||||
|
int width = gray.getWidth();
|
||||||
|
|
||||||
|
double[][] data = gray.getRawData();
|
||||||
|
double[][] result = new double[height][width];
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
|
||||||
|
double value = data[y][x];
|
||||||
|
|
||||||
|
if (value < threshold1) {
|
||||||
|
result[y][x] = 0;
|
||||||
|
} else if (value < threshold2) {
|
||||||
|
result[y][x] = 127;
|
||||||
|
} else {
|
||||||
|
result[y][x] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GrayScaleMatrix(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GrayScaleMatrix automaticThreshold(Image image) {
|
||||||
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
|
||||||
|
double[][] data = gray.getRawData();
|
||||||
|
|
||||||
|
double threshold = (gray.getMinValue() + gray.getMaxValue()) / 2.0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
double lowerSum = 0;
|
||||||
|
double upperSum = 0;
|
||||||
|
|
||||||
|
int lowerCount = 0;
|
||||||
|
int upperCount = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < gray.getHeight(); y++) {
|
||||||
|
for (int x = 0; x < gray.getWidth(); x++) {
|
||||||
|
|
||||||
|
double value = data[y][x];
|
||||||
|
|
||||||
|
if (value <= threshold) {
|
||||||
|
lowerSum += value;
|
||||||
|
lowerCount++;
|
||||||
|
} else {
|
||||||
|
upperSum += value;
|
||||||
|
upperCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowerCount == 0 || upperCount == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
double lowerMean = lowerSum / lowerCount;
|
||||||
|
double upperMean = upperSum / upperCount;
|
||||||
|
|
||||||
|
double newThreshold = (lowerMean + upperMean) / 2.0;
|
||||||
|
|
||||||
|
if (Math.abs(newThreshold - threshold) < 0.5) {
|
||||||
|
threshold = newThreshold;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
threshold = newThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
return simpleThreshold(image, (int) threshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -58,6 +58,8 @@ public class NavPresenter {
|
|||||||
|
|
||||||
public void goToNonLinearOutline() { navigator.showNonLinearOutline(); }
|
public void goToNonLinearOutline() { navigator.showNonLinearOutline(); }
|
||||||
|
|
||||||
|
public void goToThresholding() { navigator.showThresholding(); }
|
||||||
|
|
||||||
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); }
|
||||||
|
|||||||
12
src/main/java/presenters/threshold/ThresholdingListener.java
Normal file
12
src/main/java/presenters/threshold/ThresholdingListener.java
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package presenters.threshold;
|
||||||
|
|
||||||
|
import domain.image.Image;
|
||||||
|
|
||||||
|
public interface ThresholdingListener {
|
||||||
|
|
||||||
|
void onSimpleThresholdChanged(Image image);
|
||||||
|
|
||||||
|
void onDoubleThresholdChanged(Image image);
|
||||||
|
|
||||||
|
void onAutomaticThresholdChanged(Image image);
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package presenters.threshold;
|
||||||
|
|
||||||
|
import app.state.AppState;
|
||||||
|
import app.state.ThresholdingState;
|
||||||
|
import domain.image.Image;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import services.ThresholdingService;
|
||||||
|
import ui.abstractions.IThresholdingView;
|
||||||
|
|
||||||
|
public class ThresholdingPresenter implements ThresholdingListener {
|
||||||
|
|
||||||
|
private final AppState appState;
|
||||||
|
private final ThresholdingState thresholdingState;
|
||||||
|
private final ThresholdingService thresholdingService;
|
||||||
|
|
||||||
|
private IThresholdingView view;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ThresholdingPresenter(
|
||||||
|
AppState appState,
|
||||||
|
ThresholdingState thresholdingState,
|
||||||
|
ThresholdingService thresholdingService
|
||||||
|
) {
|
||||||
|
this.appState = appState;
|
||||||
|
this.thresholdingState = thresholdingState;
|
||||||
|
this.thresholdingService = thresholdingService;
|
||||||
|
|
||||||
|
thresholdingState.subscribe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setView(IThresholdingView view) {
|
||||||
|
this.view = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
view = null;
|
||||||
|
thresholdingState.unsubscribe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void computeSimpleThreshold(int threshold) {
|
||||||
|
Image image = appState.getImage();
|
||||||
|
|
||||||
|
Image result = thresholdingService.simpleThreshold(
|
||||||
|
image,
|
||||||
|
threshold
|
||||||
|
);
|
||||||
|
|
||||||
|
thresholdingState.setSimpleThreshold(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void computeDoubleThreshold(
|
||||||
|
int threshold1,
|
||||||
|
int threshold2
|
||||||
|
) {
|
||||||
|
Image image = appState.getImage();
|
||||||
|
|
||||||
|
Image result = thresholdingService.doubleThreshold(
|
||||||
|
image,
|
||||||
|
threshold1,
|
||||||
|
threshold2
|
||||||
|
);
|
||||||
|
|
||||||
|
thresholdingState.setDoubleThreshold(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void computeAutomaticThreshold() {
|
||||||
|
Image image = appState.getImage();
|
||||||
|
|
||||||
|
Image result = thresholdingService.automaticThreshold(image);
|
||||||
|
|
||||||
|
thresholdingState.setAutomaticThreshold(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSimpleThresholdChanged(Image image) {
|
||||||
|
if (view != null) {
|
||||||
|
view.updateSimpleThreshold(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDoubleThresholdChanged(Image image) {
|
||||||
|
if (view != null) {
|
||||||
|
view.updateDoubleThreshold(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutomaticThresholdChanged(Image image) {
|
||||||
|
if (view != null) {
|
||||||
|
view.updateAutomaticThreshold(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/main/java/services/ThresholdingService.java
Normal file
29
src/main/java/services/ThresholdingService.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package services;
|
||||||
|
|
||||||
|
import domain.image.Image;
|
||||||
|
import domain.image.processing.threshold.Thresholding;
|
||||||
|
|
||||||
|
public class ThresholdingService {
|
||||||
|
|
||||||
|
public Image simpleThreshold(Image image, int threshold) {
|
||||||
|
return Thresholding
|
||||||
|
.simpleThreshold(image, threshold)
|
||||||
|
.toImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image doubleThreshold(
|
||||||
|
Image image,
|
||||||
|
int threshold1,
|
||||||
|
int threshold2
|
||||||
|
) {
|
||||||
|
return Thresholding
|
||||||
|
.doubleThreshold(image, threshold1, threshold2)
|
||||||
|
.toImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image automaticThreshold(Image image) {
|
||||||
|
return Thresholding
|
||||||
|
.automaticThreshold(image)
|
||||||
|
.toImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/main/java/ui/abstractions/IThresholdingView.java
Normal file
12
src/main/java/ui/abstractions/IThresholdingView.java
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package ui.abstractions;
|
||||||
|
|
||||||
|
import domain.image.Image;
|
||||||
|
|
||||||
|
public interface IThresholdingView {
|
||||||
|
|
||||||
|
void updateSimpleThreshold(Image image);
|
||||||
|
|
||||||
|
void updateDoubleThreshold(Image image);
|
||||||
|
|
||||||
|
void updateAutomaticThreshold(Image image);
|
||||||
|
}
|
||||||
@@ -33,9 +33,10 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
private JMenu drawingMenu;
|
private JMenu drawingMenu;
|
||||||
private JMenu fourierMenu;
|
private JMenu fourierMenu;
|
||||||
private JMenu linearMenu;
|
private JMenu linearMenu;
|
||||||
private JMenu histogramMenu;
|
|
||||||
private JMenu morphologyMenu;
|
private JMenu morphologyMenu;
|
||||||
private Menu outlineMenu;
|
private Menu outlineMenu;
|
||||||
|
private Menu thresholdingMenu;
|
||||||
|
private JMenu histogramMenu;
|
||||||
|
|
||||||
private NavPresenter presenter;
|
private NavPresenter presenter;
|
||||||
|
|
||||||
@@ -103,6 +104,10 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
new MenuItem("Non-linéaire", this::displayNonLinearOutline)
|
new MenuItem("Non-linéaire", this::displayNonLinearOutline)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
thresholdingMenu = new Menu("Seuillage","/cp_51_p1.jpg",
|
||||||
|
new MenuItem("Afficher", this::displayThresholding)
|
||||||
|
);
|
||||||
|
|
||||||
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)
|
||||||
);
|
);
|
||||||
@@ -113,6 +118,7 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
this.add(linearMenu);
|
this.add(linearMenu);
|
||||||
this.add(morphologyMenu);
|
this.add(morphologyMenu);
|
||||||
this.add(outlineMenu);
|
this.add(outlineMenu);
|
||||||
|
this.add(thresholdingMenu);
|
||||||
this.add(histogramMenu);
|
this.add(histogramMenu);
|
||||||
|
|
||||||
drawingMenu.setEnabled(false);
|
drawingMenu.setEnabled(false);
|
||||||
@@ -120,9 +126,12 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
linearMenu.setEnabled(false);
|
linearMenu.setEnabled(false);
|
||||||
morphologyMenu.setEnabled(false);
|
morphologyMenu.setEnabled(false);
|
||||||
outlineMenu.setEnabled(false);
|
outlineMenu.setEnabled(false);
|
||||||
|
thresholdingMenu.setEnabled(false);
|
||||||
histogramMenu.setEnabled(false);
|
histogramMenu.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//####################################################
|
//####################################################
|
||||||
|
|
||||||
private File chooseFile(){
|
private File chooseFile(){
|
||||||
@@ -190,6 +199,7 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
linearMenu.setEnabled(true);
|
linearMenu.setEnabled(true);
|
||||||
morphologyMenu.setEnabled(true);
|
morphologyMenu.setEnabled(true);
|
||||||
outlineMenu.setEnabled(true);
|
outlineMenu.setEnabled(true);
|
||||||
|
thresholdingMenu.setEnabled(true);
|
||||||
histogramMenu.setEnabled(true);
|
histogramMenu.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,6 +210,7 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
linearMenu.setEnabled(false);
|
linearMenu.setEnabled(false);
|
||||||
morphologyMenu.setEnabled(false);
|
morphologyMenu.setEnabled(false);
|
||||||
outlineMenu.setEnabled(false);
|
outlineMenu.setEnabled(false);
|
||||||
|
thresholdingMenu.setEnabled(false);
|
||||||
histogramMenu.setEnabled(false);
|
histogramMenu.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,6 +272,7 @@ public class NavBar extends JMenuBar implements INavBar {
|
|||||||
|
|
||||||
private void displayNonLinearOutline(ActionEvent actionEvent) { presenter.goToNonLinearOutline();}
|
private void displayNonLinearOutline(ActionEvent actionEvent) { presenter.goToNonLinearOutline();}
|
||||||
|
|
||||||
|
private void displayThresholding(ActionEvent actionEvent) { presenter.goToThresholding(); }
|
||||||
|
|
||||||
private void displayErrorMessage(String title, String message) {
|
private void displayErrorMessage(String title, String message) {
|
||||||
JOptionPane.showMessageDialog(
|
JOptionPane.showMessageDialog(
|
||||||
|
|||||||
@@ -0,0 +1,292 @@
|
|||||||
|
package ui.implementation.views.threshold;
|
||||||
|
|
||||||
|
import domain.image.Image;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import presenters.threshold.ThresholdingPresenter;
|
||||||
|
import ui.abstractions.AbstractView;
|
||||||
|
import ui.abstractions.IThresholdingView;
|
||||||
|
import ui.implementation.components.controls.SaveButton;
|
||||||
|
import ui.implementation.components.image.TabbedImagePanel;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
public class ThresholdingView extends AbstractView implements IThresholdingView {
|
||||||
|
|
||||||
|
private static final String SIMPLE_TAB_TITLE = "Simple";
|
||||||
|
private static final String DOUBLE_TAB_TITLE = "Double";
|
||||||
|
private static final String AUTOMATIC_TAB_TITLE = "Automatique";
|
||||||
|
|
||||||
|
private final ThresholdingPresenter presenter;
|
||||||
|
|
||||||
|
private TabbedImagePanel modeTab;
|
||||||
|
|
||||||
|
private JSlider thresholdSlider;
|
||||||
|
private JSlider threshold1Slider;
|
||||||
|
private JSlider threshold2Slider;
|
||||||
|
|
||||||
|
private JLabel thresholdValueLabel;
|
||||||
|
private JLabel threshold1ValueLabel;
|
||||||
|
private JLabel threshold2ValueLabel;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ThresholdingView(ThresholdingPresenter presenter) {
|
||||||
|
this.presenter = presenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initComponents() {
|
||||||
|
modeTab = new TabbedImagePanel();
|
||||||
|
|
||||||
|
modeTab.addPreviewTab(SIMPLE_TAB_TITLE);
|
||||||
|
modeTab.addPreviewTab(DOUBLE_TAB_TITLE);
|
||||||
|
modeTab.addPreviewTab(AUTOMATIC_TAB_TITLE);
|
||||||
|
|
||||||
|
thresholdSlider = createThresholdSlider(128);
|
||||||
|
threshold1Slider = createThresholdSlider(85);
|
||||||
|
threshold2Slider = createThresholdSlider(170);
|
||||||
|
|
||||||
|
thresholdValueLabel = new JLabel();
|
||||||
|
threshold1ValueLabel = new JLabel();
|
||||||
|
threshold2ValueLabel = new JLabel();
|
||||||
|
|
||||||
|
updateValueLabels();
|
||||||
|
|
||||||
|
thresholdSlider.addChangeListener(e -> {
|
||||||
|
updateValueLabels();
|
||||||
|
presenter.computeSimpleThreshold(
|
||||||
|
thresholdSlider.getValue()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
threshold1Slider.addChangeListener(e -> {
|
||||||
|
if (threshold1Slider.getValue() > threshold2Slider.getValue()) {
|
||||||
|
threshold2Slider.setValue(threshold1Slider.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
updateValueLabels();
|
||||||
|
|
||||||
|
presenter.computeDoubleThreshold(
|
||||||
|
threshold1Slider.getValue(),
|
||||||
|
threshold2Slider.getValue()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
threshold2Slider.addChangeListener(e -> {
|
||||||
|
if (threshold2Slider.getValue() < threshold1Slider.getValue()) {
|
||||||
|
threshold1Slider.setValue(threshold2Slider.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
updateValueLabels();
|
||||||
|
|
||||||
|
presenter.computeDoubleThreshold(
|
||||||
|
threshold1Slider.getValue(),
|
||||||
|
threshold2Slider.getValue()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
JButton saveButton = new SaveButton();
|
||||||
|
|
||||||
|
JPanel controlPanel = createControlPanel();
|
||||||
|
|
||||||
|
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("Seuillage");
|
||||||
|
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSlider createThresholdSlider(int value) {
|
||||||
|
JSlider slider = new JSlider(
|
||||||
|
SwingConstants.VERTICAL,
|
||||||
|
0,
|
||||||
|
255,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
|
||||||
|
slider.setMajorTickSpacing(50);
|
||||||
|
slider.setMinorTickSpacing(10);
|
||||||
|
slider.setPaintTicks(true);
|
||||||
|
slider.setPaintLabels(true);
|
||||||
|
|
||||||
|
slider.setLabelTable(slider.createStandardLabels(50));
|
||||||
|
|
||||||
|
return slider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JPanel createControlPanel() {
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
|
||||||
|
GroupLayout layout = new GroupLayout(panel);
|
||||||
|
panel.setLayout(layout);
|
||||||
|
layout.setAutoCreateGaps(true);
|
||||||
|
layout.setAutoCreateContainerGaps(true);
|
||||||
|
|
||||||
|
JPanel simplePanel = createSliderPanel(
|
||||||
|
thresholdSlider,
|
||||||
|
thresholdValueLabel
|
||||||
|
);
|
||||||
|
|
||||||
|
JPanel double1Panel = createSliderPanel(
|
||||||
|
threshold1Slider,
|
||||||
|
threshold1ValueLabel
|
||||||
|
);
|
||||||
|
|
||||||
|
JPanel double2Panel = createSliderPanel(
|
||||||
|
threshold2Slider,
|
||||||
|
threshold2ValueLabel
|
||||||
|
);
|
||||||
|
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createSequentialGroup()
|
||||||
|
.addComponent(simplePanel)
|
||||||
|
.addComponent(double1Panel)
|
||||||
|
.addComponent(double2Panel)
|
||||||
|
);
|
||||||
|
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createParallelGroup(GroupLayout.Alignment.CENTER)
|
||||||
|
.addComponent(simplePanel)
|
||||||
|
.addComponent(double1Panel)
|
||||||
|
.addComponent(double2Panel)
|
||||||
|
);
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JPanel createSliderPanel(JSlider slider, JLabel valueLabel) {
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
|
||||||
|
GroupLayout layout = new GroupLayout(panel);
|
||||||
|
panel.setLayout(layout);
|
||||||
|
layout.setAutoCreateGaps(true);
|
||||||
|
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(GroupLayout.Alignment.CENTER)
|
||||||
|
.addComponent(slider)
|
||||||
|
.addComponent(valueLabel)
|
||||||
|
);
|
||||||
|
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createSequentialGroup()
|
||||||
|
.addComponent(slider)
|
||||||
|
.addComponent(valueLabel)
|
||||||
|
);
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateValueLabels() {
|
||||||
|
thresholdValueLabel.setText(
|
||||||
|
String.valueOf(thresholdSlider.getValue())
|
||||||
|
);
|
||||||
|
|
||||||
|
threshold1ValueLabel.setText(
|
||||||
|
String.valueOf(threshold1Slider.getValue())
|
||||||
|
);
|
||||||
|
|
||||||
|
threshold2ValueLabel.setText(
|
||||||
|
String.valueOf(threshold2Slider.getValue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initValues() {
|
||||||
|
modeTab.addChangeListener(e -> {
|
||||||
|
updateControls();
|
||||||
|
applyThreshold();
|
||||||
|
});
|
||||||
|
|
||||||
|
presenter.setView(this);
|
||||||
|
|
||||||
|
updateControls();
|
||||||
|
applyThreshold();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateControls() {
|
||||||
|
int operation = modeTab.getSelectedIndex();
|
||||||
|
|
||||||
|
thresholdSlider.setVisible(operation == 0);
|
||||||
|
|
||||||
|
threshold1Slider.setVisible(operation == 1);
|
||||||
|
threshold2Slider.setVisible(operation == 1);
|
||||||
|
|
||||||
|
thresholdValueLabel.setVisible(operation == 0);
|
||||||
|
|
||||||
|
threshold1ValueLabel.setVisible(operation == 1);
|
||||||
|
threshold2ValueLabel.setVisible(operation == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyThreshold() {
|
||||||
|
switch (modeTab.getSelectedIndex()) {
|
||||||
|
case 0 -> presenter.computeSimpleThreshold(
|
||||||
|
thresholdSlider.getValue()
|
||||||
|
);
|
||||||
|
|
||||||
|
case 1 -> presenter.computeDoubleThreshold(
|
||||||
|
threshold1Slider.getValue(),
|
||||||
|
threshold2Slider.getValue()
|
||||||
|
);
|
||||||
|
|
||||||
|
case 2 -> presenter.computeAutomaticThreshold();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateSimpleThreshold(Image image) {
|
||||||
|
modeTab.loadImage(SIMPLE_TAB_TITLE, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateDoubleThreshold(Image image) {
|
||||||
|
modeTab.loadImage(DOUBLE_TAB_TITLE, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateAutomaticThreshold(Image image) {
|
||||||
|
modeTab.loadImage(AUTOMATIC_TAB_TITLE, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disposeCore() {
|
||||||
|
presenter.setView(null);
|
||||||
|
presenter.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user