在 BufferedImage 中乘以像素值会导致奇怪的行为
Multiplying Pixel Values in BufferedImage results in strange Behaviour
我目前正在开发一个程序来帮助摄影师创建延时摄影。
它计算一系列图像的亮度下降或上升。因此,例如曝光和 iso 的变化不会影响亮度的整体下降。
为此,我使用一个简单的基于 Swing 的界面来显示第一张和最后一张图像。它们下方是用于调整图像亮度的滑块。
这是通过直接操作底层 DataBuffer 的 BufferedImages 来应用的。
大多数情况下这是有效的,但我遇到了一些似乎有问题的图像。
你知道为什么会这样吗?
public BufferedImage getImage(float mult){
BufferedImage retim;
retim = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
Graphics g = retim.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
DataBufferByte db = (DataBufferByte) retim.getRaster().getDataBuffer();
byte[] bts = db.getData();
for(int i=0;i<bts.length;i++){
float n = bts[i]*mult;
if(n > 255){
bts[i]= (byte) 255;
}else{
bts[i] = (byte) n;
}
}
return retim;
}
这是一种采用浮点数并将图像中的每个像素与其相乘的方法。 (还有一些防止字节值溢出的代码)。
This is the unwanted behaviour (on the left) and the expected on the right.
这是因为图像中某些字节的值被限制了。
例如(假设RGB单色space):
像素从(125,255,0)开始,如果乘以因子2.0,结果是(255,255,0)。这与原来的色调不同。
这也是奇怪的结果只出现在已经具有高亮度的像素上的原因。
这个link可能有助于改进亮度调节算法。
您也可以参考this related question。
你的问题是这一行,它的发生是由于 Java byte
s 被签名(在 [-128...127] 范围内):
float n = bts[i] * mult;
乘法后,您的n
变量可能为负,从而导致溢出。
要修复它,请使用位掩码将值作为无符号整数(在 [0...255] 范围内),然后再与常量相乘:
float n = (bts[i] & 0xff) * mult;
更好的解决方法可能是使用 RescaleOp
,它是为 BufferedImage
进行亮度调整而构建的。
类似于:
public BufferedImage getImage(float mult) {
return new RescaleOp(mult, 0, null).filter(img, null);
}
我目前正在开发一个程序来帮助摄影师创建延时摄影。 它计算一系列图像的亮度下降或上升。因此,例如曝光和 iso 的变化不会影响亮度的整体下降。
为此,我使用一个简单的基于 Swing 的界面来显示第一张和最后一张图像。它们下方是用于调整图像亮度的滑块。
这是通过直接操作底层 DataBuffer 的 BufferedImages 来应用的。
大多数情况下这是有效的,但我遇到了一些似乎有问题的图像。
你知道为什么会这样吗?
public BufferedImage getImage(float mult){
BufferedImage retim;
retim = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
Graphics g = retim.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
DataBufferByte db = (DataBufferByte) retim.getRaster().getDataBuffer();
byte[] bts = db.getData();
for(int i=0;i<bts.length;i++){
float n = bts[i]*mult;
if(n > 255){
bts[i]= (byte) 255;
}else{
bts[i] = (byte) n;
}
}
return retim;
}
这是一种采用浮点数并将图像中的每个像素与其相乘的方法。 (还有一些防止字节值溢出的代码)。
This is the unwanted behaviour (on the left) and the expected on the right.
这是因为图像中某些字节的值被限制了。
例如(假设RGB单色space):
像素从(125,255,0)开始,如果乘以因子2.0,结果是(255,255,0)。这与原来的色调不同。
这也是奇怪的结果只出现在已经具有高亮度的像素上的原因。
这个link可能有助于改进亮度调节算法。
您也可以参考this related question。
你的问题是这一行,它的发生是由于 Java byte
s 被签名(在 [-128...127] 范围内):
float n = bts[i] * mult;
乘法后,您的n
变量可能为负,从而导致溢出。
要修复它,请使用位掩码将值作为无符号整数(在 [0...255] 范围内),然后再与常量相乘:
float n = (bts[i] & 0xff) * mult;
更好的解决方法可能是使用 RescaleOp
,它是为 BufferedImage
进行亮度调整而构建的。
类似于:
public BufferedImage getImage(float mult) {
return new RescaleOp(mult, 0, null).filter(img, null);
}