Я создаю фильтр нижних частот в частотной области с частотой среза 0,015 и соответствующий фильтр верхних частот, как показано ниже:
auto getGaussianFilter(int32_t size) {
const auto sigmaf = 0.015f*size; // cutoff freq.
cv::Mat kernel = cv::Mat::zeros(size, size, CV_32FC1);
for (auto fy = -size/2; fy < size/2; ++fy)
for (auto fx = -size/2; fx < size/2; ++fx)
kernel.at<float>(fy + size/2, fx + size/2) = std::exp(-(fy*fy+fx*fx)/(2*sigmaf*sigmaf));
return kernel;
}
...
lowpassFilter = getGaussianFilter(256);
highpassFilter = 1 - lowpassFilter;
, и они применяются к изображениям, как следующий фрагмент.
std::vector<cv::Mat> planes { src, cv::Mat::zeros(src.size(), src.type()) };
std::vector<cv::Mat> fplanes { filter, filter };
cv::Mat complex, complexFilter;
cv::merge(planes, complex);
cv::merge(fplanes, complexFilter);
cv::dft(complex, complex, cv::DFT_COMPLEX_OUTPUT);
shift(complex); // swapping quadrants
cv::mulSpectrums(complex, complexFilter, complex, cv::DFT_ROWS);
shift(complex);
cv::idft(complex, complex, cv::DFT_SCALE | cv::DFT_REAL_OUTPUT);
Входные изображения имеют размер 256×256 и в логарифмическом масштабе, а фильтр нижних частот применяется к квадрату отфильтрованных входных изображений верхних частот.
А потом я хочу получить квадратный корень из итогов финальной,
но он содержит отрицательные значения; Таким образом, появляются несколько значений NaN.
applyFilter(src, dst, highpassFilter);
cv::pow(dst, 2, dst);
applyFilter(dst, dst, lowpassFilter);
cv::sqrt(dst, dst); // NaN !
Почему существуют отрицательные значения и как с ними справиться, чтобы получить квадратный корень?
РЕДАКТИРОВАТЬ: добавлен код shift
void shift(cv::Mat& src) {
src = src(cv::Rect(0, 0, src.cols & -2, src.rows & -2));
const auto cy = src.rows/2, cx = src.cols/2;
cv::Mat q0(src, cv::Rect(0, 0, cx, cy));
cv::Mat q1(src, cv::Rect(cx, 0, cx, cy));
cv::Mat q2(src, cv::Rect(0, cy, cx, cy));
cv::Mat q3(src, cv::Rect(cx, cy, cx, cy));
cv::Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
Я не поймал этот, пока третий или четвертый не прочитал ваш код …
std::vector<cv::Mat> fplanes { filter, filter };
cv::merge(fplanes, complexFilter);
Здесь вы создаете комплексный фильтр, который не является сопряженным симметричным. Применение этого фильтра создает частотный спектр, который не является сопряженным симметричным, и, следовательно, вы получаете нереальное обратное преобразование.
То, что вы хотите сделать, это иметь чисто реальный фильтр:
std::vector<cv::Mat> fplanes { filter, cv::Mat::zeros(filter(), filter()) };
cv::merge(fplanes, complexFilter);
Подумайте о фильтрах в частотной области с точки зрения величины и фазы (а не действительного и мнимого компонента). Величина изменяет то, как вы меняете амплитуду каждого частотного компонента в вашем изображении, сдвиг фазы каждого частотного компонента. В целом (за исключением очень особых случаев) вы не хотите сдвигать частотные составляющие вашего изображения, так как это испортит ваше изображение. Таким образом, держите фазу ваших фильтров частотной области равной 0. Нулевая фаза означает, что каждое значение неотрицательно и реально.
Тем не менее, ваша последовательность сдвига частотного спектра изображения, применения фильтра и сдвига назад:
cv::dft(complex, complex, cv::DFT_COMPLEX_OUTPUT);
shift(complex); // swapping quadrants
cv::mulSpectrums(complex, complexFilter, complex, cv::DFT_ROWS);
shift(complex);
cv::idft(complex, complex, cv::DFT_SCALE | cv::DFT_REAL_OUTPUT);
идентично простому смещению фильтра:
cv::dft(complex, complex, cv::DFT_COMPLEX_OUTPUT);
shift(complexFilter); // swapping quadrants
cv::mulSpectrums(complex, complexFilter, complex, 0);
cv::idft(complex, complex, cv::DFT_SCALE | cv::DFT_REAL_OUTPUT);
Обратите внимание, что я заменил cv::DFT_ROWS
с 0. Согласно документация, этот флаг указывает, что каждая строка изображения является независимым 1D-преобразованием. Я предполагаю, что это имеет значение только для CCS-упакованных матриц, но лучше все равно не указывать.
Других решений пока нет …