为什么我的图像写成 jpg 文件后颜色会发生变化?

d0nut

我目前正在制作一种将 ppm 文件转换为 jpg、png 和 bmp 文件的方法。我这样做的方式是读取 ppm 文件的内容,创建 BufferedImage,并将 ppm 文件中的每个像素分配给 BufferedImage 中的相应像素。我的 bmp 和 png 文件看起来正确。但是,jpg 文件看起来完全不同。

下面是我的代码:

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import javax.imageio.ImageIO;

public class readPPMOutputOthers {

  public static void main(String[] args) throws InterruptedException {
    // read a ppm file

    Scanner sc;
    // if the file is not found, it will throw an exception
    try {
      sc = new Scanner(new FileInputStream("res/test2.ppm"));
    } catch (FileNotFoundException e) {
      throw new IllegalArgumentException("File not found!");
    }

    // the file now is a StringBuilder
    // read line by line to get information
    StringBuilder builder = new StringBuilder();
    while (sc.hasNextLine()) {
      String s = sc.nextLine();
      // ignore comment #
      if (s.charAt(0) != '#') {
        builder.append(s).append(System.lineSeparator());
      }
    }

    // throw an exception if the raw file doesn't begin with P3
    sc = new Scanner(builder.toString());
    String token;
    token = sc.next();
    if (!token.equals("P3")) {
      throw new IllegalArgumentException("Invalid PPM file: plain RAW file should begin with P3.");
    }

    // set the fields
    // initial load image
    int width = sc.nextInt();
    int height = sc.nextInt();
    int maxValue = sc.nextInt();

    List<Integer> pixels = new ArrayList<>();
    for (int i = 0; i < height; i++) {
      for (int j = 0; j < width; j++) {
        int r = sc.nextInt();
        int g = sc.nextInt();
        int b = sc.nextInt();

        int rgb = r;
        rgb = (rgb << 8) + g;
        rgb = (rgb << 8) + b;
        pixels.add(rgb);
      }
    }

    // make a BufferedImage from pixels
    BufferedImage outputImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    int[] outputImagePixelData = ((DataBufferInt) outputImg.getRaster().getDataBuffer()).getData();

    for (int i = 0; i < pixels.size(); i++) {
      outputImagePixelData[i] = pixels.get(i);
    }

    try {
        ImageIO.write(outputImg, "png",
            new File("res/test.png"));
      ImageIO.write(outputImg, "jpg",
          new File("res/test2.jpg"));
        ImageIO.write(outputImg, "bmp",
            new File("res/test.bmp"));
    } catch (IOException e) {
      System.out.println("Exception occurred :" + e.getMessage());
    }
    System.out.println("Images were written successfully.");
  }
}

图像比较

奇怪的是它适用于非常大的图像,但不适用于这个小图像。由于测试,我需要使它适用于如此小的图像。我一直在谷歌上挖掘关于这个的帖子,但仍然没有找到解决这个问题的方法。任何帮助,将不胜感激!

红色的

奇怪颜色的原因是JPEG 编码使用的YUV420色度子采样。

在 YUV420 中,每 2x2 像素具有相同的色度信息(2x2 像素具有相同的颜色)。
2x2 像素具有相同的颜色,但每个像素具有不同的亮度(亮度)。


Wikipedia中演示了 YUV420 Chroma subsumpling
在此处输入图像描述

在我们的例子中:
在此处输入图像描述变为棕色是原始红色、青色洋红色和黄色的混合(棕色由 4 个像素“共享”)。在此处输入图像描述


  • 注意:
    色度 subsumpling 不被视为“压缩”,是指它不是作为 JPEG 压缩阶段的一部分执行的。
    我们无法通过设置压缩质量参数来控制色度二次采样。
    Chroma subsumpling 被称为“颜色格式转换”预处理阶段的一部分 - 从 RGB 转换为 YUV420 颜色格式。

常用的 JPEG 颜色格式是 YUV420,但 JPEG 标准确实支持 YUV444 Chroma subsumpling。
GIMP设法使用 YUV444 Chroma subsumpling 保存 JPEG 图像。

示例(2x2 图像):
太小:在此处输入图像描述放大:在此处输入图像描述

我找不到在 JAVA 中保存 YUV444 JPEG 的示例...

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么在使用 javascript 在画布上重新绘制后颜色会发生变化?

为什么滚动后我的单元格中的图标会发生变化?

为什么在运行“插入”函数后我的数字变量会发生变化?

Python:为什么使用 b = list(a) 复制列表后 id 会发生变化

为什么在Chrome开发工具中检查变量后,变量会发生变化?

为什么创建新列表后std :: list :: front结果会发生变化?

为什么加入表后初始 COUNT 值会发生变化?

为什么在 vue 2 中挂载后数据会发生变化?

为什么弹簧引导程序属性在不同的配置文件中会发生变化?

为什么遍历方阵时会发生变化?

为什么[0]会发生变化?

为什么“to”道具在点击时会发生变化?

为什么索引值会发生变化?

当我运行 ```npm run dev`` 时,CSS 文件会发生变化

当我将其写入文件时,为什么3D numpy数组中的值会发生变化?

为什么当我转换为 ndarray 时我的日期列会发生变化

为什么将排序列表转换为Python中的集合后元素顺序会发生变化?

调用构造函数后,为什么initializer_list中的vector <int>的值会发生变化?

更改变量后,为什么分配给变量的数组元素会发生变化?

为什么上传照片时我的 gui 布局会发生变化?

为什么我的变量被调用时会发生变化?

为什么在Java中调用setTimeout函数之前,我的值会发生变化?

为什么当我将其设为链接时,文本的位置会发生变化?

如果我使用传播运算符,为什么状态会发生变化?

为什么我移动时游戏中的事物会发生变化?Java处理环境

为什么在使用React Redux过滤时我的原始状态会发生变化

为什么我的CSS宽度%在某些页面上会发生变化?

为什么我的for循环(python)在4次迭代后会发生变化?

为什么在我的代码运行时unsortedArray会发生变化?