Clean some stuff
This commit is contained in:
@@ -8,43 +8,34 @@ import org.opencv.core.Mat;
|
|||||||
public class GlobalLinearFiltering {
|
public class GlobalLinearFiltering {
|
||||||
|
|
||||||
public static GrayScaleMatrix lowPassFiltering(GrayScaleMatrix matrix, double cutoff) {
|
public static GrayScaleMatrix lowPassFiltering(GrayScaleMatrix matrix, double cutoff) {
|
||||||
int width = matrix.getWidth();
|
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
|
||||||
int height = matrix.getHeight();
|
|
||||||
|
|
||||||
validateCutoff(cutoff, width, height);
|
Mat spectrum = fourierTransform(toMat(matrix));
|
||||||
|
|
||||||
Mat mat = toMat(matrix);
|
|
||||||
Mat spectrum = fourierTransform(mat);
|
|
||||||
|
|
||||||
shiftSpectrum(spectrum);
|
shiftSpectrum(spectrum);
|
||||||
applyIdealLowPassFilter(spectrum, cutoff);
|
applyIdealLowPassFilter(spectrum, cutoff);
|
||||||
shiftSpectrum(spectrum);
|
shiftSpectrum(spectrum);
|
||||||
|
|
||||||
Mat filtered = inverseFourierTransform(spectrum);
|
Mat filtered = inverseFourierTransform(spectrum);
|
||||||
|
|
||||||
return toGrayScaleMatrix(filtered);
|
return toGrayScaleMatrix(filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix highPassFiltering(GrayScaleMatrix matrix, double cutoff) {
|
public static GrayScaleMatrix highPassFiltering(GrayScaleMatrix matrix, double cutoff) {
|
||||||
int width = matrix.getWidth();
|
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
|
||||||
int height = matrix.getHeight();
|
|
||||||
|
|
||||||
validateCutoff(cutoff, width, height);
|
Mat spectrum = fourierTransform(toMat(matrix));
|
||||||
|
|
||||||
Mat mat = toMat(matrix);
|
|
||||||
Mat spectrum = fourierTransform(mat);
|
|
||||||
|
|
||||||
shiftSpectrum(spectrum);
|
shiftSpectrum(spectrum);
|
||||||
applyIdealHighPassFilter(spectrum, cutoff);
|
applyIdealHighPassFilter(spectrum, cutoff);
|
||||||
shiftSpectrum(spectrum);
|
shiftSpectrum(spectrum);
|
||||||
|
|
||||||
Mat filtered = inverseFourierTransform(spectrum);
|
Mat filtered = inverseFourierTransform(spectrum);
|
||||||
|
|
||||||
return toGrayScaleMatrix(filtered);
|
return toGrayScaleMatrix(filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix butterworthLowPassFiltering(GrayScaleMatrix matrix, double cutoff, int order) {
|
public static GrayScaleMatrix butterworthLowPassFiltering(GrayScaleMatrix matrix, double cutoff, int order) {
|
||||||
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
|
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
|
||||||
|
validateOrder(order);
|
||||||
|
|
||||||
Mat spectrum = fourierTransform(toMat(matrix));
|
Mat spectrum = fourierTransform(toMat(matrix));
|
||||||
|
|
||||||
@@ -52,11 +43,13 @@ public class GlobalLinearFiltering {
|
|||||||
applyButterworthLowPassFilter(spectrum, cutoff, order);
|
applyButterworthLowPassFilter(spectrum, cutoff, order);
|
||||||
shiftSpectrum(spectrum);
|
shiftSpectrum(spectrum);
|
||||||
|
|
||||||
return toGrayScaleMatrix(inverseFourierTransform(spectrum));
|
Mat filtered = inverseFourierTransform(spectrum);
|
||||||
|
return toGrayScaleMatrix(filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix butterworthHighPassFiltering(GrayScaleMatrix matrix, double cutoff, int order) {
|
public static GrayScaleMatrix butterworthHighPassFiltering(GrayScaleMatrix matrix, double cutoff, int order) {
|
||||||
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
|
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
|
||||||
|
validateOrder(order);
|
||||||
|
|
||||||
Mat spectrum = fourierTransform(toMat(matrix));
|
Mat spectrum = fourierTransform(toMat(matrix));
|
||||||
|
|
||||||
@@ -64,25 +57,23 @@ public class GlobalLinearFiltering {
|
|||||||
applyButterworthHighPassFilter(spectrum, cutoff, order);
|
applyButterworthHighPassFilter(spectrum, cutoff, order);
|
||||||
shiftSpectrum(spectrum);
|
shiftSpectrum(spectrum);
|
||||||
|
|
||||||
return toGrayScaleMatrix(inverseFourierTransform(spectrum));
|
Mat filtered = inverseFourierTransform(spectrum);
|
||||||
|
return toGrayScaleMatrix(filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void applyIdealLowPassFilter(Mat spectrum, double cutoff) {
|
private static void applyIdealLowPassFilter(Mat spectrum, double cutoff) {
|
||||||
int width = spectrum.cols();
|
int width = spectrum.cols();
|
||||||
int height = spectrum.rows();
|
int height = spectrum.rows();
|
||||||
|
|
||||||
int cx = width / 2;
|
double cx = width / 2.0;
|
||||||
int cy = height / 2;
|
double cy = height / 2.0;
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
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)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (distance > cutoff) {
|
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 width = spectrum.cols();
|
||||||
int height = spectrum.rows();
|
int height = spectrum.rows();
|
||||||
|
|
||||||
int cx = width / 2;
|
double cx = width / 2.0;
|
||||||
int cy = height / 2;
|
double cy = height / 2.0;
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
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));
|
|
||||||
|
|
||||||
if (distance <= cutoff) {
|
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 width = spectrum.cols();
|
||||||
int height = spectrum.rows();
|
int height = spectrum.rows();
|
||||||
|
|
||||||
int cx = width / 2;
|
double cx = width / 2.0;
|
||||||
int cy = height / 2;
|
double cy = height / 2.0;
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
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 = 1.0 / (1.0 + Math.pow(distance / cutoff, 2.0 * order));
|
||||||
|
|
||||||
double coefficient = 1.0 / (1.0 + Math.pow(distance / cutoff, 2 * order));
|
|
||||||
|
|
||||||
double[] value = spectrum.get(y, x);
|
double[] value = spectrum.get(y, x);
|
||||||
|
|
||||||
spectrum.put(y, x, value[0] * coefficient, value[1] * coefficient);
|
spectrum.put(y, x, value[0] * coefficient, value[1] * coefficient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,45 +119,49 @@ public class GlobalLinearFiltering {
|
|||||||
int width = spectrum.cols();
|
int width = spectrum.cols();
|
||||||
int height = spectrum.rows();
|
int height = spectrum.rows();
|
||||||
|
|
||||||
int cx = width / 2;
|
double cx = width / 2.0;
|
||||||
int cy = height / 2;
|
double cy = height / 2.0;
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
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 = distance == 0.0
|
||||||
|
? 0.0
|
||||||
double coefficient;
|
: 1.0 / (1.0 + Math.pow(cutoff / distance, 2.0 * order));
|
||||||
|
|
||||||
if (distance == 0) {
|
|
||||||
coefficient = 0;
|
|
||||||
} else {
|
|
||||||
coefficient = 1.0 / (1.0 + Math.pow(cutoff / distance, 2 * order));
|
|
||||||
}
|
|
||||||
|
|
||||||
double[] value = spectrum.get(y, x);
|
double[] value = spectrum.get(y, x);
|
||||||
|
|
||||||
spectrum.put(y, x, value[0] * coefficient, value[1] * coefficient);
|
spectrum.put(y, x, value[0] * coefficient, value[1] * coefficient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateCutoff(double cutoff, int width, int height) {
|
private static double distance(double x, double y, double cx, double cy) {
|
||||||
double minCutoff = 0;
|
double dx = x - cx;
|
||||||
double maxCutoff = Math.sqrt(
|
double dy = y - cy;
|
||||||
Math.pow(width / 2.0, 2) +
|
return Math.sqrt(dx * dx + dy * dy);
|
||||||
Math.pow(height / 2.0, 2)
|
}
|
||||||
);
|
|
||||||
|
|
||||||
if (cutoff < minCutoff || cutoff > maxCutoff) {
|
private static void shiftSpectrum(Mat spectrum) {
|
||||||
throw new IllegalArgumentException(
|
int width = spectrum.cols();
|
||||||
String.format(
|
int height = spectrum.rows();
|
||||||
"Cutoff value is out of bounds (%f - %f)",
|
|
||||||
minCutoff,
|
Mat shifted = Mat.zeros(spectrum.size(), spectrum.type());
|
||||||
maxCutoff
|
|
||||||
)
|
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) {
|
private static Mat fourierTransform(Mat mat) {
|
||||||
@@ -179,54 +170,20 @@ public class GlobalLinearFiltering {
|
|||||||
return spectrum;
|
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) {
|
private static Mat inverseFourierTransform(Mat spectrum) {
|
||||||
Mat filtered = new Mat();
|
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;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GrayScaleMatrix toGrayScaleMatrix(Mat filtered) {
|
private static GrayScaleMatrix toGrayScaleMatrix(Mat matrix) {
|
||||||
int width = filtered.cols();
|
int width = matrix.cols();
|
||||||
int height = filtered.rows();
|
int height = matrix.rows();
|
||||||
|
|
||||||
double[][] pixels = new double[height][width];
|
double[][] pixels = new double[height][width];
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
pixels[y][x] = Math.clamp(
|
pixels[y][x] = Math.clamp(matrix.get(y, x)[0], 0.0, 255.0);
|
||||||
filtered.get(y, x)[0],
|
|
||||||
0.0,
|
|
||||||
255.0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +193,6 @@ public class GlobalLinearFiltering {
|
|||||||
private static Mat toMat(GrayScaleMatrix matrix) {
|
private static Mat toMat(GrayScaleMatrix matrix) {
|
||||||
int width = matrix.getWidth();
|
int width = matrix.getWidth();
|
||||||
int height = matrix.getHeight();
|
int height = matrix.getHeight();
|
||||||
|
|
||||||
Mat mat = new Mat(height, width, CvType.CV_64F);
|
Mat mat = new Mat(height, width, CvType.CV_64F);
|
||||||
|
|
||||||
double[][] data = matrix.getRawData();
|
double[][] data = matrix.getRawData();
|
||||||
@@ -248,4 +204,22 @@ public class GlobalLinearFiltering {
|
|||||||
return mat;
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import org.opencv.core.Point;
|
|||||||
import org.opencv.imgproc.Imgproc;
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
|
||||||
public class LocalLinearFiltering {
|
public class LocalLinearFiltering {
|
||||||
|
|
||||||
public static GrayScaleMatrix convolutionMask(GrayScaleMatrix matrix, double[][] mask) {
|
public static GrayScaleMatrix convolutionMask(GrayScaleMatrix matrix, double[][] mask) {
|
||||||
validateMask(mask);
|
validateMask(mask);
|
||||||
return applyMask(matrix, mask);
|
return applyMask(matrix, mask);
|
||||||
@@ -16,91 +15,69 @@ public class LocalLinearFiltering {
|
|||||||
|
|
||||||
public static GrayScaleMatrix meanFilter(GrayScaleMatrix matrix, int maskSize) {
|
public static GrayScaleMatrix meanFilter(GrayScaleMatrix matrix, int maskSize) {
|
||||||
validateMaskSize(maskSize);
|
validateMaskSize(maskSize);
|
||||||
|
|
||||||
double coefficient = 1.0 / (maskSize * maskSize);
|
double coefficient = 1.0 / (maskSize * maskSize);
|
||||||
double[][] mask = new double[maskSize][maskSize];
|
double[][] mask = new double[maskSize][maskSize];
|
||||||
|
|
||||||
for (int y = 0; y < maskSize; y++) {
|
for (int y = 0; y < maskSize; y++) {
|
||||||
for (int x = 0; x < maskSize; x++) {
|
for (int x = 0; x < maskSize; x++) {
|
||||||
mask[y][x] = coefficient;
|
mask[y][x] = coefficient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return applyMask(matrix, mask);
|
return applyMask(matrix, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GrayScaleMatrix applyMask(GrayScaleMatrix matrix, double[][] mask) {
|
private static GrayScaleMatrix applyMask(GrayScaleMatrix matrix, double[][] mask) {
|
||||||
Mat source = toMat(matrix);
|
Mat source = toMat(matrix);
|
||||||
int maskSize = mask.length;
|
Mat kernel = toMat(mask);
|
||||||
|
|
||||||
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();
|
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);
|
GrayScaleMatrix result = fromMat(destination);
|
||||||
|
|
||||||
source.release();
|
source.release();
|
||||||
kernel.release();
|
kernel.release();
|
||||||
destination.release();
|
destination.release();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateMask(double[][] mask) {
|
private static void validateMask(double[][] mask) {
|
||||||
if (mask == null || mask.length == 0 || mask.length % 2 == 0) {
|
if (mask == null || mask.length == 0 || mask.length % 2 == 0) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException("Le masque doit être une matrice carrée de dimension impaire.");
|
||||||
"Le masque doit être une matrice carrée de dimension impaire."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int size = mask.length;
|
int size = mask.length;
|
||||||
|
|
||||||
for (double[] row : mask) {
|
for (double[] row : mask) {
|
||||||
if (row == null || row.length != size) {
|
if (row == null || row.length != size) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException("Le masque doit être une matrice carrée.");
|
||||||
"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) {
|
private static void validateMaskSize(int maskSize) {
|
||||||
if (maskSize <= 0 || maskSize % 2 == 0) {
|
if (maskSize <= 0 || maskSize % 2 == 0) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException("La taille du masque doit être un entier positif impair.");
|
||||||
"La taille du masque doit être un entier positif impair."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Mat toMat(GrayScaleMatrix matrix) {
|
private static Mat toMat(GrayScaleMatrix matrix) {
|
||||||
double[][] image = matrix.getRawData();
|
double[][] data = matrix.getRawData();
|
||||||
int height = image.length;
|
int height = data.length;
|
||||||
int width = image[0].length;
|
int width = data[0].length;
|
||||||
|
|
||||||
Mat mat = new Mat(height, width, CvType.CV_64F);
|
Mat mat = new Mat(height, width, CvType.CV_64F);
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
mat.put(y, 0, data[y]);
|
||||||
mat.put(y, x, image[y][x]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,13 +85,13 @@ public class LocalLinearFiltering {
|
|||||||
int height = mat.rows();
|
int height = mat.rows();
|
||||||
int width = mat.cols();
|
int width = mat.cols();
|
||||||
double[][] result = new double[height][width];
|
double[][] result = new double[height][width];
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
|
double[] row = new double[width];
|
||||||
|
mat.get(y, 0, row);
|
||||||
for (int x = 0; x < width; x++) {
|
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);
|
return new GrayScaleMatrix(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,94 +8,82 @@ import org.opencv.core.Size;
|
|||||||
import org.opencv.imgproc.Imgproc;
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
|
||||||
public class BasicMorphology {
|
public class BasicMorphology {
|
||||||
|
|
||||||
public static GrayScaleMatrix erosion(Image image, int tailleMasque) {
|
public static GrayScaleMatrix erosion(Image image, int tailleMasque) {
|
||||||
Mat input = toMat(image);
|
Mat input = toMat(image);
|
||||||
Mat kernel = createKernel(tailleMasque);
|
Mat kernel = createKernel(tailleMasque);
|
||||||
Mat result = new Mat();
|
Mat result = new Mat();
|
||||||
|
|
||||||
Imgproc.erode(input, result, kernel);
|
Imgproc.erode(input, result, kernel);
|
||||||
|
GrayScaleMatrix output = toGrayScaleMatrix(result);
|
||||||
return toGrayScaleMatrix(result);
|
input.release();
|
||||||
|
kernel.release();
|
||||||
|
result.release();
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix dilation(Image image, int tailleMasque) {
|
public static GrayScaleMatrix dilation(Image image, int tailleMasque) {
|
||||||
Mat input = toMat(image);
|
Mat input = toMat(image);
|
||||||
Mat kernel = createKernel(tailleMasque);
|
Mat kernel = createKernel(tailleMasque);
|
||||||
Mat result = new Mat();
|
Mat result = new Mat();
|
||||||
|
|
||||||
Imgproc.dilate(input, result, kernel);
|
Imgproc.dilate(input, result, kernel);
|
||||||
|
GrayScaleMatrix output = toGrayScaleMatrix(result);
|
||||||
return toGrayScaleMatrix(result);
|
input.release();
|
||||||
|
kernel.release();
|
||||||
|
result.release();
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix opening(Image image, int tailleMasque) {
|
public static GrayScaleMatrix opening(Image image, int tailleMasque) {
|
||||||
Mat input = toMat(image);
|
Mat input = toMat(image);
|
||||||
Mat kernel = createKernel(tailleMasque);
|
Mat kernel = createKernel(tailleMasque);
|
||||||
Mat result = new Mat();
|
Mat result = new Mat();
|
||||||
|
Imgproc.morphologyEx(input, result, Imgproc.MORPH_OPEN, kernel);
|
||||||
Imgproc.morphologyEx(
|
GrayScaleMatrix output = toGrayScaleMatrix(result);
|
||||||
input,
|
input.release();
|
||||||
result,
|
kernel.release();
|
||||||
Imgproc.MORPH_OPEN,
|
result.release();
|
||||||
kernel
|
return output;
|
||||||
);
|
|
||||||
|
|
||||||
return toGrayScaleMatrix(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix closing(Image image, int tailleMasque) {
|
public static GrayScaleMatrix closing(Image image, int tailleMasque) {
|
||||||
Mat input = toMat(image);
|
Mat input = toMat(image);
|
||||||
Mat kernel = createKernel(tailleMasque);
|
Mat kernel = createKernel(tailleMasque);
|
||||||
Mat result = new Mat();
|
Mat result = new Mat();
|
||||||
|
Imgproc.morphologyEx(input, result, Imgproc.MORPH_CLOSE, kernel);
|
||||||
Imgproc.morphologyEx(
|
GrayScaleMatrix output = toGrayScaleMatrix(result);
|
||||||
input,
|
input.release();
|
||||||
result,
|
kernel.release();
|
||||||
Imgproc.MORPH_CLOSE,
|
result.release();
|
||||||
kernel
|
return output;
|
||||||
);
|
|
||||||
|
|
||||||
return toGrayScaleMatrix(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Mat toMat(Image image) {
|
private static Mat toMat(Image image) {
|
||||||
GrayScaleMatrix gray = image.toGrayScale();
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
|
||||||
int width = gray.getWidth();
|
int width = gray.getWidth();
|
||||||
int height = gray.getHeight();
|
int height = gray.getHeight();
|
||||||
|
|
||||||
Mat mat = new Mat(height, width, CvType.CV_64F);
|
Mat mat = new Mat(height, width, CvType.CV_64F);
|
||||||
|
|
||||||
double[][] data = gray.getRawData();
|
double[][] data = gray.getRawData();
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
mat.put(y, 0, data[y]);
|
mat.put(y, 0, data[y]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Mat createKernel(int tailleMasque) {
|
private static Mat createKernel(int tailleMasque) {
|
||||||
return Imgproc.getStructuringElement(
|
if (tailleMasque <= 0 || tailleMasque % 2 == 0) {
|
||||||
Imgproc.MORPH_RECT,
|
throw new IllegalArgumentException("La taille du masque doit être un entier positif impair.");
|
||||||
new Size(tailleMasque, tailleMasque)
|
}
|
||||||
);
|
return Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(tailleMasque, tailleMasque));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GrayScaleMatrix toGrayScaleMatrix(Mat mat) {
|
private static GrayScaleMatrix toGrayScaleMatrix(Mat mat) {
|
||||||
int width = mat.cols();
|
int width = mat.cols();
|
||||||
int height = mat.rows();
|
int height = mat.rows();
|
||||||
|
|
||||||
double[][] output = new double[height][width];
|
double[][] output = new double[height][width];
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
double[] row = new double[width];
|
||||||
output[y][x] = mat.get(y, x)[0];
|
mat.get(y, 0, row);
|
||||||
}
|
System.arraycopy(row, 0, output[y], 0, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GrayScaleMatrix(output);
|
return new GrayScaleMatrix(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,23 +11,33 @@ import org.opencv.imgproc.Imgproc;
|
|||||||
public class ComplexMorphology {
|
public class ComplexMorphology {
|
||||||
|
|
||||||
public static GrayScaleMatrix geodesicDilation(Image image, Image mask, int nbIter) {
|
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 maskMat = toMat(mask);
|
||||||
Mat current = toMat(image);
|
Mat current = toMat(image);
|
||||||
Mat kernel = createKernel(3);
|
Mat kernel = createKernel(3);
|
||||||
|
|
||||||
for (int i = 0; i < nbIter; i++) {
|
for (int i = 0; i < nbIter; i++) {
|
||||||
Mat dilated = new Mat();
|
Mat dilated = new Mat();
|
||||||
|
|
||||||
Imgproc.dilate(current, dilated, kernel);
|
Imgproc.dilate(current, dilated, kernel);
|
||||||
|
|
||||||
Mat result = new Mat();
|
Mat result = new Mat();
|
||||||
|
|
||||||
Core.min(dilated, maskMat, result);
|
Core.min(dilated, maskMat, result);
|
||||||
|
|
||||||
|
current.release();
|
||||||
|
dilated.release();
|
||||||
current = result;
|
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) {
|
public static GrayScaleMatrix geodesicReconstruction(Image image, Image mask) {
|
||||||
@@ -37,48 +47,51 @@ public class ComplexMorphology {
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
Mat dilated = new Mat();
|
Mat dilated = new Mat();
|
||||||
|
|
||||||
Imgproc.dilate(current, dilated, kernel);
|
Imgproc.dilate(current, dilated, kernel);
|
||||||
|
|
||||||
Mat next = new Mat();
|
Mat next = new Mat();
|
||||||
|
|
||||||
Core.min(dilated, maskMat, next);
|
Core.min(dilated, maskMat, next);
|
||||||
|
|
||||||
double difference = Core.norm(next, current, Core.NORM_INF);
|
double difference = Core.norm(next, current, Core.NORM_INF);
|
||||||
|
|
||||||
if (difference == 0) {
|
current.release();
|
||||||
return toGrayScaleMatrix(next);
|
dilated.release();
|
||||||
|
|
||||||
|
if (difference == 0.0) {
|
||||||
|
GrayScaleMatrix result = toGrayScaleMatrix(next);
|
||||||
|
|
||||||
|
next.release();
|
||||||
|
maskMat.release();
|
||||||
|
kernel.release();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
current = next;
|
current = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix medianFilter(Image image, int tailleMasque) {
|
public static GrayScaleMatrix medianFilter(Image image, int maskSize) {
|
||||||
if (tailleMasque < 1 || tailleMasque % 2 == 0) {
|
validateMedianSize(maskSize);
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Median filter size must be a positive odd number"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mat input = to8BitMat(image);
|
Mat input = to8BitMat(image);
|
||||||
Mat result = new Mat();
|
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) {
|
private static Mat toMat(Image image) {
|
||||||
GrayScaleMatrix gray = image.toGrayScale();
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
|
||||||
int width = gray.getWidth();
|
int width = gray.getWidth();
|
||||||
int height = gray.getHeight();
|
int height = gray.getHeight();
|
||||||
|
|
||||||
Mat mat = new Mat(height, width, CvType.CV_64F);
|
Mat mat = new Mat(height, width, CvType.CV_64F);
|
||||||
|
|
||||||
double[][] data = gray.getRawData();
|
double[][] data = gray.getRawData();
|
||||||
@@ -90,16 +103,11 @@ public class ComplexMorphology {
|
|||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an image to an 8-bit grayscale matrix.
|
|
||||||
* Required by OpenCV medianBlur().
|
|
||||||
*/
|
|
||||||
private static Mat to8BitMat(Image image) {
|
private static Mat to8BitMat(Image image) {
|
||||||
GrayScaleMatrix gray = image.toGrayScale();
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
|
||||||
int width = gray.getWidth();
|
int width = gray.getWidth();
|
||||||
int height = gray.getHeight();
|
int height = gray.getHeight();
|
||||||
|
|
||||||
Mat mat = new Mat(height, width, CvType.CV_8UC1);
|
Mat mat = new Mat(height, width, CvType.CV_8UC1);
|
||||||
|
|
||||||
double[][] data = gray.getRawData();
|
double[][] data = gray.getRawData();
|
||||||
@@ -108,9 +116,7 @@ public class ComplexMorphology {
|
|||||||
byte[] row = new byte[width];
|
byte[] row = new byte[width];
|
||||||
|
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
int value = (int) Math.round(data[y][x]);
|
int value = Math.clamp((int) Math.round(data[y][x]), 0, 255);
|
||||||
value = Math.clamp(value, 0, 255);
|
|
||||||
|
|
||||||
row[x] = (byte) value;
|
row[x] = (byte) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,14 +127,15 @@ public class ComplexMorphology {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Mat createKernel(int size) {
|
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) {
|
private static GrayScaleMatrix toGrayScaleMatrix(Mat mat) {
|
||||||
int width = mat.cols();
|
int width = mat.cols();
|
||||||
int height = mat.rows();
|
int height = mat.rows();
|
||||||
|
|
||||||
double[][] output = new double[height][width];
|
double[][] output = new double[height][width];
|
||||||
|
|
||||||
if (mat.type() == CvType.CV_8UC1) {
|
if (mat.type() == CvType.CV_8UC1) {
|
||||||
@@ -150,4 +157,12 @@ public class ComplexMorphology {
|
|||||||
|
|
||||||
return new GrayScaleMatrix(output);
|
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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -7,121 +7,60 @@ import org.opencv.core.Mat;
|
|||||||
import org.opencv.imgproc.Imgproc;
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
|
||||||
public class LinearOutline {
|
public class LinearOutline {
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param image
|
|
||||||
* @param direction applied horizontally if 1, applied vertically if 2
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static GrayScaleMatrix prewittGradient(Image image, int direction) {
|
public static GrayScaleMatrix prewittGradient(Image image, int direction) {
|
||||||
Mat kernel = new Mat(3, 3, CvType.CV_64F);
|
Mat kernel = new Mat(3, 3, CvType.CV_64F);
|
||||||
|
|
||||||
if (direction == 1) {
|
if (direction == 1) {
|
||||||
kernel.put(0, 0,
|
kernel.put(0, 0, -1, -1, -1, 0, 0, 0, 1, 1, 1);
|
||||||
-1, -1, -1,
|
|
||||||
0, 0, 0,
|
|
||||||
1, 1, 1
|
|
||||||
);
|
|
||||||
} else if (direction == 2) {
|
} else if (direction == 2) {
|
||||||
kernel.put(0, 0,
|
kernel.put(0, 0, -1, 0, 1, -1, 0, 1, -1, 0, 1);
|
||||||
-1, 0, 1,
|
|
||||||
-1, 0, 1,
|
|
||||||
-1, 0, 1
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
|
kernel.release();
|
||||||
throw new IllegalArgumentException("Direction must be 1 or 2");
|
throw new IllegalArgumentException("Direction must be 1 or 2");
|
||||||
}
|
}
|
||||||
|
|
||||||
return applyKernel(image, kernel);
|
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) {
|
public static GrayScaleMatrix sobelGradient(Image image, int direction) {
|
||||||
Mat kernel = new Mat(3, 3, CvType.CV_64F);
|
Mat kernel = new Mat(3, 3, CvType.CV_64F);
|
||||||
|
|
||||||
if (direction == 1) {
|
if (direction == 1) {
|
||||||
kernel.put(0, 0,
|
kernel.put(0, 0, -1, -2, -1, 0, 0, 0, 1, 2, 1);
|
||||||
-1, -2, -1,
|
|
||||||
0, 0, 0,
|
|
||||||
1, 2, 1
|
|
||||||
);
|
|
||||||
} else if (direction == 2) {
|
} else if (direction == 2) {
|
||||||
kernel.put(0, 0,
|
kernel.put(0, 0, -1, 0, 1, -2, 0, 2, -1, 0, 1);
|
||||||
-1, 0, 1,
|
|
||||||
-2, 0, 2,
|
|
||||||
-1, 0, 1
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
|
kernel.release();
|
||||||
throw new IllegalArgumentException("Direction must be 1 or 2");
|
throw new IllegalArgumentException("Direction must be 1 or 2");
|
||||||
}
|
}
|
||||||
|
|
||||||
return applyKernel(image, kernel);
|
return applyKernel(image, kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix laplacian4(Image image) {
|
public static GrayScaleMatrix laplacian4(Image image) {
|
||||||
Mat kernel = new Mat(3, 3, CvType.CV_64F);
|
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);
|
return applyKernel(image, kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix laplacian8(Image image) {
|
public static GrayScaleMatrix laplacian8(Image image) {
|
||||||
Mat kernel = new Mat(3, 3, CvType.CV_64F);
|
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);
|
return applyKernel(image, kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GrayScaleMatrix applyKernel(Image image, Mat kernel) {
|
private static GrayScaleMatrix applyKernel(Image image, Mat kernel) {
|
||||||
GrayScaleMatrix gray = image.toGrayScale();
|
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();
|
double[][] data = gray.getRawData();
|
||||||
|
|
||||||
for (int y = 0; y < gray.getHeight(); y++) {
|
for (int y = 0; y < gray.getHeight(); y++) {
|
||||||
input.put(y, 0, data[y]);
|
input.put(y, 0, data[y]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mat result = new Mat();
|
Mat result = new Mat();
|
||||||
|
Imgproc.filter2D(input, result, CvType.CV_64F, kernel);
|
||||||
Imgproc.filter2D(
|
double[][] output = new double[result.rows()][result.cols()];
|
||||||
input,
|
|
||||||
result,
|
|
||||||
CvType.CV_64F,
|
|
||||||
kernel
|
|
||||||
);
|
|
||||||
|
|
||||||
double[][] output = new double[
|
|
||||||
result.rows()
|
|
||||||
][result.cols()];
|
|
||||||
|
|
||||||
for (int y = 0; y < result.rows(); y++) {
|
for (int y = 0; y < result.rows(); y++) {
|
||||||
for (int x = 0; x < result.cols(); x++) {
|
result.get(y, 0, output[y]);
|
||||||
output[y][x] = result.get(y, x)[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
input.release();
|
||||||
|
result.release();
|
||||||
|
kernel.release();
|
||||||
return new GrayScaleMatrix(output);
|
return new GrayScaleMatrix(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,48 +5,40 @@ import domain.image.Image;
|
|||||||
import domain.image.processing.morphology.BasicMorphology;
|
import domain.image.processing.morphology.BasicMorphology;
|
||||||
|
|
||||||
public class NonLinearOutline {
|
public class NonLinearOutline {
|
||||||
|
private static final int MASK_SIZE = 3;
|
||||||
|
|
||||||
public static GrayScaleMatrix gradientErosion(Image image) {
|
public static GrayScaleMatrix gradientErosion(Image image) {
|
||||||
GrayScaleMatrix original = image.toGrayScale();
|
GrayScaleMatrix original = image.toGrayScale();
|
||||||
GrayScaleMatrix erosion = BasicMorphology.erosion(image, 3);
|
GrayScaleMatrix erosion = BasicMorphology.erosion(image, MASK_SIZE);
|
||||||
|
|
||||||
return subtract(original, erosion);
|
return subtract(original, erosion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix gradientDilation(Image image) {
|
public static GrayScaleMatrix gradientDilation(Image image) {
|
||||||
GrayScaleMatrix original = image.toGrayScale();
|
GrayScaleMatrix original = image.toGrayScale();
|
||||||
GrayScaleMatrix dilation = BasicMorphology.dilation(image, 3);
|
GrayScaleMatrix dilation = BasicMorphology.dilation(image, MASK_SIZE);
|
||||||
|
|
||||||
return subtract(dilation, original);
|
return subtract(dilation, original);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix beucherGradient(Image image) {
|
public static GrayScaleMatrix beucherGradient(Image image) {
|
||||||
GrayScaleMatrix erosion = BasicMorphology.erosion(image, 3);
|
GrayScaleMatrix erosion = BasicMorphology.erosion(image, MASK_SIZE);
|
||||||
GrayScaleMatrix dilation = BasicMorphology.dilation(image, 3);
|
GrayScaleMatrix dilation = BasicMorphology.dilation(image, MASK_SIZE);
|
||||||
|
|
||||||
return subtract(dilation, erosion);
|
return subtract(dilation, erosion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix nonLinearLaplacian(Image image) {
|
public static GrayScaleMatrix nonLinearLaplacian(Image image) {
|
||||||
GrayScaleMatrix original = image.toGrayScale();
|
GrayScaleMatrix original = image.toGrayScale();
|
||||||
GrayScaleMatrix erosion = BasicMorphology.erosion(image, 3);
|
GrayScaleMatrix erosion = BasicMorphology.erosion(image, MASK_SIZE);
|
||||||
GrayScaleMatrix dilation = BasicMorphology.dilation(image, 3);
|
GrayScaleMatrix dilation = BasicMorphology.dilation(image, MASK_SIZE);
|
||||||
|
|
||||||
int height = original.getHeight();
|
int height = original.getHeight();
|
||||||
int width = original.getWidth();
|
int width = original.getWidth();
|
||||||
|
|
||||||
double[][] result = new double[height][width];
|
|
||||||
|
|
||||||
double[][] originalData = original.getRawData();
|
double[][] originalData = original.getRawData();
|
||||||
double[][] erosionData = erosion.getRawData();
|
double[][] erosionData = erosion.getRawData();
|
||||||
double[][] dilationData = dilation.getRawData();
|
double[][] dilationData = dilation.getRawData();
|
||||||
|
double[][] result = new double[height][width];
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
result[y][x] =
|
result[y][x] = dilationData[y][x] + erosionData[y][x] - 2 * originalData[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) {
|
private static GrayScaleMatrix subtract(GrayScaleMatrix first, GrayScaleMatrix second) {
|
||||||
int height = first.getHeight();
|
int height = first.getHeight();
|
||||||
int width = first.getWidth();
|
int width = first.getWidth();
|
||||||
|
|
||||||
double[][] firstData = first.getRawData();
|
double[][] firstData = first.getRawData();
|
||||||
double[][] secondData = second.getRawData();
|
double[][] secondData = second.getRawData();
|
||||||
|
|
||||||
double[][] result = new double[height][width];
|
double[][] result = new double[height][width];
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
result[y][x] =
|
result[y][x] = firstData[y][x] - secondData[y][x];
|
||||||
firstData[y][x] - secondData[y][x];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,54 +4,29 @@ import domain.image.GrayScaleMatrix;
|
|||||||
import domain.image.Image;
|
import domain.image.Image;
|
||||||
|
|
||||||
public class Thresholding {
|
public class Thresholding {
|
||||||
|
public static GrayScaleMatrix simpleThreshold(Image image, int threshold) {
|
||||||
public static GrayScaleMatrix simpleThreshold(
|
validateThreshold(threshold);
|
||||||
Image image,
|
|
||||||
int threshold
|
|
||||||
) {
|
|
||||||
GrayScaleMatrix gray = image.toGrayScale();
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
return applySimpleThreshold(gray, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GrayScaleMatrix doubleThreshold(
|
public static GrayScaleMatrix doubleThreshold(Image image, int threshold1, int threshold2) {
|
||||||
Image image,
|
validateThreshold(threshold1);
|
||||||
int threshold1,
|
validateThreshold(threshold2);
|
||||||
int threshold2
|
|
||||||
) {
|
|
||||||
if (threshold1 > threshold2) {
|
if (threshold1 > threshold2) {
|
||||||
int temp = threshold1;
|
int temp = threshold1;
|
||||||
threshold1 = threshold2;
|
threshold1 = threshold2;
|
||||||
threshold2 = temp;
|
threshold2 = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
GrayScaleMatrix gray = image.toGrayScale();
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
|
||||||
int height = gray.getHeight();
|
int height = gray.getHeight();
|
||||||
int width = gray.getWidth();
|
int width = gray.getWidth();
|
||||||
|
|
||||||
double[][] data = gray.getRawData();
|
double[][] data = gray.getRawData();
|
||||||
double[][] result = new double[height][width];
|
double[][] result = new double[height][width];
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
|
|
||||||
double value = data[y][x];
|
double value = data[y][x];
|
||||||
|
|
||||||
if (value < threshold1) {
|
if (value < threshold1) {
|
||||||
result[y][x] = 0;
|
result[y][x] = 0;
|
||||||
} else if (value < threshold2) {
|
} else if (value < threshold2) {
|
||||||
@@ -67,23 +42,18 @@ public class Thresholding {
|
|||||||
|
|
||||||
public static GrayScaleMatrix automaticThreshold(Image image) {
|
public static GrayScaleMatrix automaticThreshold(Image image) {
|
||||||
GrayScaleMatrix gray = image.toGrayScale();
|
GrayScaleMatrix gray = image.toGrayScale();
|
||||||
|
|
||||||
double[][] data = gray.getRawData();
|
double[][] data = gray.getRawData();
|
||||||
|
|
||||||
double threshold = (gray.getMinValue() + gray.getMaxValue()) / 2.0;
|
double threshold = (gray.getMinValue() + gray.getMaxValue()) / 2.0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
double lowerSum = 0;
|
double lowerSum = 0;
|
||||||
double upperSum = 0;
|
double upperSum = 0;
|
||||||
|
|
||||||
int lowerCount = 0;
|
int lowerCount = 0;
|
||||||
int upperCount = 0;
|
int upperCount = 0;
|
||||||
|
|
||||||
for (int y = 0; y < gray.getHeight(); y++) {
|
for (int y = 0; y < gray.getHeight(); y++) {
|
||||||
for (int x = 0; x < gray.getWidth(); x++) {
|
for (int x = 0; x < gray.getWidth(); x++) {
|
||||||
|
|
||||||
double value = data[y][x];
|
double value = data[y][x];
|
||||||
|
|
||||||
if (value <= threshold) {
|
if (value <= threshold) {
|
||||||
lowerSum += value;
|
lowerSum += value;
|
||||||
lowerCount++;
|
lowerCount++;
|
||||||
@@ -100,7 +70,6 @@ public class Thresholding {
|
|||||||
|
|
||||||
double lowerMean = lowerSum / lowerCount;
|
double lowerMean = lowerSum / lowerCount;
|
||||||
double upperMean = upperSum / upperCount;
|
double upperMean = upperSum / upperCount;
|
||||||
|
|
||||||
double newThreshold = (lowerMean + upperMean) / 2.0;
|
double newThreshold = (lowerMean + upperMean) / 2.0;
|
||||||
|
|
||||||
if (Math.abs(newThreshold - threshold) < 0.5) {
|
if (Math.abs(newThreshold - threshold) < 0.5) {
|
||||||
@@ -111,6 +80,27 @@ public class Thresholding {
|
|||||||
threshold = newThreshold;
|
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.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,10 +10,15 @@ import java.util.function.Supplier;
|
|||||||
public class UseCaseService {
|
public class UseCaseService {
|
||||||
|
|
||||||
public Image reduceNoise(Image i0) {
|
public Image reduceNoise(Image i0) {
|
||||||
|
|
||||||
|
double cutoff = 0.7 * getMaxCutoff(i0.getWidth(), i0.getHeight());
|
||||||
|
|
||||||
GrayScaleMatrix m0 = i0.toGrayScale();
|
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();
|
Image i1 = m1.toImage();
|
||||||
return ComplexMorphology.medianFilter(i1, 9).toImage();
|
|
||||||
|
return measureTime("Median filter", () -> ComplexMorphology.medianFilter(i1, 5).toImage());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Image[] equalizeHistogram(Image image) {
|
public Image[] equalizeHistogram(Image image) {
|
||||||
@@ -88,10 +93,19 @@ public class UseCaseService {
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> long measureTime(Supplier<T> operation) {
|
public <T> T measureTime(String name, Supplier<T> operation) {
|
||||||
long start = System.nanoTime();
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user