Я хотел бы вычислить нормированную кросс-корреляцию между двумя изображениями с помощью Java.
Моя программа работает нормально, но когда я попытался проверить мои результаты в MATLAB, я, к сожалению, не получил те же результаты, что и в моей реализации Java.
Это код, который я выполнил в MATLAB:
Img1 = rgb2gray(imread('image1.png'));
Img2 = rgb2gray(imread('image2.png'));
corr2(Img1, Img2);
Это часть моей реализации Java. Некоторые из классов были удалены для лучшего понимания:
Я не уверен, что не так с моей реализацией Java.
У меня также есть еще один вопрос. В MATLAB мне пришлось преобразовать изображение в оттенки серого, прежде чем использовать corr2
. Нужно ли делать то же самое в Java?
Причина, по которой это не то же самое, заключается в том, что вы не учитывали заголовки в PNG файле.
Если вы посмотрите на свой Java-код, вы читаете изображение как поток байтов в вашем методе readImage
. Для PNG присутствуют заголовки, такие как размер изображения и количество битов цвета на пиксель. Вы не только захватываете данные изображения (которые, кстати, сжаты с использованием версии LZW, поэтому вы даже не читаете данные необработанных изображений), но вы также захватываете дополнительную информацию, которая собирается в вашем коде корреляции.
Смущает то, что вы отлично читаете изображение, используя тип BufferedImage
в начале кода корреляции для получения строк и столбцов. Почему вы переключились на использование байтового потока в вашем методе readImage
?
Таким образом, вам необходимо изменить свой метод readImage
чтобы взять объект BufferedImage
, или перечитать данные, подобные тому, что вы делали в методе корреляции в вашем методе readImage
. Как только вы это сделаете, используйте методы BufferedImage
для доступа к пикселям RGB. FWIW, если вы читаете изображение как оттенки серого, тогда каждый канал должен давать вам такую же интенсивность, чтобы вы могли работать только на одном канале. Неважно, что.... но убедитесь, что вы выполняете корреляцию на изображениях в оттенках серого. Это неоднозначно, когда вы переходите к цвету, поскольку в настоящее время нет установленного стандарта о том, как это сделать.
Используя BufferedImage
, вы можете использовать метод getRGB
для получения getRGB
пикселя в столбце x
и строке y
. x
перемещается слева направо, а y
пересекает сверху вниз. Когда вы вызываете getRGB
он возвращает одно 32-битное целое число в формате ARGB. Каждый канал имеет 8 бит. Таким образом, первые 8 бит (MSB) являются альфа-значением, а остальные 8 бит - красными, третьи 8 бит - зелеными, а окончательные 8 - синими. В зависимости от того, какой канал вы хотите, вам нужно сбросить бит и замаскировать биты, которые вам не нужны, чтобы получить нужное значение.
В качестве примера:
int rgb = img.getRGB(x, y);
int alpha = rgb >> 24 & 0xFF;
int red = rgb >> 16 & 0xFF;
int green = rgb >> 8 & 0xFF;
int blue = rgb & 0xFF;
Для значения альфа вам нужно сдвинуть вправо на 24 бита, чтобы довести его до позиций LSB, затем с помощью 0xFF
получить маску, чтобы получить только 8 бит, которые представляют альфа-значение. Точно так же вы сделали бы то же самое для красного, зеленого и синего каналов. Поскольку корреляция довольно некорректна для цветных изображений, позвольте преобразовать изображение в оттенки серого в свой метод readImage
. Таким образом, нет необходимости конвертировать изображение перед запуском этого метода. Мы сделаем это в самом методе, чтобы избавить вас от хлопот.
Если вы посмотрите, как MATLAB выполняет rgb2gray
, он выполняет взвешенную сумму, взвешивая каналы по-разному. Веса определяются с помощью SMPTE Rec. 601 (для тех из вас, кто хочет понять, как я это знаю, вы можете взглянуть на источник rgb2gray
и прочитать первую строку матрицы преобразования. Эти коэффициенты по существу являются определением стандарта 601).
Предыдущие версии MATLAB просто добавили все каналы, разделенные на 3 и занявшие слово. Я не знаю, какую версию MATLAB вы используете, но чтобы быть в безопасности, я собираюсь использовать самое современное преобразование.
public static void readImage(BufferedImage img, int array[][], int nrows, int ncols) {
for (int i = 0; i < nrows; i++)
for (int j = 0; j < ncols; j++) {
int rgb = img.getRGB(j, i);
int red = rgb >> 16 & 0xFF;
int green = rgb >> 8 & 0xFF;
int blue = rgb & 0xFF;
array[i][j] = (int) (0.299*((double)red) + 0.587*((double)green) +
0.114*((double)blue) );
}
}
Это, надеюсь, даст вам то, что вы хотите!