Listing 4: ImagePointLut member functions

///////////////////////////////////////////////////////////////////////////
//    File: iplut.cpp
//    Description: ImagePointLut - point lookup table routines 
//
//    Author: C Dare-Edwards
//      Copyright Conrad Dare-Edwards 1997

#include "stdafx.h"
#include "isystem.hpp"
#include "iplut.hpp"

// histogram equalisation 
void
ImagePointLut::Equalise( const ImageHist& hist )
{
    double divider = hist.getSum() / 255.0;
    double total=0;
    
    // equalise and produce a table 
        for(int i=0; i < 256; i++ )
        {
        total += (double)hist.getFrequency(i) * (double)i;
        (*this)[i] = (int)(total /divider) ;
            }

    // build points from the table produced
    BuildPointList();
}

// optimise a min max stretch by adding a mean 
// value and clipping the top and bottom 5 percent 
void 
ImagePointLut::Optimise( const ImageHist& hist,colour type )
{
    // defualt min to max    
    SetMinToMax( hist, type );    
       
    // if a green pseudo colour lookup table
    // mean value is at the top of the range 
    if( type == GREEN )
    {
        // find central point or the first to 
        // equal 255 on the y axis  and move x to mean 
        ILISTPOS pos = NULL;
        while(  ( pos = m_PointList.getNext( pos )) != NULL )
        {
            if( (m_PointList.getData(pos)).y == 255 )
            {
               (m_PointList.getData(pos)).x =(int)hist.getMean();
                break;
            }
        }
    }        
    else // red or blue lookup table
    {
            // add a new central mean
        m_PointList.Append( 
              ImagePoint( (int)hist.getMean(),getRange() / 2 ) );                                 
    }
    
    Update();    // and resort list
}

// Update - sort tidy and recompute lookup table
void
ImagePointLut::Update( BOOL tidy )
{
    // make sure that the m_PointList is ok
    SortPointList();
    
    // remove un needed points if requestedi
    if( tidy)  TidyPointList();    

    // catch problems 
    if( !m_PointList.isEmpty() )
    {
        // compute lookup table 
        // scan through list and hand across to ScaleTo
        ILISTPOS pos  = m_PointList.getHead(); 
        ILISTPOS last = pos;    
        while(  ( pos = m_PointList.getNext( pos )) != NULL)
        {
            ImageLut::ScaleTo( m_PointList.getData( last ), 
                    m_PointList.getData( pos ));
            last = pos; // save pos for next round        
        }
    }
}

// SortPointList
void
ImagePointLut::SortPointList( void )
{
    // set to 0 if we dont need a 0,0 point
    int zeropoint =1;  

    // set to 0 if we dont need a 255,255 point
    int maxpoint  =1;  

    // scan through all points and invert them on each y axis
    if( !m_PointList.isEmpty() )
    {
        ILISTPOS pos = NULL;
        while(  ( pos = m_PointList.getNext( pos )) != NULL )
        {
                // test for end points
            if( m_PointList.getData( pos ).x ==  0 )
            {
                zeropoint = 0;       
            }
            else if( m_PointList.getData( pos ).x ==255) 
            {    
                maxpoint = 0;
            }
        }    
    }
    // insert top and bottom as needed
    if( maxpoint )
    {
        m_PointList.Append( ImagePoint( 255,255 ) ); 
    }
    
    if( zeropoint )
    {
        m_PointList.InsertBefore( 
            ImagePoint(0,0), m_PointList.getHead() );
    }
    

    // and a very simple sort routine    
    int changes;  // do untill list hasn't changed 
    do
    {
        // no changes yet
        changes = FALSE;
        
        // skip the first node
        ILISTPOS pos = m_PointList.getHead();  

        while(  ( pos = m_PointList.getNext( pos )) != NULL )
        {
            ILISTPOS last = m_PointList.getPrev( pos ); 

            // if this point is greater swap them
            if(  m_PointList.getData(  last  ).x  > 
                    m_PointList.getData(  pos ).x )
            {
                ImagePoint hold( m_PointList.getData(last));
                m_PointList.getData(  last  ) = 
                            m_PointList.getData(  pos );
                m_PointList.getData(  pos ) = hold;
                changes = TRUE;
            }// end if greater
        } // end while in list
    
    }while( changes );
}

// TidyPointList - delete any unnessary points from the list
void 
ImagePointLut::TidyPointList( )
{
     // can't run unless there are 3 or more points
    if( m_PointList.getLength() < 3 ) return;  

    // second point in list
    ILISTPOS pos  =m_PointList.getNext( m_PointList.getHead()); 
    ILISTPOS next;
    while(  ( next = m_PointList.getNext( pos )) != NULL )
    {
        ILISTPOS last = m_PointList.getPrev( pos );
    
        // work out wheather pos is on the 
        // line between last and next
        // (pos.x-last.x)*(next.y-last.y) - 
        // (pos.y-last.y)*(next.x-last.x)      
        int offLine =
            ((m_PointList.getData(pos).x - 
                    m_PointList.getData(last).x)*
             (m_PointList.getData(next).y - 
                    m_PointList.getData(last).y))
          - ((m_PointList.getData(pos).y - 
                    m_PointList.getData(last).y)*
             (m_PointList.getData(next).x - 
                    m_PointList.getData(last).x));

        // if  on line between last and next its not needed 
        if(  abs(offLine) <= 1  ) m_PointList.Remove( pos );
        else 
        {
            if( m_PointList.getData(pos).x > 255 || 
                m_PointList.getData(pos).x < 0   ||
                m_PointList.getData(pos).y > 255 ||
                m_PointList.getData(pos).y < 0 )
                m_PointList.Remove( pos );
        }
        pos = next; // and go around again 
    }
}

// create a point list from ImageLut 
void 
ImagePointLut::BuildPointList( )
{
    m_PointList.RemoveAll();    // start fresh
    ImageLut* lut = (ImageLut*)this;    

    // always have the first point
    m_PointList.Append( ImagePoint( 0, (*lut)[0]) );

    int last = 0;
    for ( int pos = 1; pos< 255; pos++ )
    { 
        int next = pos + 1;
    
        // work out wheather pos is on 
        // the line between last and next
        int offLine =(( pos - last)*
                     ((*lut)[next] - (*lut)[last]))-
                     (((*lut)[pos] -(*lut)[last])*
                       (next - last));

        int ydist = abs(((*lut)[pos]) - ((*lut)[last]));
        int xdist = pos - last;
        int distance = (ydist * ydist) + (xdist * xdist);
        
        // if distinct from other points add it to the list 
        if(  !(abs(offLine) <= 1) && distance >= 16)
        {
            // add this new point to the list
            m_PointList.Append( ImagePoint( pos,(*lut)[pos]));
            last = pos;    // shift last across to x 
        } 
    }

    // always have the end point
    m_PointList.Append( ImagePoint( 255, (*lut)[255]) );
}
//End of File