У меня проблема с использованием билинейной интерполяции для 16-битных данных. У меня есть два изображения, origImage и displayImage. Я хочу использовать AffineTransformOp для фильтрации origImage через AffineTransform в displayImage, который является размером области отображения. origImage имеет тип BufferedImage.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. Все указанные переменные рассчитываются на основе пользовательского ввода (движения мыши) и должны быть правильными (это было проверено многими людьми, в том числе и мной). Надеюсь, это поможет с ошибкой.
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);
Я до сих пор понятия не имею, что здесь происходит. Буду очень признателен за любую помощь, которая может быть оказана. Я также приложил пример ошибки, возникающей в реальном изображении, с которой я сталкиваюсь для дополнительной справки.
Вот ошибка, возникающая на рентгеновском снимке руки
Вот увеличенная версия, сфокусированная на области между большим пальцем и первым пальцем.
Еще раз обратите внимание, что ошибка возникает не на очень белых областях, а на значениях в середине динамического диапазона, как на градиентном изображении.
Я обнаружил больше информации. Я настраивал некоторые из преобразований и обнаружил, что ошибка не возникает, если я просто фильтрую матрицу тождеств. Это также не происходит, если я перевожу на целое число. Это происходит, если я перевожу не целым числом. Это также происходит, если я изменяю масштаб на любое значение, кроме 1 (целое число или нет). Надеюсь, это поможет.
После дополнительных экспериментов ошибка определенно проявляется на границе пикселей между половиной максимальной интенсивности (65535/2 = 32767,5). Это также происходит ТОЛЬКО при этом значении. Я надеюсь, что это может помочь диагностике !!
По запросу AlBlue здесь приведен код, полностью независимый от моего приложения, который может генерировать ошибку. Обратите внимание, что в оригинальном посте я включил градиент изображения, сгенерированный с помощью приведенного ниже кода, однако я увеличил один из градиентов, чтобы лучше показать эффект. Вы должны увидеть эффект четыре раза на переведенном изображении 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);
}
Как еще одно обновление, я только что попробовал это на Fedora 10 и увидел, что ошибка все еще присутствует.