从 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);
}
我正在使用 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);
}