code factorized, gaussienFilter done, borders added, imageController updated

This commit is contained in:
Kea Horvath committed 2023-03-31 20:44:56 +02:00
1 parent 522bbc73cf
commit 29ab434586
2 files changed
+151 -68

No files matched your search

@@ -16,6 +16,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import boofcv.io.image.ConvertBufferedImage;
import boofcv.struct.border.BorderType;
import boofcv.struct.image.GrayU8;
import boofcv.struct.image.Planar;
@@ -135,6 +136,23 @@ public class ImageController {
return nodes;
}
public BorderType getBorderType(String borderType) {
switch (borderType) {
case "EXTENDED":
return BorderType.EXTENDED;
case "REFLECT":
return BorderType.REFLECT;
case "REFLECT_101":
return BorderType.NORMALIZED;
case "WRAP":
return BorderType.WRAP;
case "ZERO":
return BorderType.ZERO;
default:
return null;
}
}
/**
* récupère une image et la modifie si un algorithme est renseigné
*
@@ -210,8 +228,9 @@ public class ImageController {
}
break;
case "meanFilter":
if (!parameters.containsKey("size") || parameters.size() != 2)
return JSONError("Algorithm 'meanFilter' requires one parameter 'size'(positive odd integer)",
if (!parameters.containsKey("size") || !parameters.containsKey("borderType") || parameters.size() != 3)
return JSONError(
"Algorithm 'meanFilter' requires two parameters: 'size'(positive odd integer) and 'borderType'('SKIP', 'EXTENDED', 'WRAP', 'REFLECT', 'ZERO' or 'NORMALIZED')",
HttpStatus.BAD_REQUEST);
try {
int i = Integer.parseInt(parameters.get("size"));
@@ -219,25 +238,41 @@ public class ImageController {
return JSONError("Parameter 'size' should be a positive odd integer",
HttpStatus.BAD_REQUEST);
Planar<GrayU8> clone = input.clone();
ImageProcessing.meanFilter(clone, input, i);
BorderType borderType = getBorderType(parameters.get("borderType"));
if (borderType == null) {
return JSONError(
"Parameter 'borderType' should be 'SKIP', 'EXTENDED', 'WRAP', 'REFLECT', 'ZERO' or 'NORMALIZED'",
HttpStatus.BAD_REQUEST);
}
ImageProcessing.meanFilter(clone, input, i, borderType);
} catch (NumberFormatException e) {
return JSONError("Parameter 'size' should be a positive odd integer",
HttpStatus.BAD_REQUEST);
}
break;
case "gaussienFilter":
if (/* !parameters.containsKey("size") || */ parameters.size() != 1)
return JSONError("Algorithm 'gaussienFilter' requires no parameters", HttpStatus.BAD_REQUEST);
if (!parameters.containsKey("size") || !parameters.containsKey("sigma")
|| !parameters.containsKey("borderType") || parameters.size() != 5)
return JSONError(
"Algorithm 'gaussienFilter' requires 3 parameters: 'size'(positive odd integer), 'sigma'(positive number) and 'borderType'('SKIP', 'EXTENDED', 'WRAP', 'REFLECT', 'ZERO' or 'NORMALIZED')",
HttpStatus.BAD_REQUEST);
try {
// int i = Integer.parseInt(parameters.get("size"));
// if (i % 2 == 0)
// return JSONError("Parameter 'size' should be a positive odd integer",
// HttpStatus.BAD_REQUEST);
Planar<GrayU8> clone = input.clone();
ImageProcessing.gaussienFilter(clone, input, 5);
} catch (NumberFormatException e) {
int i = Integer.parseInt(parameters.get("size"));
if (i % 2 == 0 || i < 0)
return JSONError("Parameter 'size' should be a positive odd integer",
HttpStatus.BAD_REQUEST);
double sigma = Double.parseDouble(parameters.get("sigma"));
Planar<GrayU8> clone = input.clone();
BorderType borderType = getBorderType(parameters.get("borderType"));
if (borderType == null) {
return JSONError(
"Parameter 'borderType' should be 'SKIP', 'EXTENDED', 'WRAP', 'REFLECT', 'ZERO' or 'NORMALIZED'",
HttpStatus.BAD_REQUEST);
}
ImageProcessing.gaussienFilter(clone, input, i, sigma, borderType);
} catch (NumberFormatException e) {
return JSONError("Parameters 'size' and 'sigma' should be a positive numbers",
HttpStatus.BAD_REQUEST);
}
break;
case "contours":
@@ -1,5 +1,6 @@
package pdl.backend;
import boofcv.struct.border.BorderType;
import boofcv.struct.image.GrayU8;
import boofcv.struct.image.Planar;
@@ -279,74 +280,77 @@ public class ImageProcessing {
/**
* Applique un filtre moyenneur de taille indiquée à l'image
* passée en paramètre (le bord de l'image n'est pas modifié)
* passée en paramètre et stocke le résultat dans l'image de sortie.
*
* @param input image d'entrée
* @param output image de sortie
* @param size taille du filtre à appliquer (doit être impaire)
* @param borderType type de bord à utiliser pour la convolution
*/
public static void meanFilter(Planar<GrayU8> input, Planar<GrayU8> output, int size) {
public static void meanFilter(Planar<GrayU8> input, Planar<GrayU8> output, int size, BorderType borderType) {
// Vérification que la taille est impaire
if (size % 2 == 0) {
throw new IllegalArgumentException("La taille doit être impaire");
if (size % 2 == 0 || size < 0) {
throw new IllegalArgumentException(
"La taille doit être impaire et positive");
}
// Boucle pour parcourir tous les pixels de l'image d'entrée
BoofConcurrency.loopFor(0, input.height, y -> {
for (int x = 0; x < input.width; x++) {
if (y < size / 2 || x < size / 2 || y >= input.height - size / 2
|| x >= input.width - size / 2) {
setRGBValue(output, x, y, getRGBValue(input, x, y));
continue;
}
int totalValue[] = new int[3];
// Boucle pour parcourir le carré size x size autour du pixel actuel
for (int j = y - size / 2; j < y + size / 2 + 1; j++) {
for (int i = x - size / 2; i < x + size / 2 + 1; i++) {
for (int k = 0; k < totalValue.length; k++) {
totalValue[k] += input.getBand(k).get(i, j);
int[][] kernel = new int[size][size];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
kernel[i][j] = 1;
}
}
}
// Calcule la moyenne des pixels du carré et l'applique au pixel actuel dans
// l'image de
// sortie
for (int k = 0; k < totalValue.length; k++) {
totalValue[k] /= size * size;
}
setRGBValue(output, x, y, totalValue);
}
});
convolution(input, output, kernel, borderType);
}
/**
* TODO
* Calcule le noyau gaussien de taille demandée
*
* @param size taille du noyau gaussien
* @return noyau gaussien
* Applique un filtre gaussien de taille et de valeur données sur une image et
* stocke le résultat dans l'image de sortie.
*
* @param input L'image d'entrée
* @param output L'image de sortie
* @param size La taille du filtre à appliquer (doit être impaire)
* @param sigma La valeur du sigma à utiliser pour le filtre gaussien.
* @param borderType Le type de bord à utiliser pour la convolution
*/
public static int[][] createGaussienKernel(int size) {
// Vérification que la taille est impaire
if (size % 2 == 0 || size < 0) {
throw new IllegalArgumentException("La taille doit être impaire et positive");
public static void gaussienFilter(Planar<GrayU8> input, Planar<GrayU8> output,
int size, double sigma, BorderType borderType) {
if (size % 2 == 0 || size < 0 || sigma <= 0) {
throw new IllegalArgumentException(
"La taille doit être impaire et positive et sigma doit être strictement positif");
}
double[][] kernel = new double[size][size];
double sigma = 4 / 3;
double sum = 0.0; // For accumulating the kernel values
for (int x = 0; x < size; ++x)
for (int y = 0; y < size; ++y) {
kernel[x][y] = 1 / (2 * Math.PI * sigma * sigma) * Math.exp(-(x * x + y * y) / (2 * sigma * sigma));
int half = size / 2;
double sum = 0;
for (int x = -half; x <= half; ++x) {
for (int y = -half; y <= half; ++y) {
double gaussianValue = 1 / (2 * Math.PI * sigma * sigma)
* Math.exp(-(x * x + y * y) / (2 * sigma * sigma));
kernel[x + half][y + half] = gaussianValue;
sum += gaussianValue;
}
}
// On récupère le pourcentage de chaque valeur par rapport à la somme
for (int x = -half; x <= half; ++x) {
for (int y = -half; y <= half; ++y) {
kernel[x + half][y + half] = kernel[x + half][y + half] / sum;
}
}
// Normalize the kernel
int[][] kernelk = new int[size][size];
for (int x = 0; x < size; ++x)
for (int y = 0; y < size; ++y)
kernelk[x][y] = (int) (kernel[x][y] / sum);
return kernelk;
int[][] kernelInt = new int[size][size];
double factor = 1 / kernel[0][0];
// Si le facteur est trop grand (la valeur du coin est très très petite par
// rapport au reste), on le fixe à 1 million
if (factor > 1000000) {
factor = 1000000;
}
// normalisation
for (int x = 0; x < size; ++x) {
for (int y = 0; y < size; ++y) {
kernelInt[x][y] = (int) (kernel[x][y] * factor);
}
}
convolution(input, output, kernelInt, borderType);
}
/**
@@ -357,12 +361,12 @@ public class ImageProcessing {
* @param input L'image d'entrée
* @param output L'image de sortie
* @param kernel Le noyau de convolution à utiliser.
* @param borderType Le type de bord à utiliser pour la convolution
*/
public static void gaussienFilter(Planar<GrayU8> input, Planar<GrayU8> output,
int size) {
int[][] kernel = { { 1, 2, 3, 2, 1 }, { 2, 6, 8, 6, 2 }, { 3, 8, 10, 8, 3 }, { 2, 6, 8, 6, 2 },
{ 1, 2, 3, 2, 1 } };
int half = size / 2;
public static void convolution(Planar<GrayU8> input, Planar<GrayU8> output,
int[][] kernel, BorderType borderType) {
int size = kernel.length;
int half = kernel.length / 2;
int coefs = 0;
// Calcul du nombre total de coefficients dans le noyau
for (int i = 0; i < kernel.length; i++) {
@@ -374,10 +378,54 @@ public class ImageProcessing {
// Parcours de l'image d'entrée et application de la convolution
BoofConcurrency.loopFor(0, input.height, y -> {
for (int x = 0; x < input.width; x++) {
// Vérification si le carré sera à l'intérieur de l'image
// On traite d'abord les bords
if (y < half || x < half || y >= input.height - half || x >= input.width -
half) {
if (borderType == BorderType.SKIP) {
setRGBValue(output, x, y, getRGBValue(input, x, y));
} else if (borderType == BorderType.ZERO) {
setRGBValue(output, x, y, new int[] { 0, 0, 0 });
} else {
int totalValue[] = new int[3];
int coefsUsed = 0;
for (int j = y - half; j < y + half + 1; j++) {
int tmpj = j;
if (j < 0 || j >= input.height) {
if (borderType == BorderType.EXTENDED) {
tmpj = j < 0 ? 0 : input.height - 1;
} else if (borderType == BorderType.NORMALIZED) {
continue;
} else if (borderType == BorderType.REFLECT) {
tmpj = j < 0 ? -j : (input.height - 1) - (j - (input.height - 1));
} else if (borderType == BorderType.WRAP) {
tmpj = j < 0 ? j + (input.height - 1) : (j - (input.height - 1));
}
}
for (int i = x - size / 2; i < x + size / 2 + 1; i++) {
int tmpi = i;
if (i < 0 || i >= input.width) {
if (borderType == BorderType.EXTENDED) {
tmpi = i < 0 ? 0 : input.width - 1;
} else if (borderType == BorderType.NORMALIZED) {
continue;
} else if (borderType == BorderType.REFLECT) {
tmpi = i < 0 ? -i : (input.width - 1) - (i - (input.width - 1));
} else if (borderType == BorderType.WRAP) {
tmpi = i < 0 ? i + (input.width - 1) : (i - (input.width - 1));
}
}
for (int k = 0; k < totalValue.length; k++) {
totalValue[k] += input.getBand(k).get(tmpi, tmpj)
* kernel[tmpi][tmpj];
}
coefsUsed += kernel[tmpi][tmpj];
}
}
for (int k = 0; k < totalValue.length; k++) {
totalValue[k] /= coefsUsed;
}
setRGBValue(input, x, y, totalValue);
}
continue;
}
int currentJ = 0;