从 JPG 图像读取像素数据

Reading Pixel Data From JPG Image

我正在使用 Java 读取一个简单的 jpg 图像并打印出像素数据的二维数组。

如果我将整个图像设为黑色,我会得到我期望的结果: 这是 10x20 的黑色图像

结果:

 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 

但是,如果我在图像的第一行画一条白线,我会在一个我不期望的地方得到 1: 另一张图片:

-1  -1  -1  -1  -1  -1  -1  -1  -1  -1 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 1  1  1  1  1  1  1  1  1  1    //Why??
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0

这是我的代码:

byte[][]pixels;
BufferedImage image;

public ImageProcessor(File f) throws IOException{
    image = ImageIO.read(f);
    //Bitmap bMap = BitmapFactory.decodeFile(f.getAbsolutePath());  // Si es jpg
    pixels = new byte[image.getWidth()][];

    for (int x = 0; x < image.getWidth(); x++) {
        pixels[x] = new byte[image.getHeight()];

        for (int y = 0; y < image.getHeight(); y++) {
            pixels[x][y] = (byte) (image.getRGB(x, y));
        }
    }    

}

public void printPixelMatrix(){
    for (int i = 0; i < image.getHeight(); i++) {
        for (int j = 0; j < image.getWidth(); j++) {
            System.out.print(" "+pixels[j][i] + " ");
        }
        System.out.print("\n");
    }        

}

Java 没有无符号类型,因此您的 "white" 像素,即最大值 (0xff),被解释为负 1。

想必你的正 1 是一个压缩神器。

我怀疑您从 JPEG 量化中得到了伪影。 JPEG 压缩方形像素块,而不是单个像素。

看看是否有办法更改您的量化表。如果您将它们全部设为 1 值,这应该会消失。一些编码器为此使用 "quality" 设置。使用最高质量设置。

我不使用 Java 所以我继续学习一般的计算机图形学知识...

1) 首先,您可能想要为缓冲图像设置一个 type(即:4 字节,其中 R + G + B + 的每个组件有 1 个字节 + Α)。类似于 BufferedImage.TYPE_INT_ARGB.

2) 我不明白你为什么要将 image.getRGB(x, y) 的结果放入一个字节中。从 Java 文档看来 getRGB(x, y) returns 数组不是单个数字,即便如此,该数字也会将所有 A-R-G-B 合并为一个,但字节只能保存一个组件的值作为最大数量(最多 255,但颜色 int 可能像 4278254335 分布在 4 个字节上)。

建议的解决方案: 而不是字节(和步幅?),只需扫描像素并获得像素值的 int。然后打印这些值。 Black = 0 还有 White = 4278254335。我想我得到了下面的十六进制格式代码,所以应该显示为:Black = FF000000 然后是 White = FFFFFFFF.

我认为您的最终代码应该如下所示。请修正任何错误(我发表评论以便您了解我正在尝试做的事情)。那应该在预期的位置为您提供黑色的预期颜色,或带白线的黑色:

//# load your old one as usual
image = ImageIO.read(f);

//# Create a new bufferdImage with type (will draw old into this) //also consider TYPE_INT_RGB
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);

//# Then draw original into new type...
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
g.dispose(); //needed or not???

//# Doing the For-loop
int imgW = image.getWidth();
int imgH = image.getHeight();
int pixels[][] = new int[imgW][imgH]; //create a 2D array

//# Fill Array : for each [x] pos we read down /column 
//# so that we fill [y] with those pixel values
for (int x = 0; x < imgW; x++) 
{
    //On each X pos we scan all Y pixels in that column 
    for (int y = 0; y < imgH; y++) 
    {
        int col = image.getRGB(x, y);
        pixels[x][y] = col;

        //printPixelARGB( col ); //if you need this format instead of printPixelMatrix
    }
} 

//# To Print output
public void printPixelMatrix()
{
    for (int i = 0; i < image.getHeight(); i++) 
    {
        for (int j = 0; j < image.getWidth(); j++) 
        {
            //System.out.print(" " + pixels[j][i] + " ");
            int c = pixels[j][i]; //get integer that was stored in the array
            String HexVal = Integer.toHexString( c ) //giveshex value like AARRGGBB
            System.out.print(" " + HexVal + " ");
        }

        System.out.print("\n");
    }        

}

//# Another helper function to print pixel values
//# print out example blue : argb: 255, 0, 0, 255
public void printPixelARGB(int pixel) 
{
    int alpha = (pixel >> 24) & 0xff;
    int red = (pixel >> 16) & 0xff;
    int green = (pixel >> 8) & 0xff;
    int blue = (pixel) & 0xff;
    System.out.println("ARGB : " + alpha + ", " + red + ", " + green + ", " + blue);
}