对图像中出现的面孔进行像素化并调整像素大小

问题描述 投票:0回答:1

我正在尝试对图像中出现的面孔进行像素化。我正在使用 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;
}
java image file azure-cognitive-services photo
1个回答
0
投票

将缩放因子计算为面部尺寸与参考尺寸(例如,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");
}

我能够获取我发送图像的数据。

结果: enter image description here

  • 简单的块填充可能无法产生最佳质量的输出。有一些算法可以平均每个块内的颜色,这可以带来更平滑的像素化效果。
© www.soinside.com 2019 - 2024. All rights reserved.