Filter Library Camera Interface Physics

ScanFilterFFTInverse.cpp

00001 /*
00002  * ScanFilterFFTInverse.cpp - inverse FFT.
00003  *
00004  * This file is part of the Camera Filter Library.
00005  * Computer Aided Measurement Environment for Realtime Atomic imaging (Camera)
00006  *
00007  * Copyright (C) 2004-2005, Leiden Probe Microscopy.
00008  * Copyright (C) 2004-2005, Universiteit Leiden.
00009  *
00010  * Authors: M. Seynen (original), Martin J. Moene
00011  *
00012  * $Id: ScanFilterFFTInverse.cpp 511 2007-04-03 10:19:11Z moene $
00013  */
00014 
00015 #include "stdafx.h"                     // for common (pre-compiled) headers
00016 //#include <cfl/stdafx.h>                 // for common (pre-compiled) headers
00017 #include <cfl/resource.h>               // for messages and other resources
00018 
00019 #include <Camera/InterfaceDll.h>        // Camera--Filter Library interface
00020 
00021 #include <cfl/ScanFilterFFTInverse.h>   // this filter's header
00022 #include <cfl/ScanFilterClip.h>         // clipping (cropping) filter
00023 #include <cfl/ToolCilImage.h>           // for Image type and ToImage conversion shim
00024 
00025 #include <cil/Math.h>                   // for real(), //min(), max(), sqrt(), sin(), Pi
00026 #include <cil/Traits.h>                 // for NumericTraits<>::Min()
00027 #include <cil/FFTInverseImageFilter.h>          // FFT inverse image filter
00028 #include <cil/RescaleIntensityImageFilter.h>    // to rescale inverse FFT image
00029 
00030 #pragma warning( disable : 4663 )       // template<> Class<type>
00031 #include <limits>                       // for numeric_limits<>
00032 #pragma warning( default : 4663 )
00033 
00034 #undef min                              // use cil::min instead of macro
00035 #undef max                              // use cil::max instead of macro
00036 
00037 /*
00038  * configuration defines:
00039  */
00040 
00041 // currently none
00042 // #define USE_FULL_SCALE               // rescale output
00043 // #define USE_FULL_IFFT                // do not crop image
00044 
00045 /*
00046  * end of configuration defines.
00047  */
00048 
00049 #ifdef _DEBUG
00050 #undef THIS_FILE
00051 static char THIS_FILE[]=__FILE__;
00052 #define new DEBUG_NEW
00053 #endif
00054 
00055 #define CFL_SCHEMAVERSION_FILTERIFFT 0  // permanent storage schema version
00056                                         // this filter's name
00057 LPCTSTR CScanFilterFFTInverse::m_lpcsFilterName = _T("Inverse-Fast-Fourier-Transform");
00058                                         // this filter's short name
00059 LPCTSTR CScanFilterFFTInverse::m_lpcsShortFilterName = _T( "FFT-1" );
00060                                         // serialization
00061 IMPLEMENT_SERIAL( CScanFilterFFTInverse, CScanFilter, CFL_SCHEMAVERSION_FILTERIFFT)
00062 
00063 /**
00064  * constructor.
00065  */
00066 CScanFilterFFTInverse::CScanFilterFFTInverse()
00067    : m_lpsbTmp( new CScanBaseBuffer )
00068 {
00069 //   Q_LOG( _T("CScanFilterBgsDiff::CScanFilterBgsDiff()") );
00070 
00071    m_csFilterName = m_lpcsFilterName;
00072 }
00073 
00074 /**
00075  * destructor.
00076  */
00077 CScanFilterFFTInverse::~CScanFilterFFTInverse()
00078 {
00079 //   Q_LOG( _T("CScanFilterFFTInverse::~CScanFilterFFTInverse()") );
00080 
00081    delete m_lpsbTmp;
00082    ; // do nothing
00083 }
00084 
00085 /**
00086  * no dialog.
00087  */
00088 BOOL CScanFilterFFTInverse::CanDoDialogEntry() const
00089 {
00090    return FALSE;
00091 }
00092 
00093 /**
00094  * store or retrieve the object's settings;
00095  * see also CScanFilterNull::Serialize().
00096  */
00097 void CScanFilterFFTInverse::Serialize(CArchive& ar)
00098 {
00099    CScanFilter::Serialize( ar );
00100 
00101    if ( ar.IsStoring() )
00102    {
00103       ; // do nothing
00104    }
00105    else
00106    {
00107       ; // do nothing
00108    }
00109 };
00110 
00111 /**
00112  * no parameters.
00113  */
00114 #pragma warning( push )
00115 #pragma warning( disable : 4100 )       // unreferenced formal parameter
00116 
00117 BOOL CScanFilterFFTInverse::SetParameters(LPCTSTR lpParameters)
00118 {
00119    return TRUE;
00120 }
00121 
00122 #pragma warning( pop )
00123 
00124 /*
00125  * no parameters.
00126  */
00127 LPCTSTR CScanFilterFFTInverse::GetParameters() const
00128 {
00129    return NULL;
00130 }
00131 
00132 /**
00133  * check parameters, take care of a properly sized output buffer,
00134  * set its name and copy filter parameters and process;
00135  * see also CScanFilterNull::ApplyCore().
00136  */
00137 BOOL CScanFilterFFTInverse::Apply()
00138 {
00139 //   Q_LOG( _T("CScanFilterCrossCorrelate::Apply()") );
00140 
00141    if ( Q_INVALID( NULL == m_lpsbIn && "ensure input buffer") )
00142       return FALSE;
00143 
00144    if ( Q_INVALID( NULL == m_lpsbTmp ) && "ensure valid temporary buffer" )
00145       return FALSE;
00146 
00147    if ( Q_INVALID( NULL == m_lpsbOut && "ensure output buffer" ) )
00148       return FALSE;
00149 
00150    if ( Q_INVALID( !m_lpsbIn->IsCompleteFrame() && "ensure complete frame" ) )
00151       return FALSE;
00152 
00153    /*
00154     * copy the filter settings (not the data):
00155     */
00156    Q_RETURN( m_lpsbTmp->CreateOutputBufferFor( *m_lpsbIn ) );
00157 
00158    m_lpsbTmp->m_csBufferName = m_lpsbIn->m_csBufferName + _T(" - ") + m_lpcsShortFilterName;
00159    m_lpsbTmp->m_csDataName.Format(_T("%s(%s)"), m_lpcsShortFilterName, m_lpsbIn->m_csDataName );
00160 
00161    /*
00162     * create a new suspended thread to do the computation;
00163     * the progressdialog resumes the thread and displays the progress:
00164     */
00165    CProgressDlg dlg( AfxGetMainWnd() ); // IFFT has no dialog
00166 
00167    ThreadArgs threadArgs( &dlg, this );
00168 
00169    CWinThread *hThread = AfxBeginThread(
00170       ComputationThreadFunction,        // the controlling function for the worker thread
00171       &threadArgs,                      // the arguments and return value
00172       THREAD_PRIORITY_BELOW_NORMAL,     // the priority
00173       0,                                // 0: the stack size defaults to the same size
00174                                         //    stack as the creating thread.
00175       CREATE_SUSPENDED,                 // create it in suspended state
00176       NULL                              // security attributes structure
00177    );
00178 
00179    /*
00180     * show progress dialog, try to start thread:
00181     */
00182    if ( dlg.DoModal( hThread ) <= 0 )
00183    {
00184       return FALSE;
00185    };
00186 
00187    /*
00188     * return thread result:
00189     */
00190    return threadArgs.bReturn;
00191 }
00192 
00193 /**
00194  * create a thread that computes the result.
00195  */
00196 UINT CScanFilterFFTInverse::ComputationThreadFunction( LPVOID lpContext )
00197 {
00198 //   Q_LOG( _T("CScanFilterFFTInverse::ComputationThreadFunction()") );
00199 
00200    CScanFilterFFTInverse::ThreadArgs *lpTreadArgs = static_cast< CScanFilterFFTInverse::ThreadArgs* >( lpContext );
00201 
00202    lpTreadArgs->bReturn = lpTreadArgs->pThis->Compute( lpTreadArgs->pDlg );
00203 
00204    lpTreadArgs->pDlg->Terminate();
00205 
00206    return lpTreadArgs->bReturn;
00207 }
00208 
00209 /**
00210  * compute the desired result.
00211  */
00212 BOOL CScanFilterFFTInverse::Compute( CProgressDlg *pDlg )
00213 {
00214 //   Q_LOG( _T("CScanFilterFFTInverse::Compute()") );
00215 
00216    ASSERT( m_lpsbIn  );
00217    ASSERT( m_lpsbTmp );
00218    ASSERT( m_lpsbOut );
00219 
00220    /*
00221     * prepare some local varables:
00222     */
00223    BOOL bL2R = m_lpsbIn->HasLeftToRightScan();
00224    BOOL bR2L = m_lpsbIn->HasRightToLeftScan();
00225 
00226    /*
00227     * update progress dlg; don't touch dialog from other thread!
00228     */
00229    pDlg->SetText ( _T("Computing 2D inverse fast fourier transformation" ) );
00230    pDlg->SetRange( 0, bR2L && bL2R ? 2: 1 );
00231 
00232    /*
00233     * check for FFT input to filter:
00234     */
00235    if ( bL2R && 0 == m_lpsbIn->m_pdFourierL2R ||
00236         bR2L && 0 == m_lpsbIn->m_pdFourierR2L   )
00237    {
00238       MessageBox(
00239          IsInteractive() ? m_pDlg->m_hWnd : AfxGetMainWnd()->m_hWnd,
00240          _T( "This scanbuffer does not contain a fourier spectrum." ),
00241          _T( "Cannot transform" ),
00242          MB_ICONEXCLAMATION | MB_OK
00243       );
00244 
00245       return FALSE;
00246    }
00247 
00248    /*
00249     * allocate fourier buffer:
00250     *
00251     * Note if we come this far, we know that the temporary buffer is created
00252     * from an input buffer that contains an FFT, so the temporary buffer's size
00253     * is already appropriate for handling FFT.
00254     */
00255    Q_RETURN( m_lpsbTmp->CopyFourierBufferFrom( *m_lpsbIn ) );
00256 
00257    /*
00258     * perform the left-right and right-left transformations:
00259     */
00260    int progress = 0;
00261 
00262    if ( bL2R )
00263    {
00264       ComputePart( m_lpsbTmp->FourierDataL2R(), ToImage( m_lpsbTmp, false ) );
00265 
00266       pDlg->SetPos( ++progress );
00267    }
00268 
00269    if ( bR2L )
00270    {
00271       ComputePart( m_lpsbTmp->FourierDataR2L(), ToImage( m_lpsbTmp, true ) );
00272 
00273       pDlg->SetPos( ++progress );
00274    }
00275 
00276    /*
00277     * release the allocated fourier memory, because it does not contain an FFT
00278     * spectrum anymore:
00279     */
00280    m_lpsbTmp->DeleteFourierBuffer();
00281 
00282    /*
00283     * crop the image to the original size, unless USE_FULL_IFFT is defined;
00284     */
00285    Q_RETURN( CropImage() );
00286 
00287    /*
00288     * set the output buffer name (prevent Clip from showing):
00289     */
00290    m_lpsbOut->m_csBufferName.Format( _T("%s - %s"), m_lpsbIn->m_csBufferName, m_lpcsShortFilterName );
00291 
00292    /*
00293     * check if a stop is requested from the progress dialog:
00294     */
00295    if ( pDlg->StopRequested() )
00296    {
00297       return FALSE;
00298    }
00299    else
00300    {
00301       return TRUE;
00302    }
00303 }
00304 
00305 /**
00306  * compute a frame.
00307  */
00308 void CScanFilterFFTInverse::ComputePart( FourierElementType** pFFT, Image& dst )
00309 {
00310    using   cil::Size2D;
00311 
00312    typedef std::complex< FourierElementType > Complex;
00313 
00314    typedef cil::Image< Complex              > FFTImageType;
00315    typedef cil::Image< FourierElementType   > IFFTImageType;
00316    typedef      Image                         OutputImageType;
00317 
00318    typedef cil::FFTInverseImageFilter       < FFTImageType , IFFTImageType   > FFTInverseImageFilter;
00319    typedef cil::RescaleIntensityImageFilter < IFFTImageType, OutputImageType > RescaleIntensityImageFilter;
00320 
00321    /*
00322     * the FFT Image view on the CScanBaseBuffer FFT databuffer:
00323     *
00324     * the FFT Image is a 1-dimensional array of complex<FourierElementType>
00325     * the CScanBaseBuffer FFT databuffer is a 2-dimensional array of FourierElementType
00326     *
00327     *            fftImage.Data () ----------->   cmplx
00328     * m_lpsbOut->FourierDataL2R() => [row0] -> [ re,im . . . ]  <- important: contiguous block
00329     *                                   .      [   .   . . . ]
00330     *                                   .      [   .   . . . ]
00331     *                                [rowN] -> [   .   . . . ]
00332     *
00333     */
00334    Size2D fftSize( Size2D( dst.Width(), dst.Height() ) );
00335    FFTImageType fftImage( reinterpret_cast<FFTImageType::PixelType*>( cil::To1DView( pFFT ) ), fftSize );
00336 
00337    IFFTImageType ifftImage;
00338 
00339    /*
00340     * do the inverse FFT transformation:
00341     */
00342    FFTInverseImageFilter fftiFilter;
00343    fftiFilter.Apply( fftImage, ifftImage );
00344 
00345    /*
00346     * scale to result to the (integral) destination image:
00347     */
00348    RescaleIntensityImageFilter scaleFilter;
00349    scaleFilter.SetOutputMinimum( lpm::NumericTraits< OutputImageType::ValueType >::Min() );
00350    scaleFilter.SetOutputMaximum( lpm::NumericTraits< OutputImageType::ValueType >::Max() );
00351    scaleFilter.Apply( ifftImage, dst );
00352 }
00353 
00354 /**
00355  * crop image to original size (remove border with zero data).
00356  */
00357 BOOL CScanFilterFFTInverse::CropImage()
00358 {
00359    typedef CScanFilterClip CropFilter;
00360 
00361    CropFilter cropFilter;
00362 
00363    cropFilter.SetDragInput   ( false, GetUsedRectangle() );
00364    cropFilter.SetInputBuffer ( 0, m_lpsbTmp );
00365    cropFilter.SetOutputBuffer( 0, m_lpsbOut );
00366 
00367    return cropFilter.Apply();
00368 }
00369 
00370 /**
00371  * true if any edge contains non-zero data.
00372  */
00373 bool CScanFilterFFTInverse::HasNonzeroEdge() const
00374 {
00375    Pointer  data = m_lpsbTmp->Data();
00376    SizeType ncol = m_lpsbTmp->Columns();
00377    SizeType size = m_lpsbTmp->GetFrameSize();
00378 
00379    return 0 != data[  0              ]  // top-left
00380        || 0 != data[        ncol - 1 ]  // top-right
00381        || 0 != data[ size - ncol - 1 ]  // bottom-left
00382        || 0 != data[ size        - 1 ]; // bottom-right
00383 }
00384 
00385 /**
00386  * the rectangle that contains non-zero data;
00387  * from the outside to the inside we search for non-zero data;
00388  * if USE_FULL_IFFT is defined, rectange is full IFFT result.
00389  */
00390 CRect CScanFilterFFTInverse::GetUsedRectangle() const
00391 {
00392    typedef Pointer Iterator;
00393 
00394 #ifdef _CIL_MSC_6
00395    typedef std::reverse_iterator<Pointer, ValueType> ReverseIterator;
00396 #else
00397    typedef std::reverse_iterator<Pointer> ReverseIterator;
00398 #endif
00399 
00400    SizeType nrow   = m_lpsbTmp->Rows();
00401    SizeType ncol   = m_lpsbTmp->Columns();
00402    SizeType size   = m_lpsbTmp->GetFrameSize();
00403 
00404    /*
00405     * set default cropping coordinates:
00406     */
00407    SizeType left   = 0;
00408    SizeType right  = ncol - 0;
00409    SizeType top    = 0;
00410    SizeType bottom = nrow - 0;
00411 
00412 #ifdef USE_FULL_IFFT
00413    return CRect( left, top, right, bottom );
00414 #endif
00415 
00416    /*
00417     * if any edge contains non-zero data, return full rectangle:
00418     */
00419    if ( HasNonzeroEdge() )
00420    {
00421       return CRect( left, top, right, bottom );
00422    }
00423 
00424    /*
00425     * determine used rectangle:
00426     */
00427    Iterator itopleft  = m_lpsbTmp->Data();
00428    Iterator imidleft  = itopleft + size / 2;
00429    Iterator icenter   = imidleft + ncol / 2;
00430    Iterator ibotright = itopleft + size;
00431 
00432    /*
00433     * downward search each line for non-zero data:
00434     */
00435    Iterator pos = std::find_if(
00436       itopleft,                                         // start
00437       icenter ,                                         // end
00438       std::bind2nd( std::not_equal_to<ValueType>(), 0 ) // criterion
00439    );
00440 
00441    if ( pos != icenter )
00442    {
00443       top = 0 + ( pos - itopleft ) / ncol;
00444    }
00445 
00446    /*
00447     * upward search each line for non-zero data:
00448     */
00449    ReverseIterator rpos = std::find_if(
00450       ReverseIterator( ibotright ),                     // start
00451       ReverseIterator( icenter   ),                     // end
00452       std::bind2nd( std::not_equal_to<ValueType>(), 0 ) // criterion
00453    );
00454 
00455    if ( rpos != ReverseIterator( icenter ) )
00456    {
00457       bottom = nrow - ( rpos - ReverseIterator( ibotright ) ) / ncol;
00458    }
00459 
00460    /*
00461     * rightward search each column for non-zero data:
00462     */
00463 
00464    for ( Iterator icol = itopleft; icol < itopleft + ncol / 2; ++icol )
00465    {
00466       for ( Iterator it = icol; it < icenter; it += ncol )
00467       {
00468          if ( 0 != *it )
00469          {
00470             left = 0 + ( it - itopleft ) % ncol;
00471             goto foundLeft;
00472          }
00473       }
00474    }
00475 foundLeft: ;
00476 
00477    /*
00478     * leftward search each column for non-zero data:
00479     */
00480 
00481    for ( ReverseIterator ricol = ReverseIterator( ibotright );
00482                          ricol < ReverseIterator( itopleft + ncol / 2 ); ++ricol )
00483    {
00484       for ( ReverseIterator it = ricol; it < ReverseIterator( icenter ); it += ncol )
00485       {
00486          if ( 0 != *it )
00487          {
00488             right = ncol - ( it - ReverseIterator( ibotright ) ) % ncol;
00489             goto foundRight;
00490          }
00491       }
00492    }
00493 foundRight: ;
00494 
00495    return CRect( left, top, right, bottom );
00496 }
00497 
00498 /*
00499  * end of file
00500  */
00501 

Camera Filter Library documentation © 2004-2007 by Leiden Probe Microscopy