Filter Library Camera Interface Physics

ScanFilterHighPass.cpp

00001 /*
00002  * ScanFilterHighPass.cpp - highpass filter (frequency domain).
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: ScanFilterHighPass.cpp 400 2006-09-28 13:34:02Z moene $
00013  */
00014 
00015 /*
00016  * configuration defines:
00017  */
00018 
00019 // currently none
00020 
00021 /*
00022  * end of configuration defines.
00023  */
00024 
00025 #include "stdafx.h"                     // for common (pre-compiled) headers
00026 //#include <cfl/stdafx.h>                 // for common (pre-compiled) headers
00027 #include <cfl/resource.h>               // for messages and other resources
00028 
00029 #include <Camera/InterfaceDll.h>        // Camera--Filter Library interface
00030 
00031 #include <cfl/ScanFilterHighPass.h>     // this filter's header
00032 #include <cfl/FilterDlg_HighPass.h>     // this filter's dialog
00033 
00034 #pragma warning( disable: 4018 4100 4116 4146 4244 4663)
00035 #include <cil/Math.h>                   // for lpm::min()
00036 #pragma warning( default: 4018 4100 4116 4146 4244 4663)
00037 
00038 #undef min                              // use lpm::min instead of macro
00039 #undef max                              // use lpm::max instead of macro
00040 
00041 #ifdef _DEBUG
00042 #undef THIS_FILE
00043 static char THIS_FILE[]=__FILE__;
00044 #define new DEBUG_NEW
00045 #endif
00046 
00047 #define CFL_SCHEMAVERSION_FILTERHIGHPASS 0  // permanent storage schema version
00048                                                 // this filter's name
00049 LPCTSTR CScanFilterHighPass::m_lpcsFilterName = _T("High-Pass");
00050                                         // this filter's short name
00051 LPCTSTR CScanFilterHighPass::m_lpcsShortFilterName = _T( "HP" );
00052                                                 // serialization
00053 IMPLEMENT_SERIAL(CScanFilterHighPass, CScanFilterFourierBase, CFL_SCHEMAVERSION_FILTERHIGHPASS)
00054 
00055 /*
00056  * the default shift flag.
00057  */
00058 const CScanFilterHighPass::RealType CScanFilterHighPass::def_dCutOff = 0.25;
00059 
00060 /*
00061  * the default clad flag.
00062  */
00063 const CScanFilterHighPass::RealType CScanFilterHighPass::def_dSoftEdge = 0.05;
00064 
00065 /*
00066  * constructor.
00067  */
00068 CScanFilterHighPass::CScanFilterHighPass() :
00069    m_dCutOff   ( def_dCutOff ),
00070    m_dSoftEdge ( def_dSoftEdge )
00071 {
00072    //   Q_LOG( _T("CScanFilterHighPass::CScanFilterHighPass()") );
00073 
00074    m_csFilterName = m_lpcsFilterName;
00075 
00076    ReadFilterSettings();
00077 }
00078 
00079 /*
00080  * destructor.
00081  */
00082 CScanFilterHighPass::~CScanFilterHighPass()
00083 {
00084 //   Q_LOG( _T("CScanFilterHighPass::~CScanFilterHighPass()") );
00085 }
00086 
00087 /*
00088  * store or retrieve the object's settings;
00089  * see also CScanFilterNull::Serialize().
00090  */
00091 void CScanFilterHighPass::Serialize(CArchive& ar)
00092 {
00093 //   Q_LOG( _T("CScanFilterHighPass::~Serialize()") );
00094 
00095    CScanFilterFourierBase::Serialize( ar );
00096 
00097    if ( ar.IsStoring() )
00098    {
00099       ar << m_dCutOff << m_dSoftEdge;
00100    }
00101    else
00102    {
00103       ar >> m_dCutOff >> m_dSoftEdge;
00104    }
00105 }
00106 
00107 /*
00108  * \brief configure filter with settings as provided by the application on the
00109  * filterlist window (e.g. via registry); see also CScanFilterNull::ReadFilterSettings().
00110  */
00111 void CScanFilterHighPass::ReadFilterSettings( )
00112 {
00113 //   Q_LOG( _T("CScanFilterHighPass::ReadFilterSettings()") );
00114 
00115    CWinApp* pApp = AfxGetApp();
00116 
00117    if ( Q_INVALID( NULL == pApp ) )
00118       return ;
00119 
00120    /*
00121     * parameter string:
00122     */
00123    SetParameters( pApp->GetProfileString( gCflRegistrySubkey, m_lpcsFilterName, _T( "0.75,0.05" ) ) );
00124 }
00125 
00126 /*
00127  * \brief save filter settings e.g. for use with the filterlist window (e.g. via registry);
00128  * see also ReadFilterSettings().
00129  */
00130 void CScanFilterHighPass::WriteFilterSettings() const
00131 {
00132 //   Q_LOG( _T("CScanFilterHighPass::ReadFilterSettings()") );
00133 
00134    CWinApp* pApp = AfxGetApp();
00135 
00136    if ( Q_INVALID( NULL == pApp ) )
00137       return ;
00138 
00139    /*
00140     * parameter string:
00141     */
00142    LPCTSTR pStr = GetParameters();
00143 
00144    if ( pStr )
00145    {
00146       pApp->WriteProfileString( gCflRegistrySubkey, m_lpcsFilterName, pStr );
00147       delete const_cast<LPTSTR>( pStr );
00148    }
00149 }
00150 
00151 /*
00152  * provide current filter parameter(s) for filter-scripting capture
00153  * in the main application;
00154  * see also CScanFilterNull::GetParameters().
00155  */
00156 LPCTSTR CScanFilterHighPass::GetParameters( ) const
00157 {
00158 //   Q_LOG( _T("CScanFilterHighPass::GetParameters()") );
00159 
00160    /*
00161     * format parameters and return a c-string on the heap:
00162     */
00163    CString csParameters;
00164 
00165    csParameters.Format( _T("%.2lf,%.2lf"), m_dCutOff, m_dSoftEdge );
00166 
00167    return strcpy( new TCHAR[ csParameters.GetLength() + 1 ], csParameters );
00168 }
00169 /*
00170  * set parameters for filter-script execution of filter;
00171  * see also CScanFilterNull::SetParameters().
00172  */
00173 BOOL CScanFilterHighPass::SetParameters( LPCTSTR lpParameters )
00174 {
00175 //   Q_LOG( _T("CScanFilterHighPass::SetParameters()") );
00176 
00177    if ( Q_INVALID( NULL == lpParameters && "CScanFilterHighPass (SetParameters): parameters expected, none provided (NULL)." ) )
00178    {
00179       return FALSE;
00180    }
00181 
00182    /*
00183     * set defaults, read parameter string with factor and optional offset:
00184     */
00185    m_dCutOff = 0.0;
00186    m_dSoftEdge = 0.0;
00187 
00188    int nfields = _stscanf( lpParameters, _T( "%lf,%lf" ), &m_dCutOff, &m_dSoftEdge );
00189 
00190    if ( Q_INVALID( 2 > nfields && "CScanFilterHighPass (SetParameters): cutoff and softedge expected, got fewer." ) )
00191    {
00192       return FALSE;
00193    }
00194 
00195    if ( Q_INVALID( ( m_dCutOff < 0.0 || m_dCutOff > 10.0 ) && "CScanFilterHighPass: invalid cutoff value." ) )
00196    {
00197       return FALSE;
00198    }
00199 
00200    if ( Q_INVALID( ( m_dSoftEdge < 0.0 || m_dSoftEdge > 10.0 ) && "CScanFilterHighPass: invalid softedge value." ) )
00201    {
00202       return FALSE;
00203    }
00204 
00205    return TRUE;
00206 }
00207 
00208 /*
00209  * create filter dialog and prepare filter for Apply();
00210  * see also CScanFilterNull::RunModeless().
00211  */
00212 BOOL CScanFilterHighPass::RunModeless( CWnd* pParentWnd, CDocument* pDoc )
00213 {
00214 //   Q_LOG( _T("CScanFilterHighPass::RunModeless()") );
00215 
00216    CFilterDlg_HighPassPtr pDlg = new CFilterDlg_HighPass();
00217 
00218    if ( Q_INVALID( NULL == pDlg ) )
00219       return FALSE;
00220 
00221    pDlg->SetParameters( this, pDoc );   // (void) method
00222 
00223    /*
00224     * Create returns non-zero if dialog was created and initialized succesfully.
00225     * Note: no pDlg->DestroyWindow() must be done.
00226     */
00227    pDlg->Create( IDD_FILTERDLG_HIGHPASS, pParentWnd );
00228 
00229    m_pDlg = pDlg;
00230 
00231    /*
00232     * apply the filter now:
00233     */
00234    BOOL bRet = Apply();
00235 
00236    if ( bRet )
00237    {
00238       pDlg->UpdateView();
00239    }
00240 
00241    return bRet;
00242 }
00243 
00244 /*
00245  * check parameters, take care of a properly sized output buffer,
00246  * set its name and copy filter parameters and process;
00247  * see also CScanFilterNull::ApplyCore().
00248  */
00249 BOOL CScanFilterHighPass::Apply()
00250 {
00251 //   Q_LOG( _T("CScanFilterHighPass::Apply()") );
00252 
00253 //    /*
00254 //     * pre-apply must also be done from apply for scripting use:
00255 //     */
00256 //   if ( !PreApply() )
00257 //   {
00258 //      return FALSE;
00259 //   }
00260 
00261    if ( Q_INVALID( NULL == m_lpsbIn && "ensure input buffer") )
00262       return FALSE;
00263 
00264    if ( Q_INVALID( NULL == m_lpsbOut && "ensure output buffer" ) )
00265       return FALSE;
00266 
00267    if ( Q_INVALID( !m_lpsbIn->IsCompleteFrame() && "ensure complete frame" ) )
00268       return FALSE;
00269 
00270    /*
00271     * copy the filter settings (not the data):
00272     */
00273    Q_RETURN( m_lpsbOut->CreateOutputBufferFor( *m_lpsbIn ) );
00274 
00275    m_lpsbOut->m_csBufferName = m_lpsbIn->m_csBufferName + _T(" - ") + m_lpcsShortFilterName;
00276 
00277    if ( IsInteractive() )
00278    {
00279       m_pDlg->SetDlgItemText( IDC_BUFFEROUTNAME, m_lpsbOut->m_csBufferName  );
00280    }
00281 
00282    /*
00283     * create a new suspended thread to do the computation;
00284     * the progressdialog resumes the thread and displays the progress:
00285     */
00286    CProgressDlg dlg( IsInteractive() ? m_pDlg : AfxGetMainWnd() );
00287 
00288    ThreadArgs threadArgs( &dlg, this );
00289 
00290    CWinThread *hThread = AfxBeginThread(
00291       ComputationThreadFunction,        // the controlling function for the worker thread
00292       &threadArgs,                      // the arguments and return value
00293       THREAD_PRIORITY_BELOW_NORMAL,     // the priority
00294       0,                                // 0: the stack size defaults to the same size
00295                                         //    stack as the creating thread.
00296       CREATE_SUSPENDED,                 // create it in suspended state
00297       NULL                              // security attributes structure
00298    );
00299 
00300    /*
00301     * show progress dialog, try to start thread:
00302     */
00303    if ( dlg.DoModal( hThread ) <= 0 )
00304    {
00305       return FALSE;
00306    };
00307 
00308    /*
00309     * return thread result:
00310     */
00311    return threadArgs.bReturn;
00312 }
00313 
00314 /**
00315  * thread-function.
00316  */
00317 UINT CScanFilterHighPass::ComputationThreadFunction(LPVOID lpContext)
00318 {
00319 //   Q_LOG( _T("CScanFilterHighPass::ComputationThreadFunction()") );
00320 
00321    CScanFilterHighPass::ThreadArgs *lpTreadArgs = static_cast< CScanFilterHighPass::ThreadArgs* >( lpContext );
00322 
00323    lpTreadArgs->bReturn = lpTreadArgs->pThis->Compute( lpTreadArgs->pDlg );
00324 
00325    lpTreadArgs->pDlg->Terminate();
00326 
00327    return lpTreadArgs->bReturn;
00328 }
00329 
00330 /**
00331  * compute the desired result.
00332  */
00333 BOOL CScanFilterHighPass::Compute( CProgressDlg *pDlg )
00334 {
00335 //   Q_LOG( _T("CScanFilterLowPass::Compute()") );
00336 
00337    ASSERT( m_lpsbIn  );
00338    ASSERT( m_lpsbOut );
00339 
00340    /*
00341     * prepare some local varables:
00342     */
00343    BOOL bL2R = m_lpsbIn->HasLeftToRightScan();
00344    BOOL bR2L = m_lpsbIn->HasRightToLeftScan();
00345 
00346    /*
00347     * update progress dlg: don't touch dialog from other thread!
00348     */
00349    pDlg->SetText(_T("Computing 2D high-pass"));
00350    pDlg->SetRange( 0, bR2L && bL2R ? 4 : 3 );
00351 
00352    /*
00353     * check for FFT input to filter:
00354     */
00355    if ( bL2R && 0 == m_lpsbIn->m_pdFourierL2R ||
00356         bR2L && 0 == m_lpsbIn->m_pdFourierR2L   )
00357    {
00358       MessageBox(
00359          IsInteractive() ? m_pDlg->m_hWnd : AfxGetMainWnd()->m_hWnd,
00360          _T( "This scanbuffer does not contain a fourier spectrum." ),
00361          _T( "Cannot transform" ),
00362          MB_ICONEXCLAMATION | MB_OK
00363       );
00364 
00365       return FALSE;
00366    }
00367 
00368    /*
00369     * allocate fourier buffer:
00370     *
00371     * Note if we come this far, we know that the output buffer is created from
00372     * an input buffer that contains an FFT, so the output buffers size is already
00373     * appropriate for handling FFT.
00374     */
00375    Q_RETURN( m_lpsbOut->CreateFourierBuffer() );
00376 
00377    /*
00378     * keep track of progress:
00379     */
00380    int progress = 0;
00381 
00382    /*
00383     * perform the left-right and right-left transformations:
00384     */
00385    if ( bL2R )
00386    {
00387       ComputePart( m_lpsbIn->FourierDataL2R(), m_lpsbOut->FourierDataL2R() );
00388 
00389       pDlg->SetPos( ++progress );
00390    }
00391 
00392    if ( bR2L )
00393    {
00394       ComputePart( m_lpsbIn->FourierDataR2L(), m_lpsbOut->FourierDataR2L() );
00395 
00396       pDlg->SetPos( ++progress );
00397    }
00398 
00399    /*
00400     * compute amplitude response:
00401     */
00402    const int& nrow = m_lpsbOut->Rows();
00403    const int& ncol = m_lpsbOut->Columns();
00404 
00405    RealType *dAmpBuffer = new double[ nrow * ncol * 2 ];
00406 
00407    RealType dMax = CScanFilterFourierBase::BuildTmpAmpBuffer(
00408                     nrow, ncol, bL2R, bR2L, m_lpsbOut->FourierDataL2R(), m_lpsbOut->FourierDataR2L(), dAmpBuffer );
00409 
00410    pDlg->SetPos( ++progress );
00411 
00412    CScanFilterFourierBase::CopyAmpBufferToScanBuffer( nrow, ncol, bL2R, bR2L, dAmpBuffer, dMax );
00413 
00414    pDlg->SetPos( ++progress );
00415 
00416    delete dAmpBuffer;
00417 
00418    /*
00419     * check if a stop is requested from the progress dialog:
00420     */
00421    if ( pDlg->StopRequested() )
00422    {
00423       return FALSE;
00424    }
00425    else
00426    {
00427       return TRUE;
00428    }
00429 }
00430 
00431 /**
00432  * compute a frame.
00433  */
00434 void CScanFilterHighPass::ComputePart( FourierElementType** in, FourierElementType** out )
00435 {
00436    /*
00437     * get the image data properly into out:
00438     */
00439    SizeType nrow = m_lpsbOut->GetRowsForFFT();
00440    SizeType ncol = m_lpsbOut->GetColumnsForFFT();
00441 
00442    for ( SizeType y = 0; y < nrow / 2; ++y )
00443    {
00444       for ( SizeType x = 0; x < ncol / 2; ++x )
00445       {
00446          SizeType xi = 2 * x;
00447 
00448 //         double dDistance = sqrt( pow( 2.0 * x / ncol, 2.0 ) + pow( 2.0 * y / nrow, 2.0 ) );
00449 // 
00450 //          double    dScale = ( dDistance < ( m_dCutOff - m_dSoftEdge ) ? 0.0 :
00451 //                             ( dDistance > ( m_dCutOff + m_dSoftEdge ) ? 1.0 :
00452 //                                1.0 - 0.5 * ( 1.0 - sin( g_PI * ( dDistance - m_dCutOff ) / ( 2.0 * m_dSoftEdge ) ) ) ) );
00453 
00454          RealType dDistance = lpm::sqrt( lpm::sqr( 2.0 * x / ncol ) + lpm::sqr( 2.0 * y / nrow ) );
00455 
00456          RealType    dScale = ( dDistance < ( m_dCutOff - m_dSoftEdge ) ? 0.0 :
00457                               ( dDistance > ( m_dCutOff + m_dSoftEdge ) ? 1.0 :
00458                                  1.0 - 0.5 * ( 1.0 - lpm::sin( lpm::Pi * ( dDistance - m_dCutOff ) / ( 2.0 * m_dSoftEdge ) ) ) ) );
00459 
00460          out[       y    ][           xi    ] = dScale * in[       y    ][           xi    ];
00461          out[       y    ][           xi + 1] = dScale * in[       y    ][           xi + 1];
00462          out[nrow - y - 1][           xi    ] = dScale * in[nrow - y - 1][           xi    ];
00463          out[nrow - y - 1][           xi + 1] = dScale * in[nrow - y - 1][           xi + 1];
00464          out[       y    ][2 * ncol - xi - 2] = dScale * in[       y    ][2 * ncol - xi - 2];
00465          out[       y    ][2 * ncol - xi - 1] = dScale * in[       y    ][2 * ncol - xi - 1];
00466          out[nrow - y - 1][2 * ncol - xi - 2] = dScale * in[nrow - y - 1][2 * ncol - xi - 2];
00467          out[nrow - y - 1][2 * ncol - xi - 1] = dScale * in[nrow - y - 1][2 * ncol - xi - 1];
00468       }
00469    }
00470 }
00471 
00472 /*
00473  * end of file
00474  */
00475 

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