///////////////////////////////////////////////////////////////////////////
// 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