Результат фильтра нижних частот Фурье-идеала немного странный

Я пытаюсь реализовать идеальный фильтр нижних частот Фурье. Результат, который я получил, вроде правильный (наверное?), но вокруг изображения есть какие-то странные необработанные пиксели.

50 - радиус отсечки.

Вот изображение исходного изображения, оттенки серого, преобразование Фурье + фильтрация и обратное преобразование обратно в исходное изображение.

результат

Вот мой код:

function idealLowHighPass(img,par,d0){
  let height=img.rows;
  let width=img.cols;
  let prettypls=img.clone();
  let temp=createArray(height,width);
  let tmp = fastFourier(img);
  var tempD;

  let fraction = 0.3;
  let filter = 1;
  var x = width/2;
  var y = height/2;
  var state = -1;
  for(i=0;i<height;i++){
    for(j=0;j<width;j++){

      if(i > y && j > x){
        state = 3;
      }
      else if( i > y){
        state = 1;
      }
      else if (j > x){
        state = 2;
      }
      else{
        state = 0;
      }

      switch(state){
        case 0:
            tempD = (i * i + j * j);
            tempD = Math.sqrt(tempD);
            break;
        case 1:
            tempD = ((height - i) * (height - i) + j * j);
            tempD = Math.sqrt(tempD);
            break;
        case 2:
            tempD = (i * i + (width - j) * (width - j));
            tempD = Math.sqrt(tempD);
            break;
        case 3:
            tempD = ((height - i) * (height - i) + (width - j) * (width - j));
            tempD = Math.sqrt(tempD);
            break;
        default:
            break;
      }

      if(par == 'ideallowpass'){

        if(tempD <= d0){
            tempD = 1;
        }
        else{
            tempD = 0;
        }
      }
      tmp[i][j].re*=tempD;
      tmp[i][j].im*=tempD; 
    }
  }

  //HANDLE FFT
  //take the magnitudes
  for(i=0;i<height;i++){
    for(j=0;j<width;j++){
      temp[i][j]=Math.round(tmp[i][j].re);
    }
  }

  temp=logTransform(temp,height,width);
  for(i=0;i<height;i++){
    for(j=0;j<width;j++){
      let pixel = prettypls.ucharPtr(i,j);
      pixel[0]=Math.round(temp[i][j]);
    }
  }

  // rearrange the quadrants of Fourier image
  // so that the origin is at the image center
  let cx = prettypls.cols / 2;
  let cy = prettypls.rows / 2;
  let tmp2 = new cv.Mat();

  let rect0 = new cv.Rect(0, 0, cx, cy);
  let rect1 = new cv.Rect(cx, 0, cx, cy);
  let rect2 = new cv.Rect(0, cy, cx, cy);
  let rect3 = new cv.Rect(cx, cy, cx, cy);

  let q0 = prettypls.roi(rect0);
  let q1 = prettypls.roi(rect1);
  let q2 = prettypls.roi(rect2);
  let q3 = prettypls.roi(rect3);

  // exchange 1 and 4 quadrants
  q0.copyTo(tmp2);
  q3.copyTo(q0);
  tmp2.copyTo(q3);

  // exchange 2 and 3 quadrants
  q1.copyTo(tmp2);
  q2.copyTo(q1);
  tmp2.copyTo(q2);

  cv.imshow('fourierTransform', prettypls);

  //HANDLE IFFT
  let tmp1 = reverseFastFourier(tmp,height,width);
  //take the magnitudes
  for(i=0;i<height;i++){
    for(j=0;j<width;j++){
      temp[i][j]=Math.round(tmp1[i][j].re);
    }
  }

  for(i=0;i<height;i++){
    for(j=0;j<width;j++){
      let pixel = prettypls.ucharPtr(i,j);
      pixel[0] = Math.max(0, Math.min(255, temp[i][j]));
    }
  }
  cv.imshow('reverseFourier', prettypls);
  temp=[];tmp=[];prettypls.delete();
}

Я что-то пропустил или что-то не так с моим кодом?


person Welly Winata    schedule 03.12.2018    source источник
comment
Является ли это преобразование журнала и вычисление величины частью вычисления отфильтрованного изображения или только для промежуточного отображения? Опять же, мне трудно следовать коду с temp, tmp, tmp1 и т. д. Пожалуйста, удалите биты, которые не имеют отношения к вычислению окончательного отфильтрованного изображения. Вам будет намного легче получить ответ.   -  person Cris Luengo    schedule 03.12.2018
comment
@CrisLuengo готово, приятель, спасибо за совет!   -  person Welly Winata    schedule 03.12.2018
comment
@CrisLuengo только что отредактировал. это просто часть дисплея. поэтому в основном я вычисляю расстояние (tempD) на основе каждого квадранта (состояния), затем показываю Фурье и инвертирую его обратно   -  person Welly Winata    schedule 03.12.2018
comment
имхо, черные пятна в белой области выглядят как переполнение байтов (значения, которые будут больше 255, но ограничены 8 битами)   -  person Micka    schedule 03.12.2018
comment
Я добавил тег JavaScript, потому что важно использовать тег языка, который вы используете. Пожалуйста, исправьте, если я ошибся в языке.   -  person Cris Luengo    schedule 03.12.2018


Ответы (1)


Я предполагаю, что ваша проблема в этой строке:

pixel[0]=Math.round(temp[i][j]);

Здесь вы копируете значение с плавающей запятой, полученное в результате вещественного компонента обратного преобразования Фурье, в 8-битное целое число без знака (я предполагаю, что я вижу в коде).

Если одно из этих значений немного выше 255, что может произойти с «идеальным» фильтром нижних частот из-за артефактов звона, то преобразование в 8-битное целое число без знака приведет к циклическому переносу значения.

Что вам нужно сделать, так это зафиксировать значение в диапазоне [0,255]. Замените эту строку на:

pixel[0] = Math.max(0, Math.min(255, temp[i][j]));

Примечание. Я предполагаю, что этот синтаксис будет работать на основе небольшого поиска в Google, но это концепция, на которую вам нужно обратить внимание...

Вызов Math.round не нужен, так как temp уже содержит округленные значения.

person Cris Luengo    schedule 03.12.2018
comment
вы правильно прочитали, я копирую число с плавающей запятой из реального ift. и ваш синтаксис тоже работает нормально, к сожалению, это не решает проблему, так как результат остается прежним. в любом случае спасибо за вашу помощь, очень ценю это! - person Welly Winata; 03.12.2018
comment
@WellyWinata: Вы поместили это в последний раздел кода, где вы создаете образ для reverseFourier? У вас есть несколько повторяющихся фрагментов кода, и теперь я заметил, что эта конкретная строка кода встречается в вашей программе дважды. Я использовал слово «догадка» в своем ответе, но на самом деле я совершенно уверен, что это ваша проблема, и вам нужно убедиться, что преобразование из числа с плавающей запятой в 8-битное целое проходит правильно. Как это сделать в JavaScript, я менее уверен. - person Cris Luengo; 03.12.2018
comment
только что отредактировал код, пожалуйста, посмотрите. это ты правильно имел в виду? - person Welly Winata; 03.12.2018
comment
@WellyWinata: пока temp является массивом с плавающей запятой, а не массивом uint8. Я не могу сказать, потому что я не знаю JavaScript. Почему у вас так много массивов с такими похожими именами? А почему бы вам не объединить эти две двойные петли в одну? temp там вообще не нужно! - person Cris Luengo; 03.12.2018
comment
Это сработало как шарм, я пытался понять это несколько дней. спасибо приятель, очень ценю это! - person Welly Winata; 03.12.2018