#java #изображения
Я пытаюсь реализовать на java низкочастотную фильтрацию изображений. Реализую по книге Гонсалеса "Цифровая обработка изображений" следущие пункты (стр. 245): Исходное изображение умножается на "(-1)^(x+y)", чтобы его фурье-преобразование оказалось центрированным; Вычисляется прямое ДПФ F(u,v) изображения, полученного после шага 1; Ф-ция F(u,v) умножается на ф-цию фильтра H(u,v); Вычисляется обратное ДПФ от результата шага 3; Вычисляется вещественная часть результата шага 4; Результат шага 5 умножается на (-1)^(x+y) Чисто для примера, решила реализовать "Идеальный фильтр низких частот" (стр.257). Как я понимаю, результат получается неправильным с самого первого шага. Что я делаю не так? Прикладываю код каждого шага и результаты обработки на каждом шаге. Моя реализация шагов: 1) double funcXY; Complex[][] arrOnStepOne = new Complex[bufferedImage.getWidth()][bufferedImage.getHeight()]; for (int x = 0; x < bufferedImage.getWidth(); x++) { for (int y = 0; y < bufferedImage.getHeight(); y++) { funcXY = (Math.pow(-1.0, (x + y))) * bufferedImage.getRGB(x, y); Complex complexFuncXY = new Complex(funcXY, 0); arrOnStepOne[x][y] = complexFuncXY; } } 2) int width = arrOnStepOne.length; int height = arrOnStepOne[0].length; Complex sumByX = new Complex(0, 0); Complex sumByY = new Complex(0, 0); Complex[][] complexFurje = new Complex[width][height]; for (int u=0; u <= width-1; u++) { for (int v = 0; v <= height-1; v++) { sumByX = new Complex(0, 0); for (int x = 0; x <= width - 1; x++) { sumByY = new Complex(0, 0); for (int y = 0; y <= height - 1; y++) { Double teta = -2 * Math.PI * ((u * x / (double) width) + (v * y / (double) height)); Complex complexE = new Complex(Math.cos(teta), Math.sin(teta)); sumByY = sumByY.Add(arrOnStepOne[x][y].Mult(complexE)); } sumByX = sumByX.Add(sumByY); } complexFurje[u][v] = sumByX.Div(new Complex(width*height, 0)); } } 3) int d0; int nPow = 2; double d; double filtrD; double filtrH; Complex[][] complexFiltr = new Complex[width][height]; for (int u=0;u <= width-1; u++) { for (int v = 0; v <= height-1; v++) { d = Math.pow((u - width / 2.), 2) + Math.pow((v - height / 2.), 2); filtrD = Math.pow(d, 1. / 2); //D(u,v) d0 = 80; filtrH = 1 / (1 + Math.pow(filtrD / d0, 2. * nPow)); complexFiltr[u][v] = new Complex(filtrH, 0).Mult(complexFurje[u][v]); } } 4) for (int x = 0; x <= width-1 ; x++) { System.out.println("X = " + x +" / " + (width-1) + "."); for (int y = 0; y <= height-1 ; y++) { sumByU = new Complex(0, 0); for (int u = 0; u <= width-1; u++) { sumByV = new Complex(0, 0); for (int v = 0; v <= height - 1; v++) { Double teta = 2 * Math.PI * (x * u / (double) width + y * v / (double) height); Complex complexE = new Complex(Math.cos(teta), Math.sin(teta)); sumByV = sumByV.Add(complexE.Mult(complexFiltr[u][v])); } sumByU = sumByU.Add(sumByV); } funcStep4XY[x][y]=sumByU; } } 5,6) for (int x = 0; x <= width-1; x++) { for (int y = 0; y <= height-1; y++) { funcStep5XY[x][y] = funcStep4XY[x][y].getdReal(); funcStep5XY[x][y] *= Math.pow(-1.0,x+y); } } Ссылка на саму книгу здесь
Ответы
Ответ 1
Судя по артефактам на step1.jpg, вычисления производятся в целых числах. При этом происходит переполнение вместо сатурации, из-за чего вместо "засветки" белым цветом можно увидеть чёрные пиксели. В результате ДПФ step2.jpg вместо белой "звезды" на чёрном фоне выглядит как случайный шум, образованный всё теми же искажениями переполнения. Ну, и в итоге после ОДПФ получается сильно зашумленное изображение step56.jpg. Просто не хватает разрядности при вычислениях. Например, нужно 35 бит, а используется 32 бита.
Комментариев нет:
Отправить комментарий