提问人:Carlos Noé 提问时间:8/25/2023 最后编辑:Carlos Noé 更新时间:8/31/2023 访问量:70
像素化从图像中出现的人脸并调整像素大小
Pixelate the faces that come to me from an image and resize pixel size
问:
我正在尝试像素化从图像中浮现到我的脸。我正在使用 Azure API 对人脸进行像素化,它会返回人脸所在的位置。问题是,根据人脸的大小,必须应用一种或另一种像素化。 例如,对于 20x20 的脸,不值得应用大小为 10 的像素。但是,例如,值得在 100x100 的脸上应用 10 像素。
提前致谢!
/**
* Pixela las caras en una imagen.
* Lee una imagen desde un archivo, y para cada cara detectada en la imagen (faces) ,
* recorre cada bloque de pixels del tamaño especificado en la región de la cara. Cada bloque de
* pixels se llena con el color del pixel superior izquierdo del bloque.
* Finalmente, la imagen modificada se vuelve a escribir en el archivo original.
*
* @param pixelSize Tamaño de los pixels en la imagen pixelada.
* @param inputFile Archivo de la imagen a pixelar.
* @param faces Lista de caras detectadas en la imagen.
*
* @throws IOException Si ocurre un error durante la lectura o la escritura del archivo de la imagen.
*/
public static PixelatedOutput pixelateFaces(int pixelSize, File inputFile,
List<AzureComputerVisionService.FaceDetectionResponse> faces)
throws IOException {
BufferedImage bufferedImage = ImageIO.read(inputFile);
File f = File.createTempFile("pixelate", ".jpg");
// Iterar sobre cada cara detectada
for (AzureComputerVisionService.FaceDetectionResponse face : faces) {
AzureComputerVisionService.FaceDetectionResponse.FaceRectangle faceRectangle =
face.faceRectangle;
//por cada cara nuevo pixel size.
pixelSize = calculatePixelSize(faceRectangle, pixelSize);
int rectangleRight = faceRectangle.left + faceRectangle.width;
int rectangleBottom = faceRectangle.top + faceRectangle.height;
for (int y = faceRectangle.top; y < rectangleBottom; y += pixelSize) {
for (int x = faceRectangle.left; x < rectangleRight; x += pixelSize) {
int pixelColor = bufferedImage.getRGB(x, y);
int pixelBlockWidth = Math.min(x + pixelSize, rectangleRight);
int pixelBlockHeight = Math.min(y + pixelSize, rectangleBottom);
for (int yd = y; yd < pixelBlockHeight; yd++) {
for (int xd = x; xd < pixelBlockWidth; xd++) {
bufferedImage.setRGB(xd, yd, pixelColor);
}
}
}
}
}
ImageIO.write(bufferedImage, "jpg", f);
PixelatedOutput pixelatedOutput = new PixelatedOutput();
pixelatedOutput.setFile(f);
pixelatedOutput.setContentType("image/jpeg");
return pixelatedOutput;
}
/**
* Calcula el tamaño del píxel para una cara dada, basándose en la dimensión mínima de la cara (ancho o alto, lo que sea menor)
* y el número máximo de bloques de píxeles que representarán la cara, limitado a 36.
* <p>
* El método funciona tomando la dimensión mínima de la cara, la cual siempre será mayor o igual a 36 píxeles, y dividiéndola
* por el número máximo de bloques de píxeles (limitado a un rango de 2 a 36). Esto calcula el tamaño de cada píxel, asegurando
* que la representación de la cara tendrá exactamente {@code maxPixelBlocks} píxeles, y cada píxel tendrá un tamaño proporcional
* al tamaño de la cara.
* <p>
* Esto permite representar la cara con un nivel de detalle constante, independientemente de su tamaño.
* <p>
* Para más información sobre el tamaño mínimo detectable de la cara, consultear el service:
* <a href="https://westus.dev.cognitive.microsoft.com/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395236">documentación oficial de Azure</a>.
*
* @param faceRectangle Rectángulo que define las dimensiones de la cara. Las dimensiones deben ser mayores que cero y mínimo de 36 píxeles. (asi lo dice azure).
* @param maxPixelBlocks Número máximo de bloques de píxeles permitidos para representar la cara, debe estar en el rango de 2 a 36.
* @return El tamaño del píxel calculado, que es la dimensión mínima de la cara dividida por {@code maxPixelBlocks}, con un mínimo de 2.
* @throws ArithmeticException si {@code maxPixelBlocks} es menor o igual a 0 o mayor que 36.
*/
public static int calculatePixelSize(AzureComputerVisionService.FaceDetectionResponse.FaceRectangle faceRectangle,
int maxPixelBlocks) {
// Escogemos la mínima dimensión entre el ancho y el alto. Nos determina siempre el MIN.
if(maxPixelBlocks<=1 || maxPixelBlocks>36){
log.error("Número máximo de bloques de píxeles permitidos para representar la cara no puede ser 0 o menor o mayor que 36");
throw new ArithmeticException();
}
int minDimension = Math.min(faceRectangle.width, faceRectangle.height);
int pixelSize = minDimension / maxPixelBlocks; //no va a ser
// Asegurarse de que el tamaño del píxel sea al menos un valor mínimo. (en el caso que sea 1).
pixelSize = Math.max(pixelSize, 10);
return pixelSize;
}
答:
1赞
Suresh Chikkam
8/31/2023
#1
将比例因子计算为面部尺寸与参考尺寸的比率(例如,100x100)。然后,您可以将此比例因子乘以固定的最小像素大小(例如,10),以获得动态调整的最小像素大小。
double scalingFactor = (double) minDimension / referenceSize;
int dynamicMinPixelSize = (int) (scalingFactor * 10); // Adjust 10 based on your needs
int pixelSize = Math.max(pixelSize, dynamicMinPixelSize);
- 您可以使用该方法在一次操作中设置像素块,而不是遍历块中的每个像素。
BufferedImage
setRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
int[] pixelArray = new int[pixelBlockWidth - x];
Arrays.fill(pixelArray, pixelColor);
for (int yd = y; yd < pixelBlockHeight; yd++) {
bufferedImage.setRGB(x, yd, pixelBlockWidth - x, 1, pixelArray, 0, pixelBlockWidth - x);
}
- 如果值不在有效范围内,则抛出一个。最好扔一个。
ArithmeticException
maxPixelBlocks
IllegalArgumentException
if (maxPixelBlocks <= 1 || maxPixelBlocks > 36) {
throw new IllegalArgumentException("Number of pixel blocks must be in the range of 2 to 36");
}
我能够获得我发送图像的数据。
结果:
- 简单的块填充可能无法产生最高质量的输出。有一些算法可以平均每个块内的颜色,这可以带来更平滑的像素化效果。
评论
1赞
Carlos Noé
9/18/2023
非常感谢您的回复 Suresh Chikkam!很抱歉耽误了回答。这是个好主意,我会应用它。顺便说一句,抛出 IllegalArgumentException 是真的
评论