Add convolution and mean filtering

This commit is contained in:
2026-09-22 18:04:45 +02:00
parent 048ff5c792
commit 11aceb1f67
19 changed files with 602 additions and 68 deletions

View File

@@ -6,18 +6,17 @@ import com.google.common.eventbus.EventBus;
import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
import presenters.doubleMatrix.DoubleMatrixPresenter;
import presenters.filtering.FilteringPresenter;
import presenters.filtering.global.GlobalFilteringPresenter;
import presenters.MainPresenter;
import presenters.NavPresenter;
import presenters.filtering.local.LocalFilteringPresenter;
import services.ImageService;
import ui.abstractions.*;
import ui.implementation.components.nav.NavBar;
import ui.implementation.views.DoubleMatrix;
import ui.implementation.views.IdealFilteringView;
import ui.implementation.views.fitering.global.IdealFilteringView;
import ui.implementation.views.MainView;
import ui.abstractions.IDoubleMatrix;
import ui.abstractions.IFilteringView;
import ui.abstractions.IMainView;
import ui.abstractions.INavBar;
import ui.implementation.views.fitering.local.LocalFilteringView;
/**
* Gathers some configurations in order to set the dependency injection container up
@@ -40,13 +39,15 @@ public class AppModule extends AbstractModule {
bind(INavBar.class).to(NavBar.class);
bind(IMainView.class).to(MainView.class);
bind(IDoubleMatrix.class).to(DoubleMatrix.class);
bind(IFilteringView.class).to(IdealFilteringView.class);
bind(IGlobalFilteringView.class).to(IdealFilteringView.class);
bind(ILocalFilteringView.class).to(LocalFilteringView.class);
//--- Presentation layer ---
bind(MainPresenter.class);
bind(NavPresenter.class);
bind(DoubleMatrixPresenter.class);
bind(FilteringPresenter.class);
bind(GlobalFilteringPresenter.class);
bind(LocalFilteringPresenter.class);
//--- Service layer layer ---
bind(ImageService.class);

View File

@@ -10,6 +10,7 @@ public interface INavigator {
* Displays Fourier view
*/
void showFourier();
void showFiltering();
void showIdealFiltering();
void showButterworth();
void showConvolutionFiltering();
}

View File

@@ -3,9 +3,10 @@ package app;
import com.google.inject.Inject;
import com.google.inject.Provider;
import ui.implementation.views.DoubleMatrix;
import ui.implementation.views.IdealFilteringView;
import ui.implementation.views.NonIdealFilteringView;
import ui.implementation.views.fitering.global.IdealFilteringView;
import ui.implementation.views.fitering.global.NonIdealFilteringView;
import ui.implementation.views.ViewInitializer;
import ui.implementation.views.fitering.local.LocalFilteringView;
/**
* Concrete implement of the INavigator interface.
@@ -17,16 +18,19 @@ public class SwingNavigator implements INavigator {
private final Provider<DoubleMatrix> doubleMatrixProvider;
private final Provider<IdealFilteringView> filteringProvider;
private final Provider<NonIdealFilteringView> nonIdealFilteringProvider;
private final Provider<LocalFilteringView> convolutionFilteringProvider;
@Inject
public SwingNavigator(
Provider<DoubleMatrix> doubleMatrixProvider,
Provider<IdealFilteringView> filteringProvider,
Provider<NonIdealFilteringView> nonIdealFilteringProvider
Provider<NonIdealFilteringView> nonIdealFilteringProvider,
Provider<LocalFilteringView> convolutionFilterProvider
) {
this.doubleMatrixProvider = doubleMatrixProvider;
this.filteringProvider = filteringProvider;
this.nonIdealFilteringProvider = nonIdealFilteringProvider;
this.convolutionFilteringProvider = convolutionFilterProvider;
}
@Override
@@ -37,7 +41,7 @@ public class SwingNavigator implements INavigator {
}
@Override
public void showFiltering() {
public void showIdealFiltering() {
IdealFilteringView view = filteringProvider.get();
ViewInitializer.Initialize(view);
view.setVisible(true);
@@ -49,4 +53,12 @@ public class SwingNavigator implements INavigator {
ViewInitializer.Initialize(view);
view.setVisible(true);
}
@Override
public void showConvolutionFiltering() {
LocalFilteringView view = convolutionFilteringProvider.get();
ViewInitializer.Initialize(view);
view.setVisible(true);
}
}

View File

@@ -2,27 +2,27 @@ package app.state;
import com.google.inject.Inject;
import domain.image.Image;
import presenters.filtering.FilteringListener;
import presenters.filtering.global.GlobalFilteringListener;
import java.util.ArrayList;
import java.util.List;
public class FilteringState extends State {
public class GlobalFilteringState extends State {
private Image lowPass;
private Image highPass;
private Image butterworthLowPass;
private Image butterworthHighPass;
private final List<FilteringListener> listeners = new ArrayList<>();
private final List<GlobalFilteringListener> listeners = new ArrayList<>();
@Inject
public FilteringState() {}
public GlobalFilteringState() {}
public void subscribe(FilteringListener listener) {
public void subscribe(GlobalFilteringListener listener) {
listeners.add(listener);
}
public void unsubscribe(FilteringListener listener) {
public void unsubscribe(GlobalFilteringListener listener) {
listeners.remove(listener);
}

View File

@@ -0,0 +1,45 @@
package app.state;
import com.google.inject.Inject;
import domain.image.Image;
import presenters.filtering.global.GlobalFilteringListener;
import presenters.filtering.local.LocalFilteringListener;
import java.util.ArrayList;
import java.util.List;
public class LocalFilteringState extends State {
private Image convolution;
private Image mean;
private final List<LocalFilteringListener> listeners = new ArrayList<>();
@Inject
public LocalFilteringState() {}
public void subscribe(LocalFilteringListener listener) {
listeners.add(listener);
}
public void unsubscribe(LocalFilteringListener listener) {
listeners.remove(listener);
}
public void setConvolution(Image image) {
convolution = image;
listeners.forEach(listener -> listener.onConvolutionChanged(image));
}
public void setMean(Image image) {
mean = image;
listeners.forEach(listener -> listener.onMeanChanged(image));
}
public Image getConvolution() {
return convolution;
}
public Image getMean() {
return mean;
}
}

View File

@@ -0,0 +1,120 @@
package domain.image.processing.filtering;
import domain.image.GrayScaleMatrix;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.imgproc.Imgproc;
public class LocalLinearFiltering {
public static GrayScaleMatrix convolutionMask(GrayScaleMatrix matrix, double[][] mask) {
validateMask(mask);
return applyMask(matrix, mask);
}
public static GrayScaleMatrix meanFilter(GrayScaleMatrix matrix, int maskSize) {
validateMaskSize(maskSize);
double coefficient = 1.0 / (maskSize * maskSize);
double[][] mask = new double[maskSize][maskSize];
for (int y = 0; y < maskSize; y++) {
for (int x = 0; x < maskSize; x++) {
mask[y][x] = coefficient;
}
}
return applyMask(matrix, mask);
}
private static GrayScaleMatrix applyMask(GrayScaleMatrix matrix, double[][] mask) {
Mat source = toMat(matrix);
int maskSize = mask.length;
Mat kernel = new Mat(maskSize, maskSize, CvType.CV_64F);
for (int y = 0; y < maskSize; y++) {
for (int x = 0; x < maskSize; x++) {
kernel.put(y, x, mask[y][x]);
}
}
Mat destination = new Mat();
Imgproc.filter2D(
source,
destination,
CvType.CV_64F,
kernel,
new Point(-1, -1),
0,
Core.BORDER_REPLICATE
);
GrayScaleMatrix result = fromMat(destination);
source.release();
kernel.release();
destination.release();
return result;
}
private static void validateMask(double[][] mask) {
if (mask == null || mask.length == 0 || mask.length % 2 == 0) {
throw new IllegalArgumentException(
"Le masque doit être une matrice carrée de dimension impaire."
);
}
int size = mask.length;
for (double[] row : mask) {
if (row == null || row.length != size) {
throw new IllegalArgumentException(
"Le masque doit être une matrice carrée."
);
}
}
}
private static void validateMaskSize(int maskSize) {
if (maskSize <= 0 || maskSize % 2 == 0) {
throw new IllegalArgumentException(
"La taille du masque doit être un entier positif impair."
);
}
}
private static Mat toMat(GrayScaleMatrix matrix) {
double[][] image = matrix.getRawData();
int height = image.length;
int width = image[0].length;
Mat mat = new Mat(height, width, CvType.CV_64F);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
mat.put(y, x, image[y][x]);
}
}
return mat;
}
private static GrayScaleMatrix fromMat(Mat mat) {
int height = mat.rows();
int width = mat.cols();
double[][] result = new double[height][width];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
result[y][x] = Math.clamp(mat.get(y, x)[0], 0.0, 255.0);
}
}
return new GrayScaleMatrix(result);
}
}

View File

@@ -47,9 +47,12 @@ public class NavPresenter {
}
public void goToFiltering() {
navigator.showFiltering();
navigator.showIdealFiltering();
}
public void goToConvolution() {
navigator.showConvolutionFiltering();
}
public void gotToButterworth() {
navigator.showButterworth();

View File

@@ -1,9 +1,9 @@
package presenters.filtering;
package presenters.filtering.global;
import domain.events.listeners.Listener;
import domain.image.Image;
public interface FilteringListener extends Listener {
public interface GlobalFilteringListener extends Listener {
void onLowPassChanged(Image image);
void onHighPassChanged(Image image);
void onButterworthLowPassChanged(Image image);

View File

@@ -1,23 +1,23 @@
package presenters.filtering;
package presenters.filtering.global;
import app.state.AppState;
import app.state.FilteringState;
import app.state.GlobalFilteringState;
import com.google.inject.Inject;
import domain.image.GrayScaleMatrix;
import domain.image.Image;
import services.FilteringService;
import services.GlobalFilteringService;
import services.ImageService;
import ui.abstractions.IFilteringView;
import ui.abstractions.IGlobalFilteringView;
public class FilteringPresenter implements FilteringListener {
public class GlobalFilteringPresenter implements GlobalFilteringListener {
private final AppState appState;
private final FilteringState state;
private final GlobalFilteringState state;
private final ImageService imageService;
private final FilteringService filteringService;
private IFilteringView view;
private final GlobalFilteringService filteringService;
private IGlobalFilteringView view;
@Inject
public FilteringPresenter(AppState appState, FilteringState state, ImageService imageService, FilteringService filteringService) {
public GlobalFilteringPresenter(AppState appState, GlobalFilteringState state, ImageService imageService, GlobalFilteringService filteringService) {
this.appState = appState;
this.state = state;
this.imageService = imageService;
@@ -25,7 +25,7 @@ public class FilteringPresenter implements FilteringListener {
this.state.subscribe(this);
}
public void setView(IFilteringView view) {
public void setView(IGlobalFilteringView view) {
this.view = view;
}

View File

@@ -0,0 +1,10 @@
package presenters.filtering.local;
import domain.image.Image;
public interface LocalFilteringListener {
void onConvolutionChanged(Image image);
void onMeanChanged(Image image);
}

View File

@@ -0,0 +1,66 @@
package presenters.filtering.local;
import app.state.AppState;
import app.state.LocalFilteringState;
import domain.image.Image;
import jakarta.inject.Inject;
import services.ImageService;
import services.LocalFilteringService;
import ui.abstractions.ILocalFilteringView;
public class LocalFilteringPresenter implements LocalFilteringListener {
private final AppState appState;
private final LocalFilteringState state;
private final ImageService imageService;
private final LocalFilteringService filteringService;
private ILocalFilteringView view;
@Inject
public LocalFilteringPresenter(
AppState appState,
LocalFilteringState state,
ImageService imageService,
LocalFilteringService filteringService
) {
this.appState = appState;
this.state = state;
this.imageService = imageService;
this.filteringService = filteringService;
this.state.subscribe(this);
}
public void setView(ILocalFilteringView view) {
this.view = view;
}
public void computeConvolutionFiltering(double[][] mask) {
Image image = filteringService.applyConvolutionMask(appState.getImage(), mask);
state.setConvolution(image);
}
public void computeMeanFiltering(int value) {
Image image = filteringService.applyMeanFilter(appState.getImage(),value);
state.setMean(image);
}
@Override
public void onConvolutionChanged(Image image) {
if (view != null) {
view.updateConvolutionFiltering(image);
}
}
@Override
public void onMeanChanged(Image image) {
if (view != null) {
view.updateMeanFiltering(image);
}
}
public void dispose() {
state.unsubscribe(this);
}
}

View File

@@ -4,7 +4,7 @@ import domain.image.GrayScaleMatrix;
import domain.image.Image;
import domain.image.processing.filtering.GlobalLinearFiltering;
public class FilteringService {
public class GlobalFilteringService {
public Image lowPassFiltering(GrayScaleMatrix matrix, double percentage) {
double cutoff = percentage * getMaxCutoff(matrix.getWidth(), matrix.getHeight());

View File

@@ -0,0 +1,23 @@
package services;
import domain.image.GrayScaleMatrix;
import domain.image.Image;
import domain.image.processing.filtering.LocalLinearFiltering;
public class LocalFilteringService {
public Image applyConvolutionMask(Image image, double[][] mask) {
GrayScaleMatrix result = LocalLinearFiltering.convolutionMask(getGrayScale(image), mask);
return result.toImage();
}
public Image applyMeanFilter(Image image, int maskSize) {
GrayScaleMatrix result = LocalLinearFiltering.meanFilter(getGrayScale(image), maskSize);
return result.toImage();
}
private GrayScaleMatrix getGrayScale(Image image) {
return image.toGrayScale();
}
}

View File

@@ -2,7 +2,7 @@ package ui.abstractions;
import domain.image.Image;
public interface IFilteringView {
public interface IGlobalFilteringView {
void updateLowPassFiltering(Image image);
void updateHighPassFiltering(Image image);
void updateButterworthHighPassFiltering(Image image);

View File

@@ -0,0 +1,10 @@
package ui.abstractions;
import domain.image.Image;
public interface ILocalFilteringView {
void updateConvolutionFiltering(Image image);
void updateMeanFiltering(Image image);
}

View File

@@ -86,7 +86,7 @@ public class NavBar extends JMenuBar implements INavBar {
new MenuItem("Butterworth", this::displayButterworth)
),
new Menu("Local",
new MenuItem("Masque de convolution", this::displayIdealFilter),
new MenuItem("Masque de convolution", this::displayConvolution),
new MenuItem("Filtre moyenneur", this::displayButterworth)
)
);
@@ -107,6 +107,7 @@ public class NavBar extends JMenuBar implements INavBar {
histogramMenu.setEnabled(false);
}
//####################################################
private File chooseFile(){
@@ -229,6 +230,10 @@ public class NavBar extends JMenuBar implements INavBar {
presenter.gotToButterworth();
}
private void displayConvolution(ActionEvent actionEvent) {
presenter.goToConvolution();
}
private void displayErrorMessage(String title, String message) {
JOptionPane.showMessageDialog(
this,

View File

@@ -1,18 +1,18 @@
package ui.implementation.views;
package ui.implementation.views.fitering.global;
import com.google.inject.Inject;
import domain.image.Image;
import presenters.filtering.FilteringPresenter;
import presenters.filtering.global.GlobalFilteringPresenter;
import ui.abstractions.AbstractView;
import ui.implementation.components.controls.IntensitySlider;
import ui.implementation.components.controls.SaveButton;
import ui.abstractions.IFilteringView;
import ui.abstractions.IGlobalFilteringView;
import ui.implementation.components.image.TabbedImagePanel;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
public class IdealFilteringView extends AbstractView implements IFilteringView {
public class IdealFilteringView extends AbstractView implements IGlobalFilteringView {
private final static String LOW_PASS_TAB_TITLE = "Passe-bas";
private final static String HIGH_PASS_TAB_TITLE = "Passe-haut";
@@ -20,35 +20,14 @@ public class IdealFilteringView extends AbstractView implements IFilteringView {
private TabbedImagePanel modeTab;
private IntensitySlider intensitySlider;
private JLabel intensityLabel;
private final FilteringPresenter presenter;
private final GlobalFilteringPresenter presenter;
private boolean isUpdating;
@Inject
public IdealFilteringView(FilteringPresenter presenter) {
public IdealFilteringView(GlobalFilteringPresenter presenter) {
this.presenter = presenter;
}
@Override
public void initComponents(){
this.intensityLabel = new JLabel();
this.intensitySlider = new IntensitySlider(0, 1000);
this.intensitySlider.setOrientation(JSlider.VERTICAL);
this.modeTab = new TabbedImagePanel();
this.modeTab.addPreviewTab(LOW_PASS_TAB_TITLE);
this.modeTab.addPreviewTab(HIGH_PASS_TAB_TITLE);
JButton saveButton = new SaveButton();
saveButton.addActionListener(e -> {});
buildLayout(modeTab, intensityLabel, intensitySlider, saveButton);
setTitle("Filtre idéal");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
pack();
}
private void buildLayout(JTabbedPane modeTab,
JLabel valueTextField,
@@ -165,6 +144,27 @@ public class IdealFilteringView extends AbstractView implements IFilteringView {
}
@Override
public void initComponents(){
this.intensityLabel = new JLabel();
this.intensitySlider = new IntensitySlider(0, 1000);
this.intensitySlider.setOrientation(JSlider.VERTICAL);
this.modeTab = new TabbedImagePanel();
this.modeTab.addPreviewTab(LOW_PASS_TAB_TITLE);
this.modeTab.addPreviewTab(HIGH_PASS_TAB_TITLE);
JButton saveButton = new SaveButton();
saveButton.addActionListener(e -> {});
buildLayout(modeTab, intensityLabel, intensitySlider, saveButton);
setTitle("Filtre idéal");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
pack();
}
@Override
public void initValues(){
this.presenter.setView(this);

View File

@@ -1,10 +1,10 @@
package ui.implementation.views;
package ui.implementation.views.fitering.global;
import com.google.inject.Inject;
import domain.image.Image;
import presenters.filtering.FilteringPresenter;
import presenters.filtering.global.GlobalFilteringPresenter;
import ui.abstractions.AbstractView;
import ui.abstractions.IFilteringView;
import ui.abstractions.IGlobalFilteringView;
import ui.implementation.components.controls.IntensitySlider;
import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.TabbedImagePanel;
@@ -12,7 +12,7 @@ import ui.implementation.components.image.TabbedImagePanel;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
public class NonIdealFilteringView extends AbstractView implements IFilteringView {
public class NonIdealFilteringView extends AbstractView implements IGlobalFilteringView {
private final static String LOW_PASS_TAB_TITLE = "Passe-bas";
private final static String HIGH_PASS_TAB_TITLE = "Passe-haut";
@@ -22,11 +22,11 @@ public class NonIdealFilteringView extends AbstractView implements IFilteringVie
private IntensitySlider orderSlider;
private JLabel intensityLabel;
private JLabel orderLabel;
private final FilteringPresenter presenter;
private final GlobalFilteringPresenter presenter;
private boolean isUpdating;
@Inject
public NonIdealFilteringView(FilteringPresenter presenter) {
public NonIdealFilteringView(GlobalFilteringPresenter presenter) {
this.presenter = presenter;
}

View File

@@ -0,0 +1,238 @@
package ui.implementation.views.fitering.local;
import domain.image.Image;
import jakarta.inject.Inject;
import presenters.filtering.local.LocalFilteringPresenter;
import ui.abstractions.AbstractView;
import ui.abstractions.ILocalFilteringView;
import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.TabbedImagePanel;
import javax.swing.*;
import java.awt.*;
public class LocalFilteringView extends AbstractView implements ILocalFilteringView {
private static final String CONVOLUTION_TAB_TITLE = "Convolution";
private static final String MEAN_TAB_TITLE = "Moyenneur";
private final LocalFilteringPresenter presenter;
private TabbedImagePanel modeTab;
private JTextField convolutionSizeField;
private JPanel convolutionMaskPanel;
private JTextField[][] convolutionMaskFields;
private JTextField meanSizeField;
@Inject
public LocalFilteringView(LocalFilteringPresenter presenter) {
this.presenter = presenter;
}
@Override
public void initComponents() {
modeTab = new TabbedImagePanel();
modeTab.addPreviewTab(CONVOLUTION_TAB_TITLE);
modeTab.addPreviewTab(MEAN_TAB_TITLE);
convolutionSizeField = new JTextField("3", 5);
JButton createMaskButton = new JButton("Créer le masque");
createMaskButton.addActionListener(e -> createConvolutionMask());
convolutionMaskPanel = new JPanel();
JButton applyConvolutionButton = new JButton("Appliquer convolution");
applyConvolutionButton.addActionListener(e -> applyConvolution());
meanSizeField = new JTextField("3", 5);
JButton applyMeanButton = new JButton("Appliquer moyenneur");
applyMeanButton.addActionListener(e -> applyMean());
JButton saveButton = new SaveButton();
buildLayout(
modeTab,
convolutionSizeField,
createMaskButton,
convolutionMaskPanel,
applyConvolutionButton,
meanSizeField,
applyMeanButton,
saveButton
);
setTitle("Filtrage linéaire local");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
pack();
}
@Override
public void initValues() {
presenter.setView(this);
createConvolutionMask();
}
private void createConvolutionMask() {
try {
int size = Integer.parseInt(convolutionSizeField.getText());
if (size <= 0 || size % 2 == 0) {
return;
}
convolutionMaskPanel.removeAll();
convolutionMaskPanel.setLayout(new GridLayout(size, size, 3, 3));
convolutionMaskFields = new JTextField[size][size];
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
JTextField field = new JTextField("0");
field.setHorizontalAlignment(JTextField.CENTER);
convolutionMaskFields[y][x] = field;
convolutionMaskPanel.add(field);
}
}
convolutionMaskPanel.revalidate();
convolutionMaskPanel.repaint();
} catch (NumberFormatException ignored) {
}
}
private void applyConvolution() {
try {
double[][] mask = new double[convolutionMaskFields.length][convolutionMaskFields.length];
for (int y = 0; y < mask.length; y++) {
for (int x = 0; x < mask.length; x++) {
mask[y][x] = Double.parseDouble(convolutionMaskFields[y][x].getText());
}
}
presenter.computeConvolutionFiltering(mask);
} catch (NumberFormatException ignored) {
}
}
private void applyMean() {
try {
int maskSize = Integer.parseInt(meanSizeField.getText());
if (maskSize <= 0 || maskSize % 2 == 0) {
return;
}
presenter.computeMeanFiltering(maskSize);
} catch (NumberFormatException ignored) {
}
}
public void updateConvolutionFiltering(Image image) {
modeTab.loadImage(CONVOLUTION_TAB_TITLE, image);
}
public void updateMeanFiltering(Image image) {
modeTab.loadImage(MEAN_TAB_TITLE, image);
}
@Override
public void disposeCore() {
presenter.setView(null);
presenter.dispose();
}
private void buildLayout(
JComponent imagePanel,
JTextField convolutionSizeField,
JButton createMaskButton,
JPanel convolutionMaskPanel,
JButton applyConvolutionButton,
JTextField meanSizeField,
JButton applyMeanButton,
JButton saveButton
) {
JPanel convolutionPanel = new JPanel();
GroupLayout convolutionLayout = new GroupLayout(convolutionPanel);
convolutionPanel.setLayout(convolutionLayout);
convolutionLayout.setAutoCreateGaps(true);
convolutionLayout.setAutoCreateContainerGaps(true);
convolutionLayout.setHorizontalGroup(
convolutionLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(convolutionSizeField, GroupLayout.PREFERRED_SIZE, 60, GroupLayout.PREFERRED_SIZE)
.addComponent(createMaskButton)
.addComponent(convolutionMaskPanel)
.addComponent(applyConvolutionButton)
);
convolutionLayout.setVerticalGroup(
convolutionLayout.createSequentialGroup()
.addComponent(convolutionSizeField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(createMaskButton)
.addComponent(convolutionMaskPanel)
.addComponent(applyConvolutionButton)
);
JPanel meanPanel = new JPanel();
GroupLayout meanLayout = new GroupLayout(meanPanel);
meanPanel.setLayout(meanLayout);
meanLayout.setAutoCreateGaps(true);
meanLayout.setAutoCreateContainerGaps(true);
meanLayout.setHorizontalGroup(
meanLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(meanSizeField, GroupLayout.PREFERRED_SIZE, 60, GroupLayout.PREFERRED_SIZE)
.addComponent(applyMeanButton)
);
meanLayout.setVerticalGroup(
meanLayout.createSequentialGroup()
.addComponent(meanSizeField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(applyMeanButton)
);
JPanel rightPanel = new JPanel();
JTabbedPane operationTabs = new JTabbedPane();
operationTabs.addTab("Convolution", convolutionPanel);
operationTabs.addTab("Moyenneur", meanPanel);
GroupLayout rightLayout = new GroupLayout(rightPanel);
rightPanel.setLayout(rightLayout);
rightLayout.setAutoCreateGaps(true);
rightLayout.setAutoCreateContainerGaps(true);
rightLayout.setHorizontalGroup(
rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(operationTabs)
.addComponent(saveButton)
);
rightLayout.setVerticalGroup(
rightLayout.createSequentialGroup()
.addComponent(operationTabs)
.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(imagePanel)
.addComponent(rightPanel)
);
mainLayout.setVerticalGroup(
mainLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(imagePanel)
.addComponent(rightPanel)
);
setContentPane(mainPanel);
}
}