Билинейная интерполяция байтового ролловера Java

Проблема вкратце

Так что я работал над программным рендером 3d и мне нужен метод билинейной интерполяции. Я работаю с 3-байтовым растром BGR для скорости, и я не могу понять, как мой код функционально отличается от чего-то работающего, что я собрал вместе, непосредственно обращаясь к самому изображению. Я сначала выложу код перед результатами.

float lerp(float x1, float x2, float a) {
    return x1 * (1 - a) + x2 * a;
}

Основной линейный интерполяционный алгоритм

void berp(float sourceX, float sourceY, int destPos, byte[] source, byte[] dest, int sourceWidth) {
    float ax = sourceX - 0.5f;
    float bx = sourceX + 0.5f;
    float xa = ax - (int) (ax);
    float ay = sourceY - 0.5f;
    float by = sourceY + 0.5f;
    float ya = ay - (int) (ay);
    int pos1 = (((int) ay) * sourceWidth + ((int) ax)) * 3;
    int pos2 = (((int) ay) * sourceWidth + ((int) bx)) * 3;
    int pos3 = (((int) by) * sourceWidth + ((int) ax)) * 3;
    int pos4 = (((int) by) * sourceWidth + ((int) bx)) * 3;

Просто установите его так, чтобы позиции от pos1 до pos4 располагались в исходном массиве из 4 ближайших пикселей к заданным картам (sourceX & sourceY). xa и ya - это расстояние от карт до центра пикселя сверху и пикселя слева, соответственно, поэтому, в основном, сколько нужно выбрать из каждого пикселя.

    dest[destPos] = (byte) lerp(lerp(source[pos1], source[pos2], xa), lerp(source[pos3], source[pos4], xa), ya);
    dest[destPos + 1] = (byte) lerp(lerp(source[pos1 + 1], source[pos2 + 1], xa), lerp(source[pos3 + 1], source[pos4 + 1], xa), ya);
    dest[destPos + 2] = (byte) lerp(lerp(source[pos1 + 2], source[pos2 + 2], xa), lerp(source[pos3 + 2], source[pos4 + 2], xa), ya);
}

Здесь я интерполирую между rgb1 и rgb2, затем rgb3 и rgb4, используя xa. Затем я беру их результаты и интерполирую их, используя ya. Повторите для зеленого и красного, и это должно получиться золотой.

КРОМЕ:

Просто посмотрите на это изображение, нет способа описать его словами.

Я уверен, что вы видите мое затруднительное положение.

Любая помощь на этом этапе была бы желательна, я пытался часами безрезультатно, похоже, что это перенос с использованием броска с плавающей запятой, но я не очень понимаю, как можно получить, что lerp даст только когда-либо значение между x1 и x2 и только байты входят так...

*

*

*

*

*

Мне пришло в голову, что может быть полезно добавить код, который выдает правильное изображение. Некоторые имена и прочее могут отличаться, но суть всего этого есть:)

private int getColorBilinear (float x, float y, BufferedImage s) {
    float nx = x - 0.5f;
    float xa = nx - (int) (nx);
    float ny = y - 0.5f;
    float ya = ny - (int) (ny);
    int rgb1 = s.getRGB((int) (x - 0.5), (int) (y - 0.5));
    int rgb2 = s.getRGB((int) (x + 0.5), (int) (y - 0.5));
    int rgb3 = s.getRGB((int) (x - 0.5), (int) (y + 0.5));
    int rgb4 = s.getRGB((int) (x + 0.5), (int) (y + 0.5));

    return (int) (interpolate(
            interpolate(((rgb1 >> 16) & 0x000000FF), ((rgb2 >> 16) & 0x000000FF), xa),
            interpolate(((rgb3 >> 16) & 0x000000FF), ((rgb4 >> 16) & 0x000000FF), xa),
            ya)) << 16
            | (int) (interpolate(
            interpolate(((rgb1 >> 8) & 0x000000FF), ((rgb2 >> 8) & 0x000000FF), xa),
            interpolate(((rgb3 >> 8) & 0x000000FF), ((rgb4 >> 8) & 0x000000FF), xa),
            ya)) << 8
            | (int) (interpolate(interpolate((rgb1 & 0x000000FF), (rgb2 & 0x000000FF), xa),
            interpolate((rgb3 & 0x000000FF), (rgb4 & 0x000000FF), xa), ya));
}

1 ответ

Решение

Фактический процесс таков:

  • Значение пикселя выбирается как байт без знака
  • Байты (предполагается, что они подписаны) интерполируются
  • Интерполированное значение используется в целевом изображении в качестве байта без знака

Теперь шокирующе это на самом деле работает для большинства случаев. Проблема возникает, когда одно из значений источника выше 127, а другое - ниже. Например, метод интерполяции будет видеть (129,125) как (-127,125) и пытается интерполировать как таковой. Одним из способов борьбы с этой проблемой было бы сначала преобразовать в int, а затем интерполировать; реализация которого приведена ниже.

float lerp(byte x1, byte x2, float a) {

return unsignedByteToInt(x1) * (1 - a) + unsignedByteToInt(x2) * a;

}

int unsignedByteToInt(byte x) {return (((int) x) + 255) % 255;}
Другие вопросы по тегам