Удаление синусоидального шума фильтром Баттерворта

Я пытаюсь удалить синусоидальный шум на этом изображении:

enter image description here

Вот его спектр DFT (после применения логарифма и произвольного масштабирования интенсивности):

enter image description here

У меня уже есть фильтр Баттерворта для применения к этому изображению. Он будет выбивать среднечастотные пики. Я позабочусь о его масштабировании с [0..255] до [0..1.0] после загрузки. Здесь фильтр:

enter image description here

Результаты невелики:

enter image description here

Мои вопросы:

  • Почему в изображении остается значительное количество шума?
  • Почему результат темнее исходного изображения? Фильтр явно не касается термина DC, поэтому я ожидаю, что средняя интенсивность будет одинаковой.
  • Почему фильтр выбирает только некоторые пики? Это из учебника, поэтому я склонен полагать, что это правильно, но есть другие пики в спектре - они также являются частью шума? Я попытался удалить их с помощью концентрических фильтров, но он не принес много пользы и затемнил изображение до неузнаваемости.

Я взял изображение (обрезанное) и отфильтровываю из книги Обработка цифровых изображений по Gonzalez и Woods. В их примере периодический шум полностью удаляется фильтрацией, а средняя интенсивность изображения остается неизменной.

Мой исходный код для загрузки изображения и фильтра, DFT, фильтрация, IDFT находится ниже:

import cv

def unshift_crop(comp, width, height):
    result = cv.CreateImage((width, height), cv.IPL_DEPTH_8U, 1)
    for x in range(height):
        for y in range(width):
            real, _, _, _ = cv.Get2D(comp, x, y)
            real = int(real) * ((-1)**(x+y))
            cv.Set2D(result, x, y, cv.Scalar(real))
    return result

def load_filter(fname):
    loaded = cv.LoadImage(fname, cv.CV_LOAD_IMAGE_GRAYSCALE)
    flt = cv.CreateImage(cv.GetSize(loaded), cv.IPL_DEPTH_32F, 2)
    width, height = cv.GetSize(loaded)
    for i in range(width*height):
        px, _, _, _ = cv.Get1D(loaded, i)
        #cv.Set1D(flt, i, cv.Scalar(px/255.0, 0))
        cv.Set1D(flt, i, cv.Scalar(px/255.0, px/255.0))
    return flt

if __name__ == '__main__':
    import sys
    fname, filt_name, ofname = sys.argv[1:]
    img = cv.LoadImage(fname, cv.CV_LOAD_IMAGE_GRAYSCALE)
    width, height = cv.GetSize(img)
    src = cv.CreateImage((width*2, height*2), cv.IPL_DEPTH_32F, 2)
    dst = cv.CreateImage((width*2, height*2), cv.IPL_DEPTH_32F, 2)
    cv.SetZero(src)
    for x in range(height):
        for y in range(width):
            px, _, _, _ = cv.Get2D(img, x, y)
            px = float(px) * ((-1) ** (x+y))
            cv.Set2D(src, x, y, cv.Scalar(px, 0))
    cv.DFT(src, dst, cv.CV_DXT_FORWARD)
    flt = load_filter(filt_name)
    cv.Mul(dst, flt, src)
    cv.DFT(src, dst, cv.CV_DXT_INV_SCALE)
    result = unshift_crop(dst, width, height)
    cv.SaveImage(ofname, result)

ИЗМЕНИТЬ

В исходном источнике произошла ошибка, в которой фильтровальные мнимые компоненты были загружены как ноль. Это то, что заставило изображение результата выглядеть темнее, чем было на самом деле. Я исправил это и прокомментировал связанную строку.

Использование фиксированного источника и фильтра, предоставленного @0x69 (да, я знаю, что это не фильтр Баттерворта, но на этом этапе я счастлив попробовать что-нибудь), это результат:

enter image description here

Лучше, чем я должен был начать, но все же не так хорошо, как я надеюсь. Может ли кто-нибудь победить? Я подозреваю, что добавление большего количества выемок для выведения оставшихся пиков может принести пользу.

РЕДАКТИРОВАТЬ 2

Я связался с автором. Это их ответ:

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

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

Ответ 1

Я попытался использовать такой модифицированный фильтр: enter image description here
и что у меня есть это →
enter image description here
Я не могу полностью объяснить результаты, но, насколько я понимаю, синусоидальный шум, взаимодействуя с сигналом основного изображения, как-то генерирует вторичные, третьи... гармонические шумовые волны. Результат также далек от идеала, кажется, что некоторые шумовые гармоники остаются здесь... Кстати, спасибо за интересный вопрос.

EDIT:

Моя вторая попытка улучшения фильтра. Фильтр:
enter image description here Отфильтрованный результат:
enter image description here
Похоже, в этот раз видимая синусоидальная шумовая картина не видна.

Ответ 2

Я помню, как я играл с этим изображением во время курса обработки изображений пару лет назад, и я получил те же результаты, что и вы.

Я не знаю, как авторы учебника получили изображение, которое они отображают в книге, но они, должно быть, сделали что-то более, чем применить этот фильтр Баттерворта. Как вы заметили, есть больше пиков, поэтому возможно, что они применили больше фильтров Баттерворта, чтобы удалить их.

Однако среднее значение изображения оставалось неизменным для меня. Вы пытались вычислить среднее из двух изображений и сравнить? Возможно, это просто масштабирование при отображении, которое вызывает более темное изображение.