Merge branch 'besoin8' into 'main'
Besoin8 See merge request pdl-l3/teams/2023/v1/v1d!18
This commit is contained in:
commit
12f8a8962f
3 files changed
+172
-32
No files matched your search
@@ -1,15 +1,24 @@
|
|||||||
package pdl.backend;
|
package pdl.backend;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
|
import boofcv.io.image.ConvertBufferedImage;
|
||||||
|
import boofcv.struct.image.GrayU8;
|
||||||
|
import boofcv.struct.image.Planar;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.io.InputStreamResource;
|
import org.springframework.core.io.InputStreamResource;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@@ -24,6 +33,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||||
|
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
public class ImageController {
|
public class ImageController {
|
||||||
@@ -37,43 +49,34 @@ public class ImageController {
|
|||||||
this.imageDao = imageDao;
|
this.imageDao = imageDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/images/{id}", produces = MediaType.IMAGE_JPEG_VALUE)
|
|
||||||
public ResponseEntity<?> getImage(@PathVariable("id") long id) {
|
|
||||||
|
|
||||||
Optional<Image> image = imageDao.retrieve(id);
|
|
||||||
|
|
||||||
if (image.isPresent()) {
|
|
||||||
InputStream inputStream = new ByteArrayInputStream(image.get().getData());
|
|
||||||
return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(new InputStreamResource(inputStream));
|
|
||||||
}
|
|
||||||
return new ResponseEntity<>("Image id=" + id + " not found.", HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping(value = "/images/{id}")
|
@DeleteMapping(value = "/images/{id}")
|
||||||
public ResponseEntity<?> deleteImage(@PathVariable("id") long id) {
|
public ResponseEntity<?> deleteImage(@PathVariable("id") long id) {
|
||||||
|
var img = imageDao.retrieve(id);
|
||||||
Optional<Image> image = imageDao.retrieve(id);
|
if (img.isEmpty())
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
if (image.isPresent()) {
|
imageDao.delete(img.get());
|
||||||
imageDao.delete(image.get());
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
return new ResponseEntity<>("Image id=" + id + " deleted.", HttpStatus.OK);
|
|
||||||
}
|
|
||||||
return new ResponseEntity<>("Image id=" + id + " not found.", HttpStatus.NOT_FOUND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/images")
|
@PostMapping(value = "/images", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
public ResponseEntity<?> addImage(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {
|
public ResponseEntity<?> addImage(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {
|
||||||
|
|
||||||
String contentType = file.getContentType();
|
String contentType = file.getContentType();
|
||||||
if (contentType != null && !contentType.equals(MediaType.IMAGE_JPEG.toString())) {
|
if (contentType == null
|
||||||
return new ResponseEntity<>("Only JPEG/PNG file format supported", HttpStatus.UNSUPPORTED_MEDIA_TYPE);
|
|| (!contentType.equals(MediaType.IMAGE_JPEG_VALUE) && !contentType.equals(MediaType.IMAGE_PNG_VALUE)))
|
||||||
}
|
return new ResponseEntity<>(HttpStatus.UNSUPPORTED_MEDIA_TYPE);
|
||||||
try {
|
try {
|
||||||
imageDao.create(new Image(file.getOriginalFilename(), file.getBytes()));
|
Image newImg = new Image(file.getOriginalFilename(), file.getBytes());
|
||||||
|
imageDao.create(newImg);
|
||||||
|
URI newURI = ServletUriComponentsBuilder.fromCurrentRequest().path("/" + newImg.getId()).build().toUri();
|
||||||
|
return ResponseEntity.created(newURI).build();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return new ResponseEntity<>("Failure to read file", HttpStatus.NO_CONTENT);
|
return new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
|
||||||
}
|
}
|
||||||
return new ResponseEntity<>("Image uploaded", HttpStatus.CREATED);
|
}
|
||||||
|
|
||||||
|
@DeleteMapping(value = "/images")
|
||||||
|
public ResponseEntity<?> deleteImagesList() {
|
||||||
|
return new ResponseEntity<>(HttpStatus.METHOD_NOT_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/images", produces = "application/json")
|
@GetMapping(value = "/images", produces = "application/json")
|
||||||
@@ -92,4 +95,110 @@ public class ImageController {
|
|||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@GetMapping(value = "/images/{id}", produces = { MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE })
|
||||||
|
public ResponseEntity<?> getImage(@PathVariable("id") long id,
|
||||||
|
@RequestParam(required = false) Map<String, String> parameters) {
|
||||||
|
|
||||||
|
// Récupère l'image correspondante à l'ID fourni
|
||||||
|
Optional<Image> optImage = imageDao.retrieve(id);
|
||||||
|
if (!optImage.isPresent())
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
Image image = optImage.get();
|
||||||
|
// Si aucun paramètre n'est fourni, renvoie l'image brute
|
||||||
|
if (parameters.isEmpty()) {
|
||||||
|
InputStream inputStream = new ByteArrayInputStream(image.getData());
|
||||||
|
return ResponseEntity.ok().contentType(image.getMediaType())
|
||||||
|
.body(new InputStreamResource(inputStream));
|
||||||
|
}
|
||||||
|
// Vérifie la présence du paramètre "algorithm"
|
||||||
|
if (!parameters.containsKey("algorithm"))
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
|
||||||
|
String algo = parameters.get("algorithm");
|
||||||
|
BufferedImage bufImg;
|
||||||
|
try {
|
||||||
|
bufImg = ImageIO.read(new ByteArrayInputStream(image.getData()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("Error while reading image");
|
||||||
|
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
Planar<GrayU8> input = ConvertBufferedImage.convertFromPlanar(bufImg, null, true, GrayU8.class);
|
||||||
|
|
||||||
|
// applique l'algo a l'image en fonction des parametres et verifie la validite
|
||||||
|
// des parametres
|
||||||
|
switch (algo) {
|
||||||
|
case "changeLuminosity":
|
||||||
|
if (!parameters.containsKey("delta") || parameters.size() != 2)
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
try {
|
||||||
|
int i = Integer.parseInt(parameters.get("delta"));
|
||||||
|
ImageProcessing.changeLuminosity(input, i);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "histogram":
|
||||||
|
if (parameters.size() != 1)
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
ImageProcessing.histogram(input);
|
||||||
|
break;
|
||||||
|
case "colorFilter":
|
||||||
|
if (!parameters.containsKey("hue") || parameters.size() != 2)
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
try {
|
||||||
|
int i = Integer.parseInt(parameters.get("hue"));
|
||||||
|
ImageProcessing.colorFilter(i, input);
|
||||||
|
// hue entre 0 et 360?
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "meanFilter":
|
||||||
|
if (!parameters.containsKey("size") || parameters.size() != 2)
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
try {
|
||||||
|
int i = Integer.parseInt(parameters.get("size"));
|
||||||
|
if (i % 2 == 0)
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
Planar<GrayU8> clone = input.clone();
|
||||||
|
ImageProcessing.meanFilter(clone, input, i);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "gaussienFilter":
|
||||||
|
if (!parameters.containsKey("size") || parameters.size() != 2)
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
try {
|
||||||
|
int i = Integer.parseInt(parameters.get("size"));
|
||||||
|
if (i % 2 == 0)
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
Planar<GrayU8> clone = input.clone();
|
||||||
|
ImageProcessing.gaussienFilter(clone, input, i);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "contours":
|
||||||
|
if (parameters.size() != 1)
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
Planar<GrayU8> clone = input.clone();
|
||||||
|
ImageProcessing.gradientImageSobel(clone, input);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// transforme l'image en quelque chose que le navigateur puisse lire
|
||||||
|
bufImg = ConvertBufferedImage.convertTo_U8(input, null, true);
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
ImageIO.write(bufImg, image.getMediaType().getSubtype(), baos);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
byte[] imageData = baos.toByteArray();
|
||||||
|
InputStream inputStream = new ByteArrayInputStream(imageData);
|
||||||
|
return ResponseEntity.ok().contentType(image.getMediaType()).body(new InputStreamResource(inputStream));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -314,6 +314,36 @@ public class ImageProcessing {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
* Calcule le noyau gaussien de taille demandée
|
||||||
|
*
|
||||||
|
* @param size taille du noyau gaussien
|
||||||
|
* @return noyau gaussien
|
||||||
|
*/
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Effectue une convolution sur une image avec le noyau
|
* Effectue une convolution sur une image avec le noyau
|
||||||
@@ -324,8 +354,9 @@ public class ImageProcessing {
|
|||||||
* @param kernel Le noyau de convolution à utiliser.
|
* @param kernel Le noyau de convolution à utiliser.
|
||||||
*/
|
*/
|
||||||
public static void gaussienFilter(Planar<GrayU8> input, Planar<GrayU8> output,
|
public static void gaussienFilter(Planar<GrayU8> input, Planar<GrayU8> output,
|
||||||
int[][] kernel) {
|
int size) {
|
||||||
int size = kernel.length;
|
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;
|
int half = size / 2;
|
||||||
int totalCoefs = 0;
|
int totalCoefs = 0;
|
||||||
// Calcul du nombre total de coefficients dans le noyau
|
// Calcul du nombre total de coefficients dans le noyau
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public class ImageControllerTests {
|
|||||||
@Test
|
@Test
|
||||||
@Order(6)
|
@Order(6)
|
||||||
public void deleteImageShouldReturnSuccess() throws Exception {
|
public void deleteImageShouldReturnSuccess() throws Exception {
|
||||||
this.mockMvc.perform(delete("/images/0")).andDo(print()).andExpect(status().isOk());
|
this.mockMvc.perform(delete("/images/0")).andDo(print()).andExpect(status().isNoContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in new issue
Block a user