У меня проблема с использованием билинейной интерполяции для 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 и увидел, что ошибка все еще присутствует.