Проблема с отображением вывода DFT с imshow openCV

Я следовал руководству на этом веб-сайте, чтобы создать фильтр нижних частот с использованием NumPy и OpenCV в python. Вместо отображения преобразованного изображения с помощью pyplot, как показано в руководстве, я попытался использовать функцию imshow OpenCV, но не получил желаемого результата.

img = cv2.imread('./lenna.jpg', 0)
img = np.array(img)


dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

rows, cols = img.shape
crow,ccol = int(rows/2) , int(cols/2)

mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1

fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

cv2.imshow('before', img)
cv2.imshow('after', img_back)
cv2.waitKey(0)

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

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
586
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Если вы хотите отображать данные в типе np.float32, вы должны нормализовать его до 1.0.

img_back = cv2.normalize(img_back, None, alpha=0, beta=1.0, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)

imshow ожидает, что числа с плавающей запятой в диапазоне 0..1 будут отображаться правильно (или uint8 в диапазоне 0..255).

сделайте это для чтения изображения:

img = cv2.imread('./lenna.jpg')
img = img / np.float32(255)

Я бы не советовал cv2.normalize с NORM_MINMAX, потому что это меняет глобальный контраст изображения, а это не то, что вам нужно (или не нужно).

далее я бы советовал получить реальную составляющую комплексного результата. не берите масштаб.

Почему брать действительную составляющую предпочтительнее, чем брать величину?

bgmn 20.12.2020 00:40

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

Christoph Rackwitz 20.12.2020 04:45

Это имеет смысл, спасибо! Но решение, которое вы предоставили, похоже, не дает правильного результата в моем примере.

bgmn 21.12.2020 21:03

ах вижу проблему. БПФ и коэффициенты масштабирования... Я добавлю еще один ответ.

Christoph Rackwitz 21.12.2020 21:58
Ответ принят как подходящий

Функции OpenCV FFT требуют, чтобы флаг масштабирования DFT_SCALE был задан ровно одному из dft,idft. см. примечание на https://docs.opencv.org/3.4/d2/de8/group__core__array.html#gaa708aa2d2e57a508f968eb0f69aa5ff1

Я решил передать его в первой функции, потому что она уже принимает другой флаг.

функциям fft2 numpy это не нужно. они работают как есть.

вот обе версии, отличающиеся только dft/idft и fft2/ifft2.

import os
import sys
import numpy as np
import cv2 as cv

def prepare_spectrum(spectrum):
    mag = np.linalg.norm(spectrum, axis=2)
    mag /= mag.max()
    mag **= 1/4

    return mag

img = cv.imread(cv.samples.findFile("lena.jpg"), cv.IMREAD_GRAYSCALE)
img = img / np.float32(255)

dft = cv.dft(img, flags=cv.DFT_COMPLEX_OUTPUT | cv.DFT_SCALE)

cv.imshow("1 dft", prepare_spectrum(dft))

dft_shift = np.fft.fftshift(dft)

cv.imshow("2 dft_shift", prepare_spectrum(dft_shift))

rows, cols = img.shape
crow,ccol = (rows // 2), (cols // 2)

mask = np.zeros((rows,cols,2), dtype=np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1

dft_shift *= mask

cv.imshow("3 dft_shift masked", prepare_spectrum(dft_shift))

dft = np.fft.ifftshift(dft_shift)

cv.imshow("4 dft masked", prepare_spectrum(dft))

img_back = cv.idft(dft)

img_back = img_back[:,:,0] # real part

cv.imshow('before', img)
cv.imshow('after', img_back)
cv.waitKey()
cv.destroyAllWindows()

Нампи:

import os
import sys
import numpy as np
import cv2 as cv

def prepare_spectrum(spectrum):
    mag = np.abs(spectrum)
    mag /= mag.max()
    mag **= 1/4

    return mag

img = cv.imread(cv.samples.findFile("lena.jpg"), cv.IMREAD_GRAYSCALE)
img = img / np.float32(255)

dft = np.fft.fft2(img)

cv.imshow("1 dft", prepare_spectrum(dft))

dft_shift = np.fft.fftshift(dft)

cv.imshow("2 dft_shift", prepare_spectrum(dft_shift))

rows, cols = img.shape
crow,ccol = (rows // 2), (cols // 2)

mask = np.zeros((rows,cols), dtype=np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1

dft_shift *= mask

cv.imshow("3 dft_shift masked", prepare_spectrum(dft_shift))

dft = np.fft.ifftshift(dft_shift)

cv.imshow("4 dft masked", prepare_spectrum(dft))

img_back = np.fft.ifft2(dft)

img_back = np.real(img_back)

cv.imshow('before', img)
cv.imshow('after', img_back)
cv.waitKey()
cv.destroyAllWindows()

Другие вопросы по теме