【问题标题】:How can I pixelate a jpg with java?如何使用 java 对 jpg 进行像素化?
【发布时间】:2013-03-24 13:21:35
【问题描述】:

我正在尝试使用 Java 6 对 JPEG 进行像素化,但运气不佳。它需要使用 Java——而不是像 Photoshop 这样的图像处理程序,而且它需要看起来像老派——就像这样:

谁能帮帮我?

【问题讨论】:

  • ImageIO 将帮助您加载和保存图像tutorial,而不仅仅是像素操作。

标签: java jpeg pixel pixelate


【解决方案1】:

使用java.awt.image (javadoc) 和javax.imageio (javadoc) API,您可以轻松循环图像像素并自行执行像素化。

示例代码如下。您至少需要这些导入:javax.imageio.ImageIOjava.awt.image.BufferedImagejava.awt.image.Rasterjava.awt.image.WritableRasterjava.io.File

例子:

// How big should the pixelations be?
final int PIX_SIZE = 10;

// Read the file as an Image
img = ImageIO.read(new File("image.jpg"));

// Get the raster data (array of pixels)
Raster src = img.getData();

// Create an identically-sized output raster
WritableRaster dest = src.createCompatibleWritableRaster();

// Loop through every PIX_SIZE pixels, in both x and y directions
for(int y = 0; y < src.getHeight(); y += PIX_SIZE) {
    for(int x = 0; x < src.getWidth(); x += PIX_SIZE) {

        // Copy the pixel
        double[] pixel = new double[3];
        pixel = src.getPixel(x, y, pixel);

        // "Paste" the pixel onto the surrounding PIX_SIZE by PIX_SIZE neighbors
        // Also make sure that our loop never goes outside the bounds of the image
        for(int yd = y; (yd < y + PIX_SIZE) && (yd < dest.getHeight()); yd++) {
            for(int xd = x; (xd < x + PIX_SIZE) && (xd < dest.getWidth()); xd++) {
                dest.setPixel(xd, yd, pixel);
            }
        }
    }
}

// Save the raster back to the Image
img.setData(dest);

// Write the new file
ImageIO.write(img, "jpg", new File("image-pixelated.jpg"));

编辑:我想我应该提一下——据我所知,double[] pixel 只是 RGB 颜色值。例如,当我转储一个像素时,它看起来像{204.0, 197.0, 189.0},一种浅棕褐色。

【讨论】:

    【解决方案2】:

    完成@bchociej的回答

    我在像素中使用PIX_SIZE 定义的区域的主色。这不是一个完美的解决方案,但它稍微好一点。

    这里是一个例子:

    原文:

    旧算法:

    新算法:

    代码示例

    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.util.*;
    import java.util.List;
    
    public final class ImageUtil {
    
        public static BufferedImage pixelate(BufferedImage imageToPixelate, int pixelSize) {
            BufferedImage pixelateImage = new BufferedImage(
                imageToPixelate.getWidth(),
                imageToPixelate.getHeight(),
                imageToPixelate.getType());
    
            for (int y = 0; y < imageToPixelate.getHeight(); y += pixelSize) {
                for (int x = 0; x < imageToPixelate.getWidth(); x += pixelSize) {
                    BufferedImage croppedImage = getCroppedImage(imageToPixelate, x, y, pixelSize, pixelSize);
                    Color dominantColor = getDominantColor(croppedImage);
                    for (int yd = y; (yd < y + pixelSize) && (yd < pixelateImage.getHeight()); yd++) {
                        for (int xd = x; (xd < x + pixelSize) && (xd < pixelateImage.getWidth()); xd++) {
                            pixelateImage.setRGB(xd, yd, dominantColor.getRGB());
                        }
                    }
                }
            }
    
            return pixelateImage;
        }
    
        public static BufferedImage getCroppedImage(BufferedImage image, int startx, int starty, int width, int height) {
            if (startx < 0) startx = 0;
            if (starty < 0) starty = 0;
            if (startx > image.getWidth()) startx = image.getWidth();
            if (starty > image.getHeight()) starty = image.getHeight();
            if (startx + width > image.getWidth()) width = image.getWidth() - startx;
            if (starty + height > image.getHeight()) height = image.getHeight() - starty;
            return image.getSubimage(startx, starty, width, height);
        }
    
        public static Color getDominantColor(BufferedImage image) {
            Map<Integer, Integer> colorCounter = new HashMap<>(100);
            for (int x = 0; x < image.getWidth(); x++) {
                for (int y = 0; y < image.getHeight(); y++) {
                    int currentRGB = image.getRGB(x, y);
                    int count = colorCounter.getOrDefault(currentRGB, 0);
                    colorCounter.put(currentRGB, count + 1);
                }
            }
            return getDominantColor(colorCounter);
        }
    
        private static Color getDominantColor(Map<Integer, Integer> colorCounter) {
            int dominantRGB = colorCounter.entrySet().stream()
                .max((entry1, entry2) -> entry1.getValue() > entry2.getValue() ? 1 : -1)
                .get()
                .getKey();
            return new Color(dominantRGB);
        }
    }
    

    如何使用

    img = ImageIO.read(new File("image.jpg"));
    BufferedImage imagePixelated = ImageUtil.pixelate(img, PIX_SIZE);
    ImageIO.write(imagePixelated, "jpg", new File("image-pixelated.jpg"));
    

    【讨论】:

      【解决方案3】:

      我手头没有代码,但是如果您可以将图像大小调整为原始大小的 1/4,然后将其重新采样回原始大小,它应该可以解决问题。大多数图像库都可以做到这一点。

      【讨论】:

        【解决方案4】:

        我在 Thibaut Mottet 的回答中修改了dominantColor 函数,因此它返回的是该像素中的平均RGB,而不是最常见的颜色
        原文:

        之后:

        它不是很优化,但你明白了。

        public static Color getDominantColor(BufferedImage image) {
            int sumR = 0, sumB = 0, sumG = 0, int sum2 = 0;
            int color = 0;
            for (int x = 0; x < image.getWidth(); x++) {
                for (int y = 0; y < image.getHeight(); y++) {
                    color = image.getRGB(x, y);
                    Color c = new Color(color);
                    sumR += c.getRed();
                    sumB += c.getBlue();
                    sumG += c.getGreen();
                    sum2++;
                }
            }
            return new Color(sumR/sum2, sumG/sum2, sumB/sum2);
        

        【讨论】:

          【解决方案5】:

          搜索“Close Pixelate”项目,可能这就是你需要的。

          【讨论】:

          • 它看起来很完美,除了它是在 javascript 中的;我需要java。
          【解决方案6】:

          改进@thibaut-mottet 答案,因为我在“getDominantColor”方法上遇到编译器错误(“entry1”和“entry2”未定义)。

          import java.awt.Color;
          import java.awt.image.BufferedImage;
          import java.util.Comparator;
          import java.util.HashMap;
          import java.util.Map;
          import java.util.Map.Entry;
          
          public class ImageUtil {
          
              public static BufferedImage pixelate(BufferedImage imageToPixelate, int pixelSize) {
                  BufferedImage pixelateImage = new BufferedImage(
                      imageToPixelate.getWidth(),
                      imageToPixelate.getHeight(),
                      imageToPixelate.getType());
          
                  for (int y = 0; y < imageToPixelate.getHeight(); y += pixelSize) {
                      for (int x = 0; x < imageToPixelate.getWidth(); x += pixelSize) {
                          BufferedImage croppedImage = getCroppedImage(imageToPixelate, x, y, pixelSize, pixelSize);
                          Color dominantColor = getDominantColor(croppedImage);
                          for (int yd = y; (yd < y + pixelSize) && (yd < pixelateImage.getHeight()); yd++) {
                              for (int xd = x; (xd < x + pixelSize) && (xd < pixelateImage.getWidth()); xd++) {
                                  pixelateImage.setRGB(xd, yd, dominantColor.getRGB());
                              }
                          }
                      }
                  }
          
                  return pixelateImage;
              }
          
              public static BufferedImage getCroppedImage(BufferedImage image, int startx, int starty, int width, int height) {
                  if (startx < 0) startx = 0;
                  if (starty < 0) starty = 0;
                  if (startx > image.getWidth()) startx = image.getWidth();
                  if (starty > image.getHeight()) starty = image.getHeight();
                  if (startx + width > image.getWidth()) width = image.getWidth() - startx;
                  if (starty + height > image.getHeight()) height = image.getHeight() - starty;
                  return image.getSubimage(startx, starty, width, height);
              }
          
              public static Color getDominantColor(BufferedImage image) {
                  Map<Integer, Integer> colorCounter = new HashMap<>(100);
                  for (int x = 0; x < image.getWidth(); x++) {
                      for (int y = 0; y < image.getHeight(); y++) {
                          int currentRGB = image.getRGB(x, y);
                          int count = colorCounter.getOrDefault(currentRGB, 0);
                          colorCounter.put(currentRGB, count + 1);
                      }
                  }
                  return getDominantColor(colorCounter);
              }
          
              @SuppressWarnings("unchecked")
              private static Color getDominantColor(Map<Integer, Integer> colorCounter) {
                  int dominantRGB = colorCounter.entrySet().stream()
                      .max(new EntryComparator())
                      .get()
                      .getKey();
                  return new Color(dominantRGB);
              }
          }
          
          @SuppressWarnings("rawtypes")
          class EntryComparator implements Comparator {
          
              @SuppressWarnings("unchecked")
              @Override
              public int compare(Object o1, Object o2) {
                  Entry<Integer, Integer> entry1 = (Map.Entry<Integer, Integer>) o1;
                  Entry<Integer, Integer> entry2 = (Map.Entry<Integer, Integer>) o2;
                  return (entry1.getValue() > entry2.getValue() ? 1 : -1);
              }
          }
          

          使用方式完全相同:

          img = ImageIO.read(new File("image.jpg"));
          BufferedImage imagePixelated = ImageUtil.pixelate(img, PIX_SIZE);
          ImageIO.write(imagePixelated, "jpg", new File("image-pixelated.jpg"));
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-05-12
            • 2014-07-29
            • 2016-07-15
            • 2022-12-17
            • 1970-01-01
            • 2014-04-08
            • 1970-01-01
            • 2014-10-29
            相关资源
            最近更新 更多