int main(int argc, char **argv) {
	// InitVars is part of base. We need because of the vars in dp_payoffs.cpp
	InitVars(argc, argv);

	// Declare the supported options.
	po::options_description desc("Allowed options");
	desc.add_options()
    ("help", "produce help message")
		("features", po::value<string>()->required(), "file containing payoff features")
		("weights", po::value<string>(), "feature weights")
    ("corner_penalty", po::value<float>()->required(), "per-corner penalty")
    ("occlusion_penalty", po::value<float>()->required(),
		 "additional penalty for occluding corners")
    ("with_gradient", "also compute gradient")
    ("logit", "use logistic likelihood (default is Gaussian)")
    ("delta", po::value<double>()->default_value(kDefaultDelta),
		 "Window size for finite differences.")
		;

	// Parse options
	po::variables_map opts;
	try {
		po::store(po::parse_command_line(argc, argv, desc), opts);
		po::notify(opts);
	} catch (const po::required_option& ex) {
		cout << "Missing required option: " << ex.get_option_name() << "\n" << desc << "\n";
		return -1;
	}
	if (opts.count("help")) {
    cout << desc << "\n";
    return -1;
	}
	if (opts.count("with_gradient")) {
		cout << "GRADIENTS NOT IMPLEMENTED";
		return -1;
	}

	// Read command line arguments
	ManhattanHyperParameters params;
	params.corner_penalty = opts["corner_penalty"].as<float>();
	params.occlusion_penalty = opts["occlusion_penalty"].as<float>();
	params.weights = stream_to<VecF>(opts["weights"].as<string>());

	// Evaluate the likelihood
	double loglik = EvaluateLikelihood(params,
																		 opts["features"].as<string>(),
																		 opts.count("logit_likelihood")>0);

	// Done. Print with high precision so matlab can read with high precision.	
	DLOG << format("%.18e ") % loglik;

	return 0;
}
	CRgbImage CSkinFeatureExtractor::SkinDetector(const IRgbImage &img) const
	{
		CRgbImage *InImage = (CRgbImage*)&img;
		int width = InImage->Width();
		int height = InImage->Height();
		// allcoate memory
		DOUBLE **ppLikelihoodOnSkin = new double*[clusternum];
		DOUBLE *pLikelihoodOffSkin;
		for (int i = 0; i < clusternum; ++i)
		{
			ppLikelihoodOnSkin[i] = new double[width * height];
		}
		pLikelihoodOffSkin = new double[width * height];

		// detect each pixel to obtain likelihood
		for (int y = 0; y < height; ++y)
		{
			for (int x = 0; x < width; ++x)
			{
				const BYTE R = (*InImage)(x, y).r;
				const BYTE G = (*InImage)(x, y).g;
				const BYTE B = (*InImage)(x, y).b;
				//const BYTE A = img(x, y).A();
				DOUBLE *pLikelihoodOnSkin = new double[clusternum];					
				DOUBLE dLikelihoodOffSkin;
				EvaluateLikelihood(R, G, B, pLikelihoodOnSkin, dLikelihoodOffSkin);
				DWORD index = y * width + x;
				for (int i = 0; i < clusternum; ++i)
				{
					ppLikelihoodOnSkin[i][index] = pLikelihoodOnSkin[i];
				}
				pLikelihoodOffSkin[index] = dLikelihoodOffSkin;
				delete []pLikelihoodOnSkin;
			}
		}

		// process
		CRgbImage m_SoftMap;
		//m_SoftMap.Allocate(InImage);
		//m_SoftMap = &InImage.Clone();
		m_SoftMap.Copy(*InImage);
		int iSkinType = 0;
		SkinAdapter((const DOUBLE**)ppLikelihoodOnSkin, pLikelihoodOffSkin, m_SoftMap, iSkinType);
		//m_SoftMap.Save(L"temp.jpg");

		// skin segmentation
		//CRgbImage m_SegmentColorMap;
		//SkinSegmentor(ppLikelihoodOnSkin[iSkinType], pLikelihoodOffSkin, InImage, m_SegmentColorMap);

		// free memory
		for (int i = 0; i < clusternum; ++i)
		{
			delete []ppLikelihoodOnSkin[i];
		}
		delete []ppLikelihoodOnSkin;
		delete []pLikelihoodOffSkin;
/*
		if (m_bEnableFaceDetection)
		{
			// face detection
			CImageRgb rgbImage;
			rgbImage.Copy(InImage);
			FaceDetector(rgbImage);
		}

		if (m_bEnableROIDetection)
		{
			// ROI detection
			int iFocusLeft = 0; 
			int iFocusTop = 0; 
			int iWidth = 0;
			int iHeight = 0;	
			ROIDetector(InImage, iFocusLeft, iFocusTop, iWidth, iHeight);

			// create detection result with ROI and face detection
			CreateROIImage(m_SegmentColorMap, iFocusLeft, iFocusTop, iWidth, iHeight);
		}
*/
		return m_SoftMap;
	}