Esempio n. 1
1
/*!
 * 2D wavelet noise
 * @param[in] nx,ny 解像度
 */
void rxWaveletNoise::GenerateNoiseTile2(int n)
{
	// MARK:GenerateNoiseTile2
	if(g_pNoiseTileData != NULL && n == g_iNoiseTileSize) return;

	if(n%2) n++; // tile size must be even

	int sz = n*n;

	RXREAL *temp1 = new RXREAL[sz];
	RXREAL *temp2 = new RXREAL[sz];
	RXREAL *noise = new RXREAL[sz];

	// Step 1. Fill the tile with random numbers in the range -1 to 1.
	for(int i = 0; i < n*n; ++i){
		noise[i] = GaussianNoise();
		temp1[i] = temp2[i] = 0;
	}

	// Steps 2 and 3. Downsample and Upsample the tile
	for(int iy = 0; iy < n; ++iy){ // each x row
		int idx = iy*n;
		Downsample(&noise[idx], &temp1[idx], n, 1);
		Upsample(  &temp1[idx], &temp2[idx], n, 1);
	}

	for(int ix = 0; ix < n; ++ix){ // each y row
		int idx = ix; 
		Downsample(&temp2[idx], &temp1[idx], n, n);
		Upsample(  &temp1[idx], &temp2[idx], n, n);
	}

	// Step 4. Subtract out the coarse-scale contribution
	for(int i = 0; i < n*n; ++i){
		noise[i] -= temp2[i];
	}

	// Avoid even/odd variance difference by adding odd-offset version of noise to itself.
	int offset = n/2;
	if(offset%2 == 0) offset++;

	for(int i = 0, ix = 0; ix < n; ++ix){
		for(int iy = 0; iy < n; ++iy){
			temp1[i++] = noise[ModW(ix+offset, n)+ModW(iy+offset, n)*n];
		}
	}

	for(int i = 0; i < n*n; ++i){
		noise[i] += temp1[i];
	}

	g_pNoiseTileData = noise;
	g_iNoiseTileSize = n;

	delete [] temp1;
	delete [] temp2;
}
/// Downsampler::Measure
double Downsampler::Measure(class ImageLayout *src,class ImageLayout *dest,double in)
{
  src->TestIfCompatible(dest);

  Downsample(m_ppucSource,src);
  Downsample(m_ppucDestination,dest);

  return in;
}
Esempio n. 3
0
	static void DownsampleY(float* to, const float* from, int sx,int sy, int sz) {
		
		for (int ix = 0; ix < sx; ix++) 
			for (int iz = 0; iz < sz; iz++) {
				const int i = ix + iz*sx*sy;
				Downsample(&from[i], &to[i], sy, sx);
		}
	}
Esempio n. 4
0
	// some convenience functions for an nxn image
	static void DownsampleX(float* to, const float* from, int sx,int sy, int sz) {
		
		for (int iy = 0; iy < sy; iy++) 
			for (int iz = 0; iz < sz; iz++) {
				const int i = iy * sx + iz*sx*sy;
				Downsample(&from[i], &to[i], sx, 1);
			}
	}
Esempio n. 5
0
	static void DownsampleZ(float* to, const float* from, int sx,int sy, int sz) {
		
		for (int ix = 0; ix < sx; ix++) 
			for (int iy = 0; iy < sy; iy++) {
				const int i = ix + iy*sx;
				Downsample(&from[i], &to[i], sz, sx*sy);
		}
	}
Esempio n. 6
0
    void train(const TemplateList &data)
    {
        if (!transform || !transform->trainable)
            return;

        TemplateList downsampled = Downsample(data, classes, instances, fraction, inputVariable, gallery, subjects);

        transform->train(downsampled);
    }
Esempio n. 7
0
void* _Paint( void *ithr )
{
	CThrdat	&me = vthr[(long)ithr];

	for( int i = me.i0; i < me.ilim; ++i ) {

		vector<uint8>	msk;
		uint8*			src;
		TAffine			inv;
		uint32			w,  h;
		int				x0, xL, y0, yL,
						wL, hL,
						wi, hi;

		src = Raster8FromAny(
				GP->vTile[i].name.c_str(),
				w, h, GP->flog );

		if( GP->resmask )
			ResinMask8( msk, src, w, h, false );

		if( GP->sdnorm > 0 )
			NormRas( src, w, h, GP->lgord, GP->sdnorm );

		if( GP->resmask ) {

			int	n = w * h;

			for( int j = 0; j < n; ++j ) {
				if( !msk[j] )
					src[j] = GP->bkval;
			}
		}

		ScanLims( x0, xL, y0, yL,
			GP->ws, GP->hs, GP->vTile[i].t2g, w, h );
		wi = w;
		hi = h;

		inv.InverseOf( GP->vTile[i].t2g );

		if( GP->iscl > 1 ) {	// Scaling down

			// actually downsample src image
			Downsample( src, wi, hi, GP->iscl );

			// and point at the new pixels
			TAffine	A;
			A.NUSetScl( 1.0/GP->iscl );
			inv = A * inv;
		}

		wL = wi - 1;
		hL = hi - 1;

		for( int iy = y0; iy < yL; ++iy ) {

			for( int ix = x0; ix < xL; ++ix ) {

				Point	p( ix, iy );

				inv.Transform( p );

				if( p.x >= 0 && p.x < wL &&
					p.y >= 0 && p.y < hL ) {

					int	pix =
					(int)SafeInterp( p.x, p.y, src, wi, hi );

					if( pix != GP->bkval )
						GP->scp[ix+GP->ws*iy] = pix;
				}
			}
		}

		RasterFree( src );
	}

	return NULL;
}
bool PixPair::Load(
	const char	*apath,
	const char	*bpath,
	int			order,
	int			bDoG,
	int			r1,
	int			r2,
	FILE*		flog )
{
	printf( "\n---- Image loading ----\n" );

	clock_t		t0 = StartTiming();

/* ----------------------------- */
/* Load and sanity check rasters */
/* ----------------------------- */

	uint8	*aras, *bras;
	uint32	wa, ha, wb, hb;
	int		ok = false;

	aras = Raster8FromAny( apath, wa, ha, flog );
	bras = Raster8FromAny( bpath, wb, hb, flog );

	if( !aras || !bras ) {
		fprintf( flog,
		"PixPair: Picture load failure.\n" );
		goto exit;
	}

	if( wa != wb || ha != hb ) {
		fprintf( flog,
		"PixPair: Nonmatching picture dimensions.\n" );
		goto exit;
	}

	ok		= true;
	wf		= wa;
	hf		= ha;
	ws		= wa;
	hs		= ha;
	scl		= 1;

/* -------------- */
/* Resin removal? */
/* -------------- */

	//if( dbgCor ) {
	//	ZeroResin( "bloba.tif", aras );
	//	ZeroResin( "blobb.tif", bras );
	//}
	//else {
	//	ZeroResin( NULL, aras );
	//	ZeroResin( NULL, bras );
	//}

	//StopTiming( flog, "Resin removal", t0 );

/* ------- */
/* Flatten */
/* ------- */

	LegPolyFlatten( _avf, aras, wf, hf, order );
	RasterFree( aras );

	LegPolyFlatten( _bvf, bras, wf, hf, order );
	RasterFree( bras );

	avs_vfy	= avs_aln = avf_vfy	= avf_aln = &_avf;
	bvs_vfy	= bvs_aln = bvf_vfy	= bvf_aln = &_bvf;

/* ------------- */
/* Apply filters */
/* ------------- */

//{
//	vector<CD>	kfft;
//	double		K[] = {
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
//		Convolve( _avf, _avf, wf, hf, K, 11, 11, true, true, kfft );
//		Normalize( _avf );
//		Convolve( _bvf, _bvf, wf, hf, K, 11, 11, true, true, kfft );
//		Normalize( _bvf );
//}

#if 0
{
	vector<CD>	kfft;
	double		K[] = {
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
		Convolve( _avfflt, _avf, wf, hf, K, 11, 11, true, true, kfft );
		Normalize( _avfflt );
		Convolve( _bvfflt, _bvf, wf, hf, K, 11, 11, true, true, kfft );
		Normalize( _bvfflt );

		avs_aln = avf_aln = &_avfflt;
		bvs_aln = bvf_aln = &_bvfflt;

		bDoG = true;
}
#endif

	if( bDoG ) {

		vector<double>	DoG;
		vector<CD>		kfft;
		int				dim = MakeDoGKernel( DoG, r1, r2, flog );

		Convolve( _avfflt, _avf, wf, hf,
			&DoG[0], dim, dim, true, true, kfft );
		Normalize( _avfflt );

		Convolve( _bvfflt, _bvf, wf, hf,
			&DoG[0], dim, dim, true, true, kfft );
		Normalize( _bvfflt );

		avs_aln = avf_aln = &_avfflt;
		bvs_aln = bvf_aln = &_bvfflt;
	}

/* --------------------- */
/* Downsample all images */
/* --------------------- */

	if( ws > 2048 || hs >= 2048 ) {

		do {
			ws		/= 2;
			hs		/= 2;
			scl		*= 2;
		} while( ws > 2048 || hs > 2048 );

		fprintf( flog, "PixPair: Scaling by %d\n", scl );

		if( ws * scl != wf || hs * scl != hf ) {

			fprintf( flog,
			"PixPair: Dimensions not multiple of scale!\n" );
			goto exit;
		}

		Downsample( _avs, _avf );
		Downsample( _bvs, _bvf );

		avs_vfy = avs_aln = &_avs;
		bvs_vfy = bvs_aln = &_bvs;

		if( bDoG ) {

			if( _avfflt.size() ) {
				Downsample( _avsflt, _avfflt );
				avs_aln = &_avsflt;
			}

			if( _bvfflt.size() ) {
				Downsample( _bvsflt, _bvfflt );
				bvs_aln = &_bvsflt;
			}
		}
	}
	else
		fprintf( flog, "PixPair: Using image scale=1.\n" );

/* ------------------------------ */
/* Write DoG images for debugging */
/* ------------------------------ */

#if 0
	if( bDoG ) {
		VectorDblToTif8( "DoGa.tif", avs_aln, ws, hs );
		VectorDblToTif8( "DoGb.tif", bvs_aln, ws, hs );
	}
#endif

/* -------- */
/* Clean up */
/* -------- */

exit:
	if( aras )
		RasterFree( aras );

	if( bras )
		RasterFree( bras );

	StopTiming( flog, "Image conditioning", t0 );

	return ok;
}
Esempio n. 9
0
 bool SiftGPU::BuildGaussPyramid(IplImage* base)
 {
	float k;
	int intvlsSum = intvls + 3;
	float sig_total, sig_prev;

	printf("\n ----------- BuildGaussPyramid inside --------------- \n");

	imgArray = (IplImage**)calloc(octvs, sizeof(IplImage*));

	sigmaList[0] = SIFT_SIGMA;
	k = pow( 2.0, 1.0 / intvls );


	for(int i = 1; i < intvlsSum; i++ )
	{
		sig_prev = pow( k, i - 1 ) * SIFT_SIGMA;
		sig_total = sig_prev * k;
		sigmaList[i] = sqrt( sig_total * sig_total - sig_prev * sig_prev );
	}

	imgArray[0] = cvCloneImage(base);
	
	sizeOfImages[0] = imgArray[0]->imageSize;
	SizeOfPyramid += imgArray[0]->imageSize * intvlsSum;
	imageHeightInPyramid[0] = imgArray[0]->height;
	imageWidthInPyramid[0] = imgArray[0]->width;

	for(int o = 1; o < octvs; o++ )
	{
		imgArray[o] = Downsample( imgArray[o-1] );
		SizeOfPyramid += imgArray[o]->imageSize * intvlsSum;
		sizeOfImages[o] = imgArray[o]->imageSize;
		imageHeightInPyramid[o] = imgArray[o]->height;
		imageWidthInPyramid[o] = imgArray[o]->width;
	}


	gaussFilterGPU->CreateBufferForPyramid(SizeOfPyramid);
	subtractGPU->CreateBufferForPyramid(SizeOfPyramid);


	int offset = 0;

	offset = 0;
	int OffsetAct = 0;
	int OffsetPrev = 0;

	for(int o = 0; o < octvs; o++ )
	{
		for(int i = 0; i < intvlsSum; i++ )
		{

			if( o == 0  &&  i == 0 )
			{
				gaussFilterGPU->SendImageToPyramid(imgArray[o], OffsetAct);
			} else if(i == 0)
			{
				gaussFilterGPU->ReceiveImageFromPyramid(imgArray[o-1], OffsetPrev);
				imgArray[o] = Downsample( imgArray[o-1] );
				gaussFilterGPU->SendImageToPyramid(imgArray[o], OffsetAct);
			}

			if(i > 0 )
			{
				gaussFilterGPU->Process( sigmaList[i], imgArray[o]->width, imgArray[o]->height, OffsetPrev, OffsetAct);
				subtractGPU->Process(gaussFilterGPU->cmBufPyramid, imageWidthInPyramid[o], imageHeightInPyramid[o], OffsetPrev, OffsetAct);
			}
			OffsetPrev = OffsetAct;
			OffsetAct += sizeOfImages[o];
		}
	}



	//free( sigmaList );	
	return true;
}
Esempio n. 10
0
/*!
 * 3Dノイズタイル生成
 * @param[in] n タイルグリッド数
 */
RXREAL* rxWaveletNoise::GenerateNoiseTile4r(int &n, int &nt)
{
	if(n%2) n++; // tile size must be even

	long sz = n*n*n*nt;
	RXREAL *temp1 = new RXREAL[sz];
	RXREAL *temp2 = new RXREAL[sz];
	RXREAL *noise = new RXREAL[sz];

	// Step 1. Fill the tile with random numbers in the range -1 to 1.
	for(int i = 0; i < sz; ++i){
		noise[i] = GaussianNoise();
	}

	// Steps 2 and 3. Downsample and Upsample the tile
	for(int iy = 0; iy < n; ++iy){
		for(int iz = 0; iz < n; ++iz){
			for(int it = 0; it < nt; ++it){
				// each x row
				long idx = iy*n+iz*n*n+it*n*n*n;
				Downsample(&noise[idx], &temp1[idx], n, 1);
				Upsample(  &temp1[idx], &temp2[idx], n, 1);
			}
		}
	}

	for(int ix = 0; ix < n; ++ix){
		for(int iz = 0; iz < n; ++iz){
			for(int it = 0; it < nt; ++it){
				// each y row
				long idx = ix+iz*n*n+it*n*n*n;
				Downsample(&temp2[idx], &temp1[idx], n, n);
				Upsample(  &temp1[idx], &temp2[idx], n, n);
			}
		}
	}

	for(int ix = 0; ix < n; ++ix){
		for(int iy = 0; iy < n; ++iy){
			for(int it = 0; it < nt; ++it){
				// each z row
				long idx = ix+iy*n+it*n*n*n;
				Downsample(&temp2[idx], &temp1[idx], n, n*n);
				Upsample(  &temp1[idx], &temp2[idx], n, n*n);
			}
		}
	}

	for(int ix = 0; ix < n; ++ix){
		for(int iy = 0; iy < n; ++iy){
			for(int iz = 0; iz < n; ++iz){
				// each t row
				long idx = ix+iy*n+iz*n*n;
				Downsample(&temp2[idx], &temp1[idx], nt, n*n*n);
				Upsample(  &temp1[idx], &temp2[idx], nt, n*n*n);
			}
		}
	}

	// Step 4. Subtract out the coarse-scale contribution
	for(int i = 0; i < sz; ++i){
		noise[i] -= temp2[i];
	}

	// Avoid even/odd variance difference by adding odd-offset version of noise to itself.
	int offset = n/2;
	if(offset%2 == 0) offset++;

	for(int i = 0, ix = 0; ix < n; ++ix){
		for(int iy = 0; iy < n; ++iy){
			for(int iz = 0; iz < n; ++iz){
				for(int it = 0; it < nt; ++it){
					temp1[i++] = noise[ModW(ix+offset, n)+ModW(iy+offset, n)*n+ModW(iz+offset, n)*n*n+ModW(it+offset, nt)*n*n*n];
				}
			}
		}
	}

	for(int i = 0; i < sz; ++i){
		noise[i] += temp1[i];
	}

	delete [] temp1;
	delete [] temp2;

	return noise;
}
Esempio n. 11
0
/*!
 * 
 * @param[in] 
 * @return 
 */
RXREAL* rxWaveletNoise::GenerateNoiseTile3r(int &nx, int &ny, int &nz)
{
	if(nx%2) nx++; // tile size must be even
	if(ny%2) ny++; // tile size must be even
	if(nz%2) nz++; // tile size must be even

	int sz = nx*ny*nz;
	RXREAL *temp1 = new RXREAL[sz];
	RXREAL *temp2 = new RXREAL[sz];
	RXREAL *noise = new RXREAL[sz];

	init_genrand((unsigned)time(NULL));
	//init_genrand(1234);

	// Step 1. Fill the tile with random numbers in the range -1 to 1.
	for(int i = 0; i < sz; ++i){
		noise[i] = GaussianNoise();
	}

	// Steps 2 and 3. Downsample and Upsample the tile
	for(int iy = 0; iy < ny; ++iy){
		for(int iz = 0; iz < nz; ++iz){
			// each x row
			int idx = iy*nx+iz*nx*ny;
			Downsample(&noise[idx], &temp1[idx], nx, 1);
			Upsample(  &temp1[idx], &temp2[idx], nx, 1);
		}
	}

	for(int ix = 0; ix < nx; ++ix){
		for(int iz = 0; iz < nz; ++iz){
			// each y row
			int idx = ix+iz*nx*ny;
			Downsample(&temp2[idx], &temp1[idx], ny, nx);
			Upsample(  &temp1[idx], &temp2[idx], ny, nx);
		}
	}

	for(int ix = 0; ix < nx; ++ix){
		for(int iy = 0; iy < ny; ++iy){
			// each z row
			int idx = ix+iy*nx;
			Downsample(&temp2[idx], &temp1[idx], nz, nx*ny);
			Upsample(  &temp1[idx], &temp2[idx], nz, nx*ny);
		}
	}

	// Step 4. Subtract out the coarse-scale contribution
	for(int i = 0; i < sz; ++i){
		noise[i] -= temp2[i];
	}

	// Avoid even/odd variance difference by adding odd-offset version of noise to itself.
	int offset = nx/2;
	if(offset%2 == 0) offset++;

	for(int i = 0, ix = 0; ix < nx; ++ix){
		for(int iy = 0; iy < ny; ++iy){
			for(int iz = 0; iz < nz; ++iz){
				temp1[i++] = noise[ModW(ix+offset, nx)+ModW(iy+offset, ny)*nx+ModW(iz+offset, nz)*nx*ny];
			}
		}
	}

	for(int i = 0; i < sz; ++i){
		noise[i] += temp1[i];
	}

	delete [] temp1;
	delete [] temp2;

	return noise;
}
Esempio n. 12
0
bool Star::AutoFind(const usImage& image, int extraEdgeAllowance, int searchRegion)
{
    if (!image.Subframe.IsEmpty())
    {
        Debug.AddLine("Autofind called on subframe, returning error");
        return false; // not found
    }

    wxBusyCursor busy;

    Debug.AddLine(wxString::Format("Star::AutoFind called with edgeAllowance = %d searchRegion = %d", extraEdgeAllowance, searchRegion));

    // run a 3x3 median first to eliminate hot pixels
    usImage smoothed;
    smoothed.CopyFrom(image);
    Median3(smoothed);

    // convert to floating point
    FloatImg conv(smoothed);

    // downsample the source image
    const int downsample = 1;
    if (downsample > 1)
    {
        FloatImg tmp;
        Downsample(tmp, conv, downsample);
        conv.Swap(tmp);
    }

    // run the PSF convolution
    {
        FloatImg tmp;
        psf_conv(tmp, conv);
        conv.Swap(tmp);
    }

    enum { CONV_RADIUS = 4 };
    int dw = conv.Size.GetWidth();      // width of the downsampled image
    int dh = conv.Size.GetHeight();     // height of the downsampled image
    wxRect convRect(CONV_RADIUS, CONV_RADIUS, dw - 2 * CONV_RADIUS, dh - 2 * CONV_RADIUS);  // region containing valid data

    SaveImage(conv, "PHD2_AutoFind.fit");

    enum { TOP_N = 100 };  // keep track of the brightest stars
    std::set<Peak> stars;  // sorted by ascending intensity

    double global_mean, global_stdev;
    GetStats(&global_mean, &global_stdev, conv, convRect);

    Debug.AddLine("AutoFind: global mean = %.1f, stdev %.1f", global_mean, global_stdev);

    const double threshold = 0.1;
    Debug.AddLine("AutoFind: using threshold = %.1f", threshold);

    // find each local maximum
    int srch = 4;
    for (int y = convRect.GetTop() + srch; y <= convRect.GetBottom() - srch; y++)
    {
        for (int x = convRect.GetLeft() + srch; x <= convRect.GetRight() - srch; x++)
        {
            float val = conv.px[dw * y + x];
            bool ismax = false;
            if (val > 0.0)
            {
                ismax = true;
                for (int j = -srch; j <= srch; j++)
                {
                    for (int i = -srch; i <= srch; i++)
                    {
                        if (i == 0 && j == 0)
                            continue;
                        if (conv.px[dw * (y + j) + (x + i)] > val)
                        {
                            ismax = false;
                            break;
                        }
                    }
                }
            }
            if (!ismax)
                continue;

            // compare local maximum to mean value of surrounding pixels
            const int local = 7;
            double local_mean, local_stdev;
            wxRect localRect(x - local, y - local, 2 * local + 1, 2 * local + 1);
            localRect.Intersect(convRect);
            GetStats(&local_mean, &local_stdev, conv, localRect);

            // this is our measure of star intensity
            double h = (val - local_mean) / global_stdev;

            if (h < threshold)
            {
                //  Debug.AddLine(wxString::Format("AG: local max REJECT [%d, %d] PSF %.1f SNR %.1f", imgx, imgy, val, SNR));
                continue;
            }

            // coordinates on the original image
            int imgx = x * downsample + downsample / 2;
            int imgy = y * downsample + downsample / 2;

            stars.insert(Peak(imgx, imgy, h));
            if (stars.size() > TOP_N)
                stars.erase(stars.begin());
        }
    }

    for (std::set<Peak>::const_reverse_iterator it = stars.rbegin(); it != stars.rend(); ++it)
        Debug.AddLine("AutoFind: local max [%d, %d] %.1f", it->x, it->y, it->val);

    // merge stars that are very close into a single star
    {
        const int minlimitsq = 5 * 5;
    repeat:
        for (std::set<Peak>::const_iterator a = stars.begin(); a != stars.end(); ++a)
        {
            std::set<Peak>::const_iterator b = a;
            ++b;
            for (; b != stars.end(); ++b)
            {
                int dx = a->x - b->x;
                int dy = a->y - b->y;
                int d2 = dx * dx + dy * dy;
                if (d2 < minlimitsq)
                {
                    // very close, treat as single star
                    Debug.AddLine("AutoFind: merge [%d, %d] %.1f - [%d, %d] %.1f", a->x, a->y, a->val, b->x, b->y, b->val);
                    // erase the dimmer one
                    stars.erase(a);
                    goto repeat;
                }
            }
        }
    }

    // exclude stars that would fit within a single searchRegion box
    {
        // build a list of stars to be excluded
        std::set<int> to_erase;
        const int extra = 5; // extra safety margin
        const int fullw = searchRegion + extra;
        for (std::set<Peak>::const_iterator a = stars.begin(); a != stars.end(); ++a)
        {
            std::set<Peak>::const_iterator b = a;
            ++b;
            for (; b != stars.end(); ++b)
            {
                int dx = abs(a->x - b->x);
                int dy = abs(a->y - b->y);
                if (dx <= fullw && dy <= fullw)
                {
                    // stars closer than search region, exclude them both
                    // but do not let a very dim star eliminate a very bright star
                    if (b->val / a->val >= 5.0)
                    {
                        Debug.AddLine("AutoFind: close dim-bright [%d, %d] %.1f - [%d, %d] %.1f", a->x, a->y, a->val, b->x, b->y, b->val);
                    }
                    else
                    {
                        Debug.AddLine("AutoFind: too close [%d, %d] %.1f - [%d, %d] %.1f", a->x, a->y, a->val, b->x, b->y, b->val);
                        to_erase.insert(std::distance(stars.begin(), a));
                        to_erase.insert(std::distance(stars.begin(), b));
                    }
                }
            }
        }
        RemoveItems(stars, to_erase);
    }

    // exclude stars too close to the edge
    {
        enum { MIN_EDGE_DIST = 40 };
        int edgeDist = MIN_EDGE_DIST + extraEdgeAllowance;

        std::set<Peak>::iterator it = stars.begin();
        while (it != stars.end())
        {
            std::set<Peak>::iterator next = it;
            ++next;
            if (it->x <= edgeDist || it->x >= image.Size.GetWidth() - edgeDist ||
                it->y <= edgeDist || it->y >= image.Size.GetHeight() - edgeDist)
            {
                Debug.AddLine("AutoFind: too close to edge [%d, %d] %.1f", it->x, it->y, it->val);
                stars.erase(it);
            }
            it = next;
        }
    }

    // At first I tried running Star::Find on the survivors to find the best
    // star. This had the unfortunate effect of locating hot pixels which
    // the psf convolution so nicely avoids. So, don't do that!  -ag

    // find the brightest non-saturated star. If no non-saturated stars, settle for a saturated star.
    bool allowSaturated = false;
    while (true)
    {
        Debug.AddLine("AutoSelect: finding best star allowSaturated = %d", allowSaturated);

        for (std::set<Peak>::reverse_iterator it = stars.rbegin(); it != stars.rend(); ++it)
        {
            Star tmp;
            tmp.Find(&image, searchRegion, it->x, it->y, FIND_CENTROID);
            if (tmp.WasFound())
            {
                if (tmp.GetError() == STAR_SATURATED && !allowSaturated)
                {
                    Debug.AddLine("Autofind: star saturated [%d, %d] %.1f Mass %.f SNR %.1f", it->x, it->y, it->val, tmp.Mass, tmp.SNR);
                    continue;
                }
                SetXY(it->x, it->y);
                Debug.AddLine("Autofind returns star at [%d, %d] %.1f Mass %.f SNR %.1f", it->x, it->y, it->val, tmp.Mass, tmp.SNR);
                return true;
            }
        }

        if (allowSaturated)
            break; // no stars found

        Debug.AddLine("AutoFind: could not find a non-saturated star!");

        allowSaturated = true;
    }

    Debug.AddLine("Autofind: no star found");
    return false;
}
Esempio n. 13
0
bool Star::AutoFind(const usImage& image, int extraEdgeAllowance, int searchRegion)
{
    if (!image.Subframe.IsEmpty())
    {
        Debug.AddLine("Autofind called on subframe, returning error");
        return false; // not found
    }

    wxBusyCursor busy;

    Debug.Write(wxString::Format("Star::AutoFind called with edgeAllowance = %d searchRegion = %d\n", extraEdgeAllowance, searchRegion));

    // run a 3x3 median first to eliminate hot pixels
    usImage smoothed;
    smoothed.CopyFrom(image);
    Median3(smoothed);

    // convert to floating point
    FloatImg conv(smoothed);

    // downsample the source image
    const int downsample = 1;
    if (downsample > 1)
    {
        FloatImg tmp;
        Downsample(tmp, conv, downsample);
        conv.Swap(tmp);
    }

    // run the PSF convolution
    {
        FloatImg tmp;
        psf_conv(tmp, conv);
        conv.Swap(tmp);
    }

    enum { CONV_RADIUS = 4 };
    int dw = conv.Size.GetWidth();      // width of the downsampled image
    int dh = conv.Size.GetHeight();     // height of the downsampled image
    wxRect convRect(CONV_RADIUS, CONV_RADIUS, dw - 2 * CONV_RADIUS, dh - 2 * CONV_RADIUS);  // region containing valid data

    SaveImage(conv, "PHD2_AutoFind.fit");

    enum { TOP_N = 100 };  // keep track of the brightest stars
    std::set<Peak> stars;  // sorted by ascending intensity

    double global_mean, global_stdev;
    GetStats(&global_mean, &global_stdev, conv, convRect);

    Debug.Write(wxString::Format("AutoFind: global mean = %.1f, stdev %.1f\n", global_mean, global_stdev));

    const double threshold = 0.1;
    Debug.Write(wxString::Format("AutoFind: using threshold = %.1f\n", threshold));

    // find each local maximum
    int srch = 4;
    for (int y = convRect.GetTop() + srch; y <= convRect.GetBottom() - srch; y++)
    {
        for (int x = convRect.GetLeft() + srch; x <= convRect.GetRight() - srch; x++)
        {
            float val = conv.px[dw * y + x];
            bool ismax = false;
            if (val > 0.0)
            {
                ismax = true;
                for (int j = -srch; j <= srch; j++)
                {
                    for (int i = -srch; i <= srch; i++)
                    {
                        if (i == 0 && j == 0)
                            continue;
                        if (conv.px[dw * (y + j) + (x + i)] > val)
                        {
                            ismax = false;
                            break;
                        }
                    }
                }
            }
            if (!ismax)
                continue;

            // compare local maximum to mean value of surrounding pixels
            const int local = 7;
            double local_mean, local_stdev;
            wxRect localRect(x - local, y - local, 2 * local + 1, 2 * local + 1);
            localRect.Intersect(convRect);
            GetStats(&local_mean, &local_stdev, conv, localRect);

            // this is our measure of star intensity
            double h = (val - local_mean) / global_stdev;

            if (h < threshold)
            {
                //  Debug.Write(wxString::Format("AG: local max REJECT [%d, %d] PSF %.1f SNR %.1f\n", imgx, imgy, val, SNR));
                continue;
            }

            // coordinates on the original image
            int imgx = x * downsample + downsample / 2;
            int imgy = y * downsample + downsample / 2;

            stars.insert(Peak(imgx, imgy, h));
            if (stars.size() > TOP_N)
                stars.erase(stars.begin());
        }
    }

    for (std::set<Peak>::const_reverse_iterator it = stars.rbegin(); it != stars.rend(); ++it)
        Debug.Write(wxString::Format("AutoFind: local max [%d, %d] %.1f\n", it->x, it->y, it->val));

    // merge stars that are very close into a single star
    {
        const int minlimitsq = 5 * 5;
    repeat:
        for (std::set<Peak>::const_iterator a = stars.begin(); a != stars.end(); ++a)
        {
            std::set<Peak>::const_iterator b = a;
            ++b;
            for (; b != stars.end(); ++b)
            {
                int dx = a->x - b->x;
                int dy = a->y - b->y;
                int d2 = dx * dx + dy * dy;
                if (d2 < minlimitsq)
                {
                    // very close, treat as single star
                    Debug.Write(wxString::Format("AutoFind: merge [%d, %d] %.1f - [%d, %d] %.1f\n", a->x, a->y, a->val, b->x, b->y, b->val));
                    // erase the dimmer one
                    stars.erase(a);
                    goto repeat;
                }
            }
        }
    }

    // exclude stars that would fit within a single searchRegion box
    {
        // build a list of stars to be excluded
        std::set<int> to_erase;
        const int extra = 5; // extra safety margin
        const int fullw = searchRegion + extra;
        for (std::set<Peak>::const_iterator a = stars.begin(); a != stars.end(); ++a)
        {
            std::set<Peak>::const_iterator b = a;
            ++b;
            for (; b != stars.end(); ++b)
            {
                int dx = abs(a->x - b->x);
                int dy = abs(a->y - b->y);
                if (dx <= fullw && dy <= fullw)
                {
                    // stars closer than search region, exclude them both
                    // but do not let a very dim star eliminate a very bright star
                    if (b->val / a->val >= 5.0)
                    {
                        Debug.Write(wxString::Format("AutoFind: close dim-bright [%d, %d] %.1f - [%d, %d] %.1f\n", a->x, a->y, a->val, b->x, b->y, b->val));
                    }
                    else
                    {
                        Debug.Write(wxString::Format("AutoFind: too close [%d, %d] %.1f - [%d, %d] %.1f\n", a->x, a->y, a->val, b->x, b->y, b->val));
                        to_erase.insert(std::distance(stars.begin(), a));
                        to_erase.insert(std::distance(stars.begin(), b));
                    }
                }
            }
        }
        RemoveItems(stars, to_erase);
    }

    // exclude stars too close to the edge
    {
        enum { MIN_EDGE_DIST = 40 };
        int edgeDist = MIN_EDGE_DIST + extraEdgeAllowance;

        std::set<Peak>::iterator it = stars.begin();
        while (it != stars.end())
        {
            std::set<Peak>::iterator next = it;
            ++next;
            if (it->x <= edgeDist || it->x >= image.Size.GetWidth() - edgeDist ||
                it->y <= edgeDist || it->y >= image.Size.GetHeight() - edgeDist)
            {
                Debug.Write(wxString::Format("AutoFind: too close to edge [%d, %d] %.1f\n", it->x, it->y, it->val));
                stars.erase(it);
            }
            it = next;
        }
    }

    // At first I tried running Star::Find on the survivors to find the best
    // star. This had the unfortunate effect of locating hot pixels which
    // the psf convolution so nicely avoids. So, don't do that!  -ag

    // try to identify the saturation point

    //  first, find the peak pixel overall
    unsigned short maxVal = 0;
    for (unsigned int i = 0; i < image.NPixels; i++)
        if (image.ImageData[i] > maxVal)
            maxVal = image.ImageData[i];

    // next see if any of the stars has a flat-top
    bool foundSaturated = false;
    for (std::set<Peak>::reverse_iterator it = stars.rbegin(); it != stars.rend(); ++it)
    {
        Star tmp;
        tmp.Find(&image, searchRegion, it->x, it->y, FIND_CENTROID);
        if (tmp.WasFound() && tmp.GetError() == STAR_SATURATED)
        {
            if ((maxVal - tmp.PeakVal) * 255U > maxVal)
            {
                // false positive saturation, flat top but below maxVal
                Debug.Write(wxString::Format("AutoSelect: false positive saturation peak = %hu, max = %hu\n", tmp.PeakVal, maxVal));
            }
            else
            {
                // a saturated star was found
                foundSaturated = true;
                break;
            }
        }
    }

    unsigned int sat_level; // saturation level, including pedestal
    if (foundSaturated)
    {
        // use the peak overall pixel value as the saturation limit
        Debug.Write(wxString::Format("AutoSelect: using saturation level peakVal = %hu\n", maxVal));
        sat_level = maxVal; // includes pedestal
    }
    else
    {
        // no staurated stars found, can't make any assumption about whether the max val is saturated

        Debug.Write(wxString::Format("AutoSelect: using saturation level from BPP %u and pedestal %hu\n",
            image.BitsPerPixel, image.Pedestal));

        sat_level = ((1U << image.BitsPerPixel) - 1) + image.Pedestal;
        if (sat_level > 65535)
            sat_level = 65535;
    }
    unsigned int diff = sat_level > image.Pedestal ? sat_level - image.Pedestal : 0U;
    // "near-saturation" threshold at 90% saturation
    unsigned short sat_thresh = (unsigned short)((unsigned int) image.Pedestal + 9 * diff / 10);

    Debug.Write(wxString::Format("AutoSelect: BPP = %u, saturation at %u, pedestal %hu, thresh = %hu\n",
        image.BitsPerPixel, sat_level, image.Pedestal, sat_thresh));

    // Final star selection
    //   pass 1: find brightest star with peak value < 90% saturation AND SNR > 6
    //       this pass will reject saturated and nearly-saturated stars
    //   pass 2: find brightest non-saturated star
    //   pass 3: find brightest star, even if saturated

    for (int pass = 1; pass <= 3; pass++)
    {
        Debug.Write(wxString::Format("AutoSelect: finding best star pass %d\n", pass));

        for (std::set<Peak>::reverse_iterator it = stars.rbegin(); it != stars.rend(); ++it)
        {
            Star tmp;
            tmp.Find(&image, searchRegion, it->x, it->y, FIND_CENTROID);
            if (tmp.WasFound())
            {
                if (pass == 1)
                {
                    if (tmp.PeakVal > sat_thresh)
                    {
                        Debug.Write(wxString::Format("Autofind: near-saturated [%d, %d] %.1f Mass %.f SNR %.1f Peak %hu\n", it->x, it->y, it->val, tmp.Mass, tmp.SNR, tmp.PeakVal));
                        continue;
                    }
                    if (tmp.GetError() == STAR_SATURATED || tmp.SNR < 6.0)
                        continue;
                }
                else if (pass == 2)
                {
                    if (tmp.GetError() == STAR_SATURATED)
                    {
                        Debug.Write(wxString::Format("Autofind: star saturated [%d, %d] %.1f Mass %.f SNR %.1f\n", it->x, it->y, it->val, tmp.Mass, tmp.SNR));
                        continue;
                    }
                }

                // star accepted
                SetXY(it->x, it->y);
                Debug.Write(wxString::Format("Autofind returns star at [%d, %d] %.1f Mass %.f SNR %.1f\n", it->x, it->y, it->val, tmp.Mass, tmp.SNR));
                return true;
            }
        }

        if (pass == 1)
            Debug.Write("AutoFind: could not find a star on Pass 1\n");
        else if (pass == 2)
            Debug.Write("AutoFind: could not find a non-saturated star!\n");
    }

    Debug.Write("Autofind: no star found\n");
    return false;
}