ImagePtr	dark(const ImageSequence& images, bool gridded = false) {
	debug(LOG_DEBUG, DEBUG_LOG, 0, "gridded: %s", (gridded) ? "YES" : "NO");
	if (!gridded) {
		return dark_plain<T>(images);
	}

	debug(LOG_DEBUG, DEBUG_LOG, 0, "gridded dark processing");
	ImageMean<T>	im(images, true);
	// perform the dark computation for each individual subgrid
	size_t	badpixels = 0;
	ImageSize	step(2, 2);
	badpixels += subdark<T>(images, im, Subgrid(ImagePoint(0, 0), step));
	badpixels += subdark<T>(images, im, Subgrid(ImagePoint(1, 0), step));
	badpixels += subdark<T>(images, im, Subgrid(ImagePoint(0, 1), step));
	badpixels += subdark<T>(images, im, Subgrid(ImagePoint(1, 1), step));
	debug(LOG_DEBUG, DEBUG_LOG, 0, "total bad pixels: %d", badpixels);
	ImagePtr	darkimg = im.getImagePtr();
	darkimg->setMetadata(FITSKeywords::meta("BADPIXEL", (long)badpixels));
	return darkimg;
}
ImagePtr	dark_plain(const ImageSequence& images) {
	debug(LOG_DEBUG, DEBUG_LOG, 0, "plain dark processing");
	ImageMean<T>	im(images, true);
	size_t	badpixels = subdark<T>(images, im, Subgrid());
	debug(LOG_DEBUG, DEBUG_LOG, 0, "total bad pixels: %d", badpixels);
	
	// that's it, we now have a dark image
	ImagePtr	darkimg = im.getImagePtr();
	darkimg->setMetadata(FITSKeywords::meta("BADPIXEL", (long)badpixels));
	return darkimg;
}
/**
 * \brief main function for the focus program
 */
int	main(int argc, char *argv[]) {
	int	c;
	double	exposuretime = 0.1;
	unsigned int	cameraid = 0;
	unsigned int	ccdid = 0;
	int	length = 512;
	std::string	cameratype("uvc");

	while (EOF != (c = getopt(argc, argv, "de:m:c:C:l:")))
		switch (c) {
		case 'd':
			debuglevel = LOG_DEBUG;
			break;
		case 'm':
			cameratype = std::string(optarg);
			break;
		case 'C':
			cameraid = atoi(optarg);
			break;
		case 'c':
			ccdid = atoi(optarg);
			break;
		case 'e':
			exposuretime = atof(optarg);
			break;
		case 'l':
			length = atoi(optarg);
			break;
		}

	// get the camera
	Repository	repository;
	debug(LOG_DEBUG, DEBUG_LOG, 0, "loading module %s",
		cameratype.c_str());
	ModulePtr	module = repository.getModule(cameratype);
	module->open();


	// get the camera
	DeviceLocatorPtr	locator = module->getDeviceLocator();
	std::vector<std::string>	cameras = locator->getDevicelist();
	if (0 == cameras.size()) {
		std::cerr << "no cameras found" << std::endl;
		return EXIT_FAILURE;
	}
	if (cameraid >= cameras.size()) {
		std::string	msg = stringprintf("camera %d out of range",
			cameraid);
		debug(LOG_ERR, DEBUG_LOG, 0, "%s\n", msg.c_str());
		throw std::range_error(msg);
	}
	std::string	cameraname = cameras[cameraid];
	CameraPtr	camera = locator->getCamera(cameraname);
	debug(LOG_DEBUG, DEBUG_LOG, 0, "camera loaded: %s", cameraname.c_str());

	// get the ccd
	CcdPtr	ccd = camera->getCcd(ccdid);
	debug(LOG_DEBUG, DEBUG_LOG, 0, "get a ccd: %s",
		ccd->getInfo().toString().c_str());

	// get a centerd length x length frame
	ImageSize	framesize(length, length);
	ImageRectangle	frame = ccd->getInfo().centeredRectangle(framesize);
	Exposure	exposure(frame, exposuretime);
	debug(LOG_DEBUG, DEBUG_LOG, 0, "exposure prepared: %s",
		exposure.toString().c_str());

	// retrieve an image
	ccd->startExposure(exposure);
	ImagePtr	image = ccd->getImage();

	// write image
	unlink("test.fits");
	FITSout	out("test.fits");
	out.write(image);

	// apply a mask to keep the border out
	CircleFunction	circle(ImagePoint(length/2, length/2), length/2, 0.8);
	mask(circle, image);
	unlink("masked.fits");
	FITSout	maskout("masked.fits");
	maskout.write(image);

#if 0
	// compute the FOM
	double	fom = focusFOM(image, true,
		Subgrid(ImagePoint(1, 0), ImageSize(1, 1)));
	std::cout << "FOM: " << fom << std::endl;
#endif


	return EXIT_SUCCESS;
}