16位数据双线性插值的Java错误

16位数据双线性插值的Java错误,java,image-processing,bufferedimage,16-bit,affinetransform,Java,Image Processing,Bufferedimage,16 Bit,Affinetransform,我对16位数据使用双线性插值有问题。我有两个图像,origImage和displayImage。我想使用AffineTransformOp将原始图像通过AffineTransform过滤到displayImage中,displayImage是显示区域的大小。origImage的类型为BuffereImage.type_USHORT_GRAY,并具有sun.awt.image.ShortInterleavedRaster类型的光栅。这是我现在的代码 displayImage = new Buffe

我对16位数据使用双线性插值有问题。我有两个图像,origImage和displayImage。我想使用AffineTransformOp将原始图像通过AffineTransform过滤到displayImage中,displayImage是显示区域的大小。origImage的类型为BuffereImage.type_USHORT_GRAY,并具有sun.awt.image.ShortInterleavedRaster类型的光栅。这是我现在的代码

displayImage = new BufferedImage(getWidth(), getHeight(), origImage.getType());
try {
    op = new AffineTransformOp(atx, AffineTransformOp.TYPE_BILINEAR);
    op.filter(origImage, displayImage);
}
catch (Exception e) {
    e.printStackTrace();
}
为了显示错误,我创建了2个渐变图像。一个值在15位范围内(最大值32767),另一个值在16位范围内(最大值65535)。下面是两张图片

15位图像

16位图像

这两个图像是以相同的方式创建的,看起来应该相同,但请注意16位图像中间的线条。起初我认为这是一个溢出问题,但奇怪的是,它出现在渐变的中心,而不是在像素值较高的末端。此外,如果是溢出问题,我会怀疑15位图像也会受到影响

在此方面的任何帮助都将不胜感激

我只是想知道为什么没有人回答,我提供了足够的信息吗?需要更多信息吗

下面是我用来生成仿射变换的代码。所有引用的变量都是根据用户输入(鼠标移动)计算的,应该是正确的(包括我在内的很多人都测试过)。希望这有助于纠正错误

AffineTransform panTranslate = new AffineTransform();
panTranslate.translate(imagePanOffset.x, imagePanOffset.y);

AffineTransform rotateCenterTranslate = new AffineTransform();
rotateCenterTranslate.translate(imageRotateCTR.x, imageRotateCTR.y);
AffineTransform rotateTransform = new AffineTransform();
rotateTransform.rotate(Math.toRadians(rotateValue));
AffineTransform rotateAntiCenterTranslate = new AffineTransform();
rotateAntiCenterTranslate.translate(-imageRotateCTR.x, -imageRotateCTR.y);

AffineTransform translateTransform = new AffineTransform();
translateTransform.translate(imageMagOffset.x, imageMagOffset.y);

AffineTransform flipMatrixTransform = new AffineTransform();

switch (flipState) {
    case ENV.FLIP_NORMAL: // NORMAL
        break;

    case ENV.FLIP_TOP_BOTTOM: // FLIP
        flipMatrixTransform.scale(1.0, -1.0);
        flipMatrixTransform.translate(0.0, -h);
        break;

    case ENV.FLIP_LEFT_RIGHT: // MIRROR
        flipMatrixTransform.scale(-1.0, 1.0);
        flipMatrixTransform.translate(-w, 0.0);
        break;

    case ENV.FLIP_TOP_BOTTOM_LEFT_RIGHT: // FLIP+MIRROR
        flipMatrixTransform.scale(-1.0, -1.0);
        flipMatrixTransform.translate(-w, -h);
        break;
}

scaleTransform = new AffineTransform();
scaleTransform.scale(magFactor, magFactor);

AffineTransform atx = new AffineTransform();
atx.concatenate(panTranslate);
atx.concatenate(rotateCenterTranslate);
atx.concatenate(rotateTransform);
atx.concatenate(rotateAntiCenterTranslate);
atx.concatenate(translateTransform);
atx.concatenate(flipMatrixTransform);
atx.concatenate(scaleTransform);
我还是不知道这里发生了什么。我非常感谢能提供的任何帮助。我还附上了一个发生在真实图像中的bug示例,以供更多参考

这是发生在手部X光片上的细菌

这是一个放大版,重点放在拇指和第一个手指之间的区域。

再次注意,在极端的白色区域中,bug是如何发生的,但是在动态范围中间的值,就像在梯度图像中一样。

我发现了更多的信息。我调整了一些转换,发现如果我只是通过一个身份矩阵进行过滤,错误就不会发生。如果我按整数进行翻译,也不会发生这种情况。如果我按非整数量进行转换,则会发生这种情况。如果缩放除1(整数或非整数)以外的任何数量,也会发生此情况。希望这能有所帮助

经过更多的实验后,该缺陷肯定会在最大强度的一半(65535/2=32767.5)之间的边界像素处出现。它也仅在此值下发生。我希望这可能有助于诊断

应AlBlue的要求,这里的代码完全独立于我的应用程序,可以生成bug。请注意,在最初的文章中,我包含了一个用下面代码生成的图像渐变,但是我放大了其中一个渐变以更好地显示效果。您应该在0.5翻译的图像上看到四次效果,而不是在其他两个图像上。还请注意,当按除1以外的任何数量缩放时,都会出现此错误。只需将AffineTransform.getTranslateInstance()替换为AffineTransform.getScaleInstance(0.9,0.9)即可查看错误

private static class MyJPanel extends JPanel {
    BufferedImage displayImage = null;
    public MyJPanel(double translateValue) {
        super();
        BufferedImage bi = new BufferedImage(1024, 1024, BufferedImage.TYPE_USHORT_GRAY);

        int dataRange = (int)Math.pow(2, 16);
        double step = dataRange/(bi.getRaster().getDataBuffer().getSize()/4.0);
        double value = 0;
        for (int i=0; i<bi.getRaster().getDataBuffer().getSize(); i++) {
            bi.getRaster().getDataBuffer().setElem(i, (int)value);
            if (value >= dataRange)
                value = 0;
            else
                value += step;
        }
        displayImage = new BufferedImage(bi.getWidth(), bi.getHeight(), bi.getType());
        AffineTransform tx = AffineTransform.getTranslateInstance(translateValue, translateValue);
        AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
        op.filter(bi, displayImage);
    }

    public void paint(Graphics g) {
        super.paint(g);
        g.drawImage(displayImage, 0, 0, this);
    }
}

private static void showDisplayError() {
    JDialog dialog1 = new JDialog();
    dialog1.setTitle("No Translation");
    MyJPanel panel1 = new MyJPanel(0);
    dialog1.getContentPane().add(panel1);
    dialog1.setSize(1024, 1024);
    dialog1.setVisible(true);

    JDialog dialog2 = new JDialog();
    dialog2.setTitle("Translation of 0.5");
    MyJPanel panel2 = new MyJPanel(0.5);
    dialog2.getContentPane().add(panel2);
    dialog2.setSize(1024, 1024);
    dialog2.setVisible(true);

    JDialog dialog3 = new JDialog();
    dialog3.setTitle("Translation of 1.0");
    MyJPanel panel3 = new MyJPanel(1.0);
    dialog3.getContentPane().add(panel3);
    dialog3.setSize(1024, 1024);
    dialog3.setVisible(true);
}
私有静态类MyJPanel扩展了JPanel{
BuffereImage displayImage=null;
公共MyJPanel(双翻译值){
超级();
BuffereImage bi=新的BuffereImage(1024,1024,BuffereImage.TYPE_USHORT_GRAY);
int dataRange=(int)Math.pow(2,16);
双步骤=数据范围/(bi.getRaster().getDataBuffer().getSize()/4.0);
双值=0;
for(int i=0;i=dataRange)
数值=0;
其他的
值+=步长;
}
displayImage=新的BuffereImage(bi.getWidth(),bi.getHeight(),bi.getType());
AffineTransform tx=AffineTransform.getTranslateInstance(translateValue,translateValue);
AffineTransformOp=新的AffineTransformOp(tx,AffineTransformOp.TYPE_双线性);
op.filter(bi,显示图像);
}
公共空间涂料(图g){
超级油漆(g);
g、 drawImage(displayImage,0,0,this);
}
}
私有静态void showDisplayError(){
JDialog dialog1=新建JDialog();
对话1.设置标题(“无翻译”);
MyJPanel panel1=新的MyJPanel(0);
dialog1.getContentPane().add(panel1);
对话框1.设置大小(10241024);
对话框1.setVisible(true);
JDialog dialog2=新建JDialog();
对话框2.设置标题(“0.5的翻译”);
MyJPanel panel2=新MyJPanel(0.5);
dialog2.getContentPane().add(panel2);
对话框2.设置大小(10241024);
对话框2.setVisible(true);
JDialog dialog3=新建JDialog();
对话框3.setTitle(“1.0的翻译”);
MyJPanel panel3=新MyJPanel(1.0);
dialog3.getContentPane().add(panel3);
对话框3.设置大小(10241024);
对话框3.setVisible(true);
}

作为另一个更新,我刚刚在Fedora 10上尝试了这个功能,发现这个bug仍然存在。

你解决了这个问题吗?这可能是由于未正确使用仿射Transformop造成的。您是如何创建AffineTransform atx的?如果我有,我应该能够复制以帮助调试

你也可以看看这个。它包含了很多关于AffineTransformOp的有用信息

您使用的是什么版本的java(java-version)和操作系统?这可能是转换中的错误(已修复),也可能是渲染为PNG时出错


您是否尝试过使用最近邻过滤器而不是双线性过滤器?

您可以通过在
图形2D
而不是
仿射变换器中应用变换来解决此问题:

if (useG2D) {
    Graphics2D g = displayImage.createGraphics();
    g.transform(tx);
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                       RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    g.drawImage(bi, null, 0, 0);
} else {
    AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
    op.filter(bi, displayImage);
}
我不知道为什么这会产生不同的输出,但确实如此

注意:
useG2D
可以是常数,也可以根据
tx.getType()
的结果进行设置。当
TYPE\u QUADRANT\u旋转时,该错误不会发生