카메라 개발자 공부방(SW)

DFT(Discrete Fourier Transform) 본문

영상처리(DigitalImageProcessing)

DFT(Discrete Fourier Transform)

luckmart 2021. 11. 14. 19:59
반응형

영상 신호를 주파수 영역으로 변환시키는 DFT 코드 입니다. 입력은 pSrc이고 출력은 pReal, pImaginary입니다.

void FourierTransform::DFT(Mat* pSrc, Mat* pReal, Mat* pImaginary)
{
    *pReal = Scalar(0);
    *pImaginary = Scalar(0);

    float* src = pSrc->ptr<float>(0);
    float* real = pReal->ptr<float>(0);
    float* imaginary = pImaginary->ptr<float>(0);
    float N = (float)pSrc->rows;
    float M = (float)pSrc->cols;
    float NM = N * M;
    /* If you want to visualize this frequency domain, you should adjust coefficient scale */
    // NM = sqrtf(NM);

    uint channel = pSrc->channels();
    float pixel = 0;
    float term = 0;

    for (float u = 0; u < N; u++)
    {
        for (float v = 0; v < M; v++)
        {
            src = pSrc->ptr<float>(0);

            for (float x = 0; x < N; x++)
            {
                for (float y = 0; y < M; y++)
                {
                    pixel = (*src);
                    term = 2 * PI * ((u * x / N) + (v * y / M));
                    *real += (pixel * cosf(term));
                    *imaginary -= (pixel * sinf(term));
                    src += channel;
                }
            }

            *(real) /= NM;
            *(imaginary) /= NM;

            real += channel;
            imaginary += channel;
        }
    }
}

 

DFT 결과가 이미지 중앙에 오게끔 좌우 대칭하는 코드입니다.

void FourierTransform::shiftImage(Mat* pSrcReal, Mat* pDstReal)
{
    float* srcReal = pSrcReal->ptr<float>(0);
    float* dstReal = pDstReal->ptr<float>(0);
    int row = pSrcReal->rows / 2;
    int col = pSrcReal->cols / 2;

    int srcRowVariance[4] = { 0,     0, row, row };
    int srcColVariance[4] = { 0,   col,   0, col };    
    int dstRowVariance[4] = { row, row,   0,   0 };
    int dstColVariance[4] = { col,   0, col,   0 };

    for (int k = 0; k < 4; k++) 
    {
        for (int u = 0; u < row; u++)
        {
            for (int v = 0; v < col; v++)
            {
                srcReal = pSrcReal->ptr<float>(u + srcRowVariance[k]) + v + srcColVariance[k];
                dstReal = pDstReal->ptr<float>(u + dstRowVariance[k]) + v + dstColVariance[k];

                *dstReal = *srcReal;
            }
        }
    }
}

실수부와 허수부를 가시화 하기 위한 코드입니다.

void FourierTransform::Spectrum(Mat* pReal, Mat* pImaginary, Mat* pDst, float scale)
{
    float* real = pReal->ptr<float>(0);
    float* imaginary = pImaginary->ptr<float>(0);
    float* dst = pDst->ptr<float>(0);
    float p0 = 0.f, i0 = 0.f;
    uint channel = pReal->channels();

    for (int u = 0; u < pReal->rows; u++)
    {
        for (int v = 0; v < pReal->cols; v++)
        {
            p0 = *real, i0 = *imaginary;
            *dst = (sqrtf((p0 * p0) + (i0 * i0))) * scale;

            real += channel;
            imaginary += channel;
            dst += channel;
        }
    }
}

사각 apertureDFT 결과
왼쪽: box aperture  / 오른쪽 DFT 결과 가시화(shiftImage & spectrum 함수 적용)
육각 apertureDFT 결과
왼쪽: 육각 aperture / 오른쪽 DFT 결과 가시화(shiftImage & spectrum 함수 적용)

 

반대로 주파수 영역의 신호를 공간 주파수 영역으로 변환시키는 IDFT 코드입니다. 입력은 pReal, pImaginary 출력은 pDst 입니다.

void FourierTransform::IDFT(Mat* pReal, Mat* pImaginary, Mat* pDst)
{
    float* real = pReal->ptr<float>(0);
    float* imaginary = pImaginary->ptr<float>(0);
    float sumReal = 0.f;
    float sumImaginary = 0.f;

    float* dst = pDst->ptr<float>(0);
    uint channel = pReal->channels();

    float N = (float)pReal->rows;
    float M = (float)pReal->cols;
    float NM = N * M;
    float term = 0.f;
    float r = 0.f, i = 0.f;
    float pixel = 0.f;

    for (float x = 0; x < N; x++)
    {
        for (float y = 0; y < M; y++)
        {
            real = pReal->ptr<float>(0);
            imaginary = pImaginary->ptr<float>(0);
            sumReal = 0.f;
            sumImaginary = 0.f;

            for (float u = 0; u < N; u++)
            {
                for (float v = 0; v < M; v++)
                {
                    term = 2 * PI * ((u * x / N) + (v * y / M));
                    r = *real;
                    i = *imaginary;

                    sumReal += r * cosf(term) - i * sinf(term);
                    sumImaginary += r * sinf(term) + i * cosf(term);

                    real += channel;
                    imaginary += channel;
                }
            }

            pixel = sqrtf((sumReal) * (sumReal)+(sumImaginary) * (sumImaginary));

            if (pixel < 0) pixel = 0.f;
            if (pixel > 1) pixel = 1.f;

            *dst = pixel;

            sumReal += channel;
            sumImaginary += channel;
            dst += channel;
        }
    }
}

입력이미지DFT 결과IDFT 결과
맨왼쪽: 입력이미지 / 중앙: DFT 결과 / 맨오른쪽: DFT 결과를 IDFT 한 결과

 

 

'영상처리(DigitalImageProcessing)' 카테고리의 다른 글

FFT(Fast Fourier Transform)  (0) 2021.11.15
Comments