Clean some stuff

This commit is contained in:
2026-10-04 13:03:49 +02:00
parent 114da44ff4
commit 6373978aac
8 changed files with 249 additions and 363 deletions

View File

@@ -8,43 +8,34 @@ import org.opencv.core.Mat;
public class GlobalLinearFiltering {
public static GrayScaleMatrix lowPassFiltering(GrayScaleMatrix matrix, double cutoff) {
int width = matrix.getWidth();
int height = matrix.getHeight();
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
validateCutoff(cutoff, width, height);
Mat mat = toMat(matrix);
Mat spectrum = fourierTransform(mat);
Mat spectrum = fourierTransform(toMat(matrix));
shiftSpectrum(spectrum);
applyIdealLowPassFilter(spectrum, cutoff);
shiftSpectrum(spectrum);
Mat filtered = inverseFourierTransform(spectrum);
return toGrayScaleMatrix(filtered);
}
public static GrayScaleMatrix highPassFiltering(GrayScaleMatrix matrix, double cutoff) {
int width = matrix.getWidth();
int height = matrix.getHeight();
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
validateCutoff(cutoff, width, height);
Mat mat = toMat(matrix);
Mat spectrum = fourierTransform(mat);
Mat spectrum = fourierTransform(toMat(matrix));
shiftSpectrum(spectrum);
applyIdealHighPassFilter(spectrum, cutoff);
shiftSpectrum(spectrum);
Mat filtered = inverseFourierTransform(spectrum);
return toGrayScaleMatrix(filtered);
}
public static GrayScaleMatrix butterworthLowPassFiltering(GrayScaleMatrix matrix, double cutoff, int order) {
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
validateOrder(order);
Mat spectrum = fourierTransform(toMat(matrix));
@@ -52,11 +43,13 @@ public class GlobalLinearFiltering {
applyButterworthLowPassFilter(spectrum, cutoff, order);
shiftSpectrum(spectrum);
return toGrayScaleMatrix(inverseFourierTransform(spectrum));
Mat filtered = inverseFourierTransform(spectrum);
return toGrayScaleMatrix(filtered);
}
public static GrayScaleMatrix butterworthHighPassFiltering(GrayScaleMatrix matrix, double cutoff, int order) {
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
validateOrder(order);
Mat spectrum = fourierTransform(toMat(matrix));
@@ -64,25 +57,23 @@ public class GlobalLinearFiltering {
applyButterworthHighPassFilter(spectrum, cutoff, order);
shiftSpectrum(spectrum);
return toGrayScaleMatrix(inverseFourierTransform(spectrum));
Mat filtered = inverseFourierTransform(spectrum);
return toGrayScaleMatrix(filtered);
}
private static void applyIdealLowPassFilter(Mat spectrum, double cutoff) {
int width = spectrum.cols();
int height = spectrum.rows();
int cx = width / 2;
int cy = height / 2;
double cx = width / 2.0;
double cy = height / 2.0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
double distance = Math.sqrt(
Math.pow(x - cx, 2) + Math.pow(y - cy, 2)
);
double distance = distance(x, y, cx, cy);
if (distance > cutoff) {
spectrum.put(y, x, 0, 0);
spectrum.put(y, x, 0.0, 0.0);
}
}
}
@@ -92,16 +83,15 @@ public class GlobalLinearFiltering {
int width = spectrum.cols();
int height = spectrum.rows();
int cx = width / 2;
int cy = height / 2;
double cx = width / 2.0;
double cy = height / 2.0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
double distance = distance(x, y, cx, cy);
if (distance <= cutoff) {
spectrum.put(y, x, 0, 0);
spectrum.put(y, x, 0.0, 0.0);
}
}
}
@@ -111,18 +101,15 @@ public class GlobalLinearFiltering {
int width = spectrum.cols();
int height = spectrum.rows();
int cx = width / 2;
int cy = height / 2;
double cx = width / 2.0;
double cy = height / 2.0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2) );
double coefficient = 1.0 / (1.0 + Math.pow(distance / cutoff, 2 * order));
double distance = distance(x, y, cx, cy);
double coefficient = 1.0 / (1.0 + Math.pow(distance / cutoff, 2.0 * order));
double[] value = spectrum.get(y, x);
spectrum.put(y, x, value[0] * coefficient, value[1] * coefficient);
}
}
@@ -132,45 +119,49 @@ public class GlobalLinearFiltering {
int width = spectrum.cols();
int height = spectrum.rows();
int cx = width / 2;
int cy = height / 2;
double cx = width / 2.0;
double cy = height / 2.0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
double distance = distance(x, y, cx, cy);
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
double coefficient;
if (distance == 0) {
coefficient = 0;
} else {
coefficient = 1.0 / (1.0 + Math.pow(cutoff / distance, 2 * order));
}
double coefficient = distance == 0.0
? 0.0
: 1.0 / (1.0 + Math.pow(cutoff / distance, 2.0 * order));
double[] value = spectrum.get(y, x);
spectrum.put(y, x, value[0] * coefficient, value[1] * coefficient);
}
}
}
private static void validateCutoff(double cutoff, int width, int height) {
double minCutoff = 0;
double maxCutoff = Math.sqrt(
Math.pow(width / 2.0, 2) +
Math.pow(height / 2.0, 2)
);
if (cutoff < minCutoff || cutoff > maxCutoff) {
throw new IllegalArgumentException(
String.format(
"Cutoff value is out of bounds (%f - %f)",
minCutoff,
maxCutoff
)
);
private static double distance(double x, double y, double cx, double cy) {
double dx = x - cx;
double dy = y - cy;
return Math.sqrt(dx * dx + dy * dy);
}
private static void shiftSpectrum(Mat spectrum) {
int width = spectrum.cols();
int height = spectrum.rows();
Mat shifted = Mat.zeros(spectrum.size(), spectrum.type());
int shiftX = width / 2;
int shiftY = height / 2;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int newX = (x + shiftX) % width;
int newY = (y + shiftY) % height;
shifted.put(newY, newX, spectrum.get(y, x));
}
}
shifted.copyTo(spectrum);
shifted.release();
}
private static Mat fourierTransform(Mat mat) {
@@ -179,54 +170,20 @@ public class GlobalLinearFiltering {
return spectrum;
}
private static void shiftSpectrum(Mat spectrum) {
int width = spectrum.cols();
int height = spectrum.rows();
int cx = width / 2;
int cy = height / 2;
Mat q0 = spectrum.submat(0, cy, 0, cx);
Mat q1 = spectrum.submat(0, cy, cx, width);
Mat q2 = spectrum.submat(cy, height, 0, cx);
Mat q3 = spectrum.submat(cy, height, cx, width);
Mat tmp = new Mat();
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
private static Mat inverseFourierTransform(Mat spectrum) {
Mat filtered = new Mat();
Core.idft(
spectrum,
filtered,
Core.DFT_REAL_OUTPUT | Core.DFT_SCALE
);
Core.idft(spectrum, filtered, Core.DFT_REAL_OUTPUT | Core.DFT_SCALE);
return filtered;
}
private static GrayScaleMatrix toGrayScaleMatrix(Mat filtered) {
int width = filtered.cols();
int height = filtered.rows();
private static GrayScaleMatrix toGrayScaleMatrix(Mat matrix) {
int width = matrix.cols();
int height = matrix.rows();
double[][] pixels = new double[height][width];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
pixels[y][x] = Math.clamp(
filtered.get(y, x)[0],
0.0,
255.0
);
pixels[y][x] = Math.clamp(matrix.get(y, x)[0], 0.0, 255.0);
}
}
@@ -236,7 +193,6 @@ public class GlobalLinearFiltering {
private static Mat toMat(GrayScaleMatrix matrix) {
int width = matrix.getWidth();
int height = matrix.getHeight();
Mat mat = new Mat(height, width, CvType.CV_64F);
double[][] data = matrix.getRawData();
@@ -248,4 +204,22 @@ public class GlobalLinearFiltering {
return mat;
}
private static void validateCutoff(double cutoff, int width, int height) {
double maxCutoff = Math.sqrt(
Math.pow(width / 2.0, 2) +
Math.pow(height / 2.0, 2)
);
if (cutoff <= 0.0 || cutoff > maxCutoff) {
throw new IllegalArgumentException(
String.format("Cutoff must be > 0 and <= %f, got %f", maxCutoff, cutoff)
);
}
}
private static void validateOrder(int order) {
if (order < 1) {
throw new IllegalArgumentException("Butterworth order must be >= 1");
}
}
}

View File

@@ -8,7 +8,6 @@ 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);
@@ -16,91 +15,69 @@ public class LocalLinearFiltering {
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 kernel = toMat(mask);
Mat destination = new Mat();
Imgproc.filter2D(
source,
destination,
CvType.CV_64F,
kernel,
new Point(-1, -1),
0,
Core.BORDER_REPLICATE
);
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."
);
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."
);
throw new IllegalArgumentException("Le masque doit être une matrice carrée.");
}
for (double value : row) {
if (!Double.isFinite(value)) {
throw new IllegalArgumentException("Le masque contient une valeur invalide.");
}
}
}
}
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."
);
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;
double[][] data = matrix.getRawData();
int height = data.length;
int width = data[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]);
mat.put(y, 0, data[y]);
}
return mat;
}
private static Mat toMat(double[][] data) {
int height = data.length;
int width = data[0].length;
Mat mat = new Mat(height, width, CvType.CV_64F);
for (int y = 0; y < height; y++) {
mat.put(y, 0, data[y]);
}
return mat;
}
@@ -108,13 +85,13 @@ public class LocalLinearFiltering {
int height = mat.rows();
int width = mat.cols();
double[][] result = new double[height][width];
for (int y = 0; y < height; y++) {
double[] row = new double[width];
mat.get(y, 0, row);
for (int x = 0; x < width; x++) {
result[y][x] = Math.clamp(mat.get(y, x)[0], 0.0, 255.0);
result[y][x] = Math.clamp(row[x], 0.0, 255.0);
}
}
return new GrayScaleMatrix(result);
}
}

View File

@@ -8,94 +8,82 @@ import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
public class BasicMorphology {
public static GrayScaleMatrix erosion(Image image, int tailleMasque) {
Mat input = toMat(image);
Mat kernel = createKernel(tailleMasque);
Mat result = new Mat();
Imgproc.erode(input, result, kernel);
return toGrayScaleMatrix(result);
GrayScaleMatrix output = toGrayScaleMatrix(result);
input.release();
kernel.release();
result.release();
return output;
}
public static GrayScaleMatrix dilation(Image image, int tailleMasque) {
Mat input = toMat(image);
Mat kernel = createKernel(tailleMasque);
Mat result = new Mat();
Imgproc.dilate(input, result, kernel);
return toGrayScaleMatrix(result);
GrayScaleMatrix output = toGrayScaleMatrix(result);
input.release();
kernel.release();
result.release();
return output;
}
public static GrayScaleMatrix opening(Image image, int tailleMasque) {
Mat input = toMat(image);
Mat kernel = createKernel(tailleMasque);
Mat result = new Mat();
Imgproc.morphologyEx(
input,
result,
Imgproc.MORPH_OPEN,
kernel
);
return toGrayScaleMatrix(result);
Imgproc.morphologyEx(input, result, Imgproc.MORPH_OPEN, kernel);
GrayScaleMatrix output = toGrayScaleMatrix(result);
input.release();
kernel.release();
result.release();
return output;
}
public static GrayScaleMatrix closing(Image image, int tailleMasque) {
Mat input = toMat(image);
Mat kernel = createKernel(tailleMasque);
Mat result = new Mat();
Imgproc.morphologyEx(
input,
result,
Imgproc.MORPH_CLOSE,
kernel
);
return toGrayScaleMatrix(result);
Imgproc.morphologyEx(input, result, Imgproc.MORPH_CLOSE, kernel);
GrayScaleMatrix output = toGrayScaleMatrix(result);
input.release();
kernel.release();
result.release();
return output;
}
private static Mat toMat(Image image) {
GrayScaleMatrix gray = image.toGrayScale();
int width = gray.getWidth();
int height = gray.getHeight();
Mat mat = new Mat(height, width, CvType.CV_64F);
double[][] data = gray.getRawData();
for (int y = 0; y < height; y++) {
mat.put(y, 0, data[y]);
}
return mat;
}
private static Mat createKernel(int tailleMasque) {
return Imgproc.getStructuringElement(
Imgproc.MORPH_RECT,
new Size(tailleMasque, tailleMasque)
);
if (tailleMasque <= 0 || tailleMasque % 2 == 0) {
throw new IllegalArgumentException("La taille du masque doit être un entier positif impair.");
}
return Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(tailleMasque, tailleMasque));
}
private static GrayScaleMatrix toGrayScaleMatrix(Mat mat) {
int width = mat.cols();
int height = mat.rows();
double[][] output = new double[height][width];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
output[y][x] = mat.get(y, x)[0];
double[] row = new double[width];
mat.get(y, 0, row);
System.arraycopy(row, 0, output[y], 0, width);
}
}
return new GrayScaleMatrix(output);
}
}

View File

@@ -11,23 +11,33 @@ import org.opencv.imgproc.Imgproc;
public class ComplexMorphology {
public static GrayScaleMatrix geodesicDilation(Image image, Image mask, int nbIter) {
if (nbIter < 0) {
throw new IllegalArgumentException("Number of iterations must be >= 0");
}
Mat maskMat = toMat(mask);
Mat current = toMat(image);
Mat kernel = createKernel(3);
for (int i = 0; i < nbIter; i++) {
Mat dilated = new Mat();
Imgproc.dilate(current, dilated, kernel);
Mat result = new Mat();
Core.min(dilated, maskMat, result);
current.release();
dilated.release();
current = result;
}
return toGrayScaleMatrix(current);
GrayScaleMatrix result = toGrayScaleMatrix(current);
current.release();
maskMat.release();
kernel.release();
return result;
}
public static GrayScaleMatrix geodesicReconstruction(Image image, Image mask) {
@@ -37,48 +47,51 @@ public class ComplexMorphology {
while (true) {
Mat dilated = new Mat();
Imgproc.dilate(current, dilated, kernel);
Mat next = new Mat();
Core.min(dilated, maskMat, next);
double difference = Core.norm(next, current, Core.NORM_INF);
if (difference == 0) {
return toGrayScaleMatrix(next);
current.release();
dilated.release();
if (difference == 0.0) {
GrayScaleMatrix result = toGrayScaleMatrix(next);
next.release();
maskMat.release();
kernel.release();
return result;
}
current = next;
}
}
public static GrayScaleMatrix medianFilter(Image image, int tailleMasque) {
if (tailleMasque < 1 || tailleMasque % 2 == 0) {
throw new IllegalArgumentException(
"Median filter size must be a positive odd number"
);
}
public static GrayScaleMatrix medianFilter(Image image, int maskSize) {
validateMedianSize(maskSize);
Mat input = to8BitMat(image);
Mat result = new Mat();
Imgproc.medianBlur(input, result, tailleMasque);
Imgproc.medianBlur(input, result, maskSize);
return toGrayScaleMatrix(result);
GrayScaleMatrix output = toGrayScaleMatrix(result);
input.release();
result.release();
return output;
}
/**
* Converts an image to a CV_64F grayscale matrix.
* Used by geodesic morphology operations.
*/
private static Mat toMat(Image image) {
GrayScaleMatrix gray = image.toGrayScale();
int width = gray.getWidth();
int height = gray.getHeight();
Mat mat = new Mat(height, width, CvType.CV_64F);
double[][] data = gray.getRawData();
@@ -90,16 +103,11 @@ public class ComplexMorphology {
return mat;
}
/**
* Converts an image to an 8-bit grayscale matrix.
* Required by OpenCV medianBlur().
*/
private static Mat to8BitMat(Image image) {
GrayScaleMatrix gray = image.toGrayScale();
int width = gray.getWidth();
int height = gray.getHeight();
Mat mat = new Mat(height, width, CvType.CV_8UC1);
double[][] data = gray.getRawData();
@@ -108,9 +116,7 @@ public class ComplexMorphology {
byte[] row = new byte[width];
for (int x = 0; x < width; x++) {
int value = (int) Math.round(data[y][x]);
value = Math.clamp(value, 0, 255);
int value = Math.clamp((int) Math.round(data[y][x]), 0, 255);
row[x] = (byte) value;
}
@@ -121,14 +127,15 @@ public class ComplexMorphology {
}
private static Mat createKernel(int size) {
return Imgproc.getStructuringElement( Imgproc.MORPH_RECT, new Size(size, size)
return Imgproc.getStructuringElement(
Imgproc.MORPH_RECT,
new Size(size, size)
);
}
private static GrayScaleMatrix toGrayScaleMatrix(Mat mat) {
int width = mat.cols();
int height = mat.rows();
double[][] output = new double[height][width];
if (mat.type() == CvType.CV_8UC1) {
@@ -150,4 +157,12 @@ public class ComplexMorphology {
return new GrayScaleMatrix(output);
}
private static void validateMedianSize(int maskSize) {
if (maskSize < 1 || maskSize % 2 == 0) {
throw new IllegalArgumentException(
"Median filter size must be a positive odd number"
);
}
}
}

View File

@@ -7,121 +7,60 @@ 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, -1, -1,
0, 0, 0,
1, 1, 1
);
kernel.put(0, 0, -1, -1, -1, 0, 0, 0, 1, 1, 1);
} else if (direction == 2) {
kernel.put(0, 0,
-1, 0, 1,
-1, 0, 1,
-1, 0, 1
);
kernel.put(0, 0, -1, 0, 1, -1, 0, 1, -1, 0, 1);
} else {
kernel.release();
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, -2, -1,
0, 0, 0,
1, 2, 1
);
kernel.put(0, 0, -1, -2, -1, 0, 0, 0, 1, 2, 1);
} else if (direction == 2) {
kernel.put(0, 0,
-1, 0, 1,
-2, 0, 2,
-1, 0, 1
);
kernel.put(0, 0, -1, 0, 1, -2, 0, 2, -1, 0, 1);
} else {
kernel.release();
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
);
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
);
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
);
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()];
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];
result.get(y, 0, output[y]);
}
}
input.release();
result.release();
kernel.release();
return new GrayScaleMatrix(output);
}
}

View File

@@ -5,48 +5,40 @@ import domain.image.Image;
import domain.image.processing.morphology.BasicMorphology;
public class NonLinearOutline {
private static final int MASK_SIZE = 3;
public static GrayScaleMatrix gradientErosion(Image image) {
GrayScaleMatrix original = image.toGrayScale();
GrayScaleMatrix erosion = BasicMorphology.erosion(image, 3);
GrayScaleMatrix erosion = BasicMorphology.erosion(image, MASK_SIZE);
return subtract(original, erosion);
}
public static GrayScaleMatrix gradientDilation(Image image) {
GrayScaleMatrix original = image.toGrayScale();
GrayScaleMatrix dilation = BasicMorphology.dilation(image, 3);
GrayScaleMatrix dilation = BasicMorphology.dilation(image, MASK_SIZE);
return subtract(dilation, original);
}
public static GrayScaleMatrix beucherGradient(Image image) {
GrayScaleMatrix erosion = BasicMorphology.erosion(image, 3);
GrayScaleMatrix dilation = BasicMorphology.dilation(image, 3);
GrayScaleMatrix erosion = BasicMorphology.erosion(image, MASK_SIZE);
GrayScaleMatrix dilation = BasicMorphology.dilation(image, MASK_SIZE);
return subtract(dilation, erosion);
}
public static GrayScaleMatrix nonLinearLaplacian(Image image) {
GrayScaleMatrix original = image.toGrayScale();
GrayScaleMatrix erosion = BasicMorphology.erosion(image, 3);
GrayScaleMatrix dilation = BasicMorphology.dilation(image, 3);
GrayScaleMatrix erosion = BasicMorphology.erosion(image, MASK_SIZE);
GrayScaleMatrix dilation = BasicMorphology.dilation(image, MASK_SIZE);
int height = original.getHeight();
int width = original.getWidth();
double[][] result = new double[height][width];
double[][] originalData = original.getRawData();
double[][] erosionData = erosion.getRawData();
double[][] dilationData = dilation.getRawData();
double[][] result = new double[height][width];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
result[y][x] =
dilationData[y][x]
+ erosionData[y][x]
- 2 * originalData[y][x];
result[y][x] = dilationData[y][x] + erosionData[y][x] - 2 * originalData[y][x];
}
}
@@ -56,16 +48,13 @@ public class NonLinearOutline {
private static GrayScaleMatrix subtract(GrayScaleMatrix first, GrayScaleMatrix second) {
int height = first.getHeight();
int width = first.getWidth();
double[][] firstData = first.getRawData();
double[][] secondData = second.getRawData();
double[][] result = new double[height][width];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
result[y][x] =
firstData[y][x] - secondData[y][x];
result[y][x] = firstData[y][x] - secondData[y][x];
}
}

View File

@@ -4,54 +4,29 @@ import domain.image.GrayScaleMatrix;
import domain.image.Image;
public class Thresholding {
public static GrayScaleMatrix simpleThreshold(
Image image,
int threshold
) {
public static GrayScaleMatrix simpleThreshold(Image image, int threshold) {
validateThreshold(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 applySimpleThreshold(gray, threshold);
}
return new GrayScaleMatrix(result);
}
public static GrayScaleMatrix doubleThreshold(
Image image,
int threshold1,
int threshold2
) {
public static GrayScaleMatrix doubleThreshold(Image image, int threshold1, int threshold2) {
validateThreshold(threshold1);
validateThreshold(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) {
@@ -67,23 +42,18 @@ public class Thresholding {
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++;
@@ -100,7 +70,6 @@ public class Thresholding {
double lowerMean = lowerSum / lowerCount;
double upperMean = upperSum / upperCount;
double newThreshold = (lowerMean + upperMean) / 2.0;
if (Math.abs(newThreshold - threshold) < 0.5) {
@@ -111,6 +80,27 @@ public class Thresholding {
threshold = newThreshold;
}
return simpleThreshold(image, (int) threshold);
return applySimpleThreshold(gray, (int) threshold);
}
private static GrayScaleMatrix applySimpleThreshold(GrayScaleMatrix gray, int threshold) {
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);
}
private static void validateThreshold(int threshold) {
if (threshold < 0 || threshold > 255) {
throw new IllegalArgumentException("Le seuil doit être compris entre 0 et 255.");
}
}
}

View File

@@ -10,10 +10,15 @@ import java.util.function.Supplier;
public class UseCaseService {
public Image reduceNoise(Image i0) {
double cutoff = 0.7 * getMaxCutoff(i0.getWidth(), i0.getHeight());
GrayScaleMatrix m0 = i0.toGrayScale();
GrayScaleMatrix m1 = GlobalLinearFiltering.butterworthLowPassFiltering(m0, 10, 1);
GrayScaleMatrix m1 = measureTime("Butterworth low pass", () -> GlobalLinearFiltering.butterworthLowPassFiltering(m0, cutoff, 1));
Image i1 = m1.toImage();
return ComplexMorphology.medianFilter(i1, 9).toImage();
return measureTime("Median filter", () -> ComplexMorphology.medianFilter(i1, 5).toImage());
}
public Image[] equalizeHistogram(Image image) {
@@ -88,10 +93,19 @@ public class UseCaseService {
return image;
}
public <T> long measureTime(Supplier<T> operation) {
public <T> T measureTime(String name, Supplier<T> operation) {
long start = System.nanoTime();
operation.get();
return (System.nanoTime() - start) / 1_000_000;
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));
}
}