У меня проблема с использованием билинейной интерполяции для 16-битных данных. У меня есть два изображения: origImage и displayImage. Я хочу использовать AffineTransformOp для фильтрации origImage через AffineTransform в displayImage, который является размером области отображения. origImage имеет тип BufferedImage.TYPE_USHORT_GRAY и имеет растр типа sun.awt.image.ShortInterleavedRaster. Вот код, который у меня есть сейчасОшибка Java при билинейной интерполяции 16-битных данных
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 и увидел, что ошибка все еще присутствует.
Это похоже на проблему с переполнением, поскольку именно три строки пикселей должны иметь цвет RGB 128-128-128, которые были изменены. (Они заменяются одной строкой 57-57-57, одной строкой 232-232-232 и одной строкой 151-151-151.) Но я понятия не имею, почему. –
Спасибо за ответ. Эти изображения должны быть в оттенках серого, поэтому должен быть только один канал, почему вы предлагаете конкретные значения, которые вы опубликовали? – Jon
Я открыл ваши png-изображения в gimp и посмотрел на значения цвета. Оба имеют гладкий вертикальный градиент от 0 до 255 (от 0x00 до 0xff), за исключением белых и черных полос сверху и снизу и трех проблемных рядов пикселей в середине второго изображения. Но опять же, я понятия не имею, откуда они взялись. –