Hi Wade and all,
This tool was planned for 1.6.1, but unfortunately I've had no time to finish it properly and the release of 1.6.1 is imminent, so it won't be available until 1.6.2 in September. Chances are that I'll finish it during August, but I'll only have access to a Linux development machine. Since it will be open-source however, anybody able to compile modules on Windows will be able to produce a Windows version. As soon as I have the source code available I'll post it here.
This tool (I still haven't decided the name) will perform just the same task that the frame adaptation routine does in StarAlignment. The algorithm is a robust linear fit. Instead of the usual linear regression, which is unreliable due to its poor resistance to outliers, I have implemented a clever algorithm based on minimizing absolute deviation. The algorithm is described for example on Numerical Recipes in C 2nd Ed., section 15.7 page 703. It is a simple, robust and elegant algorithm (although its mathematical foundation isn't trivial).
In case it may help somebody, here is an excerpt taken directly from StarAlignment's source code:
template <class T>
inline T SameSign( const T& a, const T& b )
{
return (b >= 0) ? (a >= 0 ? a : -a) : (a >= 0 ? -a : a);
}
class LinearFit
{
public:
double a, b; // y = a + b*x
double adev; // mean absolute deviation
LinearFit( const Array<float>& x, const Array<float>& y ) : a( 0 ), b( 0 ), adev( 0 )
{
size_type n = x.Length();
double sx = 0, sy = 0, sxy = 0, sxx = 0;
for ( size_type j = 0; j < n; ++j )
{
sx += x[j];
sy += y[j];
sxy += x[j]*y[j];
sxx += x[j]*x[j];
}
double del = n*sxx - sx*sx;
a = (sxx*sy - sx*sxy)/del;
b = (n*sxy - sx*sy)/del;
double chisq = 0;
for ( size_type j = 0; j < n; ++j )
{
double t = y[j] - (a + b*x[j]);
chisq += t*t;
}
double sigb = Sqrt( chisq/del );
if ( sigb > 0 )
{
double f1 = rofunc( b, x, y );
double b2 = b + SameSign( 3*sigb, f1 );
if ( b2 == b )
{
adev /= n;
return;
}
double f2 = rofunc( b2, x, y );
double b1 = b;
while ( f1*f2 > 0 )
{
b = b2 + 1.6*(b2 - b1);
b1 = b2;
f1 = f2;
b2 = b;
f2 = rofunc( b2, x, y );
}
sigb *= 0.01;
while ( Abs( b2 - b1 ) > sigb )
{
b = b1 + (b2 - b1)/2;
if ( b == b1 || b == b2 )
break;
double f = rofunc( b, x, y );
if ( f*f1 >= 0 )
{
f1 = f;
b1 = b;
}
else
{
f2 = f;
b2 = b;
}
}
}
adev /= n;
}
double rofunc( double b, const Array<float>& x, const Array<float>& y )
{
const double eps = 2.5e-16;
size_type n = x.Length();
{
Array<float> f( n );
for ( size_type j = 0; j < n; ++j )
f[j] = y[j] - b*x[j];
size_type n2 = n >> 1;
if ( n & 1 )
a = *pcl::Select( f.Begin(), f.End(), n2 );
else
{
f.Sort();
a = (f[n2] + f[n2-1])/2;
}
}
double sum = 0;
adev = 0;
for ( size_type j = 0; j < n; ++j )
{
double d = y[j] - (b*x[j] + a);
adev += Abs( d );
if ( y[j] != 0 )
d /= Abs( y[j] );
if ( Abs( d ) > eps )
sum += (d >= 0) ? x[j] : -x[j];
}
return sum;
}
};
This is an adaptation from Numerical Recipes. The LinearFit class fits a straight line y = a + b*x to two sets of numbers x and y passed as arrays. If you fill x and y with all the pixels from image A and image B, respectively, then you'll get a linear function that can be easily applied with PixelMath to match image B to image A in terms of mean background levels and signal strength. The code above is C++ but it can be easily implemented as JavaScript (it would be a bit slow but usable). Anyone?
Sorry for not being able to offer something more useful right now.