/* 检测函数 */
void POIDetecter::detectMultiScale( const Mat& image, vector<OutBlock>& objects,
                                          vector<int>& rejectLevels,
                                          vector<double>& levelWeights,
                                          double scaleFactor, int minNeighbors,
                                          Size minObjectSize, Size maxObjectSize,
                                          bool outputRejectLevels )
{
    const double GROUP_EPS = 0.2;
    CV_Assert( scaleFactor > 1 && image.depth() == CV_8U );

    if( empty() )
        return;
    objects.clear();

    if( maxObjectSize.height == 0 || maxObjectSize.width == 0 )
	{
		maxObjectSize.width = image.size().width/2;
		maxObjectSize.height = image.size().height/2;
	}

    Mat grayImage = image;
    if( grayImage.channels() > 1 )
    {
        Mat temp;
        cvtColor(grayImage, temp, CV_BGR2GRAY);
        grayImage = temp;
    }
    
	std::map<int ,vector<CascadeClassifier> > scaleClassifiers;
	/* 不同分类器多个尺度 */
	vector<Rect> candidates;
	map<int , vector<Rect> > hz_rect;
	
	double factor = 1;
	if(image.rows * image.cols < 1e6)
	{
		/* 100万像素一下的扩大一下 */
		/* factor = 24/32*/
		factor = 0.75;
	}
	Mat imageBuffer(image.rows/factor + 2, image.cols/factor + 2, CV_8U);
	/* 计算步长 */
	int yStep = 4;

	double theFactor = scaleFactor;
	for( ; ; factor *= theFactor )
	{
		//if(factor < 1.0)
		//	theFactor = 1.17; // 0.625*1.17*1.17*1.17=1
		//else
		//	theFactor = scaleFactor;

		scaleClassifiers.clear();
		Size scaledImageSize( cvRound( grayImage.cols/factor ), cvRound( grayImage.rows/factor ) );
		/* 处理各个字符的分类器 */
		for(std::map<int ,vector<CascadeClassifier> >::iterator it = classifierUsed.begin(); it != classifierUsed.end(); it++)
		{
			int keylabel = it->first;
			vector<CascadeClassifier> classifiers = it->second;
			for(size_t i =0; i < classifiers.size(); i++)
			{
				CascadeClassifier classifier = classifiers[i];

				Size originalWindowSize = classifier.getOriginalWindowSize();
				Size windowSize( cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) );
				Size processingRectSize( scaledImageSize.width - originalWindowSize.width, scaledImageSize.height - originalWindowSize.height );

				if( processingRectSize.width <= 0 || processingRectSize.height <= 0 )/* 扩大后图像的尺寸小于分类器窗尺寸 */
					continue;
				if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height )
					continue;
				if( windowSize.width < minObjectSize.width && windowSize.height < minObjectSize.height )/* 最小尺寸的设置在多宽高比下要谨慎 */
					continue;
				scaleClassifiers[keylabel].push_back(classifier);
			}
		}
		/* 改尺寸下不存在任何分类器 */
		if(scaleClassifiers.empty())
		{
			break;
		}

		/* 缩放图片 */
		Mat scaledImage( scaledImageSize, CV_8U, imageBuffer.data );
		resize( grayImage, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR );
		int stripCount, stripSize;

		/* 得到haar所需要的积分图 */
		int cn = scaledImageSize.width +1, rn = scaledImageSize.height+1;
		Mat sum_scale = Mat(rn, cn, CV_32S);
		Mat sqsum_scale = Mat(rn, cn, CV_64F);
		Mat	tilted_scale = Mat(rn, cn, CV_32S);
		//integral(scaledImage, sum_scale, sqsum_scale, tilted_scale);

		//hog
		vector<Mat> hist_scale;
		hist_scale.clear();
		for( int bin = 0; bin < HOGEvaluator::Feature::BIN_NUM; bin++ )
		{
			hist_scale.push_back( Mat(rn, cn, CV_32FC1) );
		}
		Mat normSum_scale;
		normSum_scale.create( rn, cn, CV_32FC1 );
		integralHistogram( scaledImage, hist_scale, normSum_scale, HOGEvaluator::Feature::BIN_NUM );

		const int PTS_PER_THREAD = 1000;
		//double t0 = (double)getTickCount();
		//tt = 0.0;
		for(std::map<int ,vector<CascadeClassifier> >::iterator it = scaleClassifiers.begin(); it != scaleClassifiers.end(); it++)
		{
			int keylabel = it->first;
			vector<CascadeClassifier> classifiers = it->second;
			for(size_t i =0; i < classifiers.size(); i++)
			{
				CascadeClassifier classifier = classifiers[i];
				Size originalWindowSize = classifier.getOriginalWindowSize();
				Size processingRectSize( scaledImageSize.width - originalWindowSize.width, scaledImageSize.height - originalWindowSize.height );
				/* 并行个数以及大小,按照列进行并行处理,确实是列 */
				stripCount = ((processingRectSize.width/yStep)*(processingRectSize.height + yStep-1)/yStep + PTS_PER_THREAD/2)/PTS_PER_THREAD;
				stripCount = std::min(std::max(stripCount, 1), 100);
				stripSize = (((processingRectSize.height + stripCount - 1)/stripCount + yStep-1)/yStep)*yStep;
				/* 调用单尺度检测函数进行检测 */
				/* yStep是步长,factor是因子 */
				candidates.clear();
				/* candidates是结果 */
				if( !classifier.detectSingleScale( &sum_scale, &sqsum_scale, &tilted_scale,
					hist_scale, normSum_scale,
					scaledImage, stripCount, processingRectSize, 
					stripSize, yStep, factor, candidates,
					rejectLevels, levelWeights, outputRejectLevels) )
					continue;
				/* 返回的结果 */
				for(size_t m=0; m< candidates.size(); m++)
				{		
					hz_rect[keylabel].push_back(candidates[m]);
				}
			}
		}
		//double exec_time = ((double)getTickCount() - t0)/getTickFrequency();
		//cout << "time: " << exec_time << endl;
	}
    //objects.resize(candidates.size());
    //std::copy(candidates.begin(), candidates.end(), objects.begin());
	/* 合并检测结果 */
	for(map<int, vector<Rect> >::iterator it = hz_rect.begin(); it != hz_rect.end(); it++)
	{
		int key = it->first;
		//vector<Rect> key_vec = it->second;
		groupRectangles( it->second, minNeighbors, GROUP_EPS );
	}

	for(map<int, vector<Rect> >::iterator it = hz_rect.begin(); it != hz_rect.end(); it++)
	{
		int key = it->first;
		string hz;
		getWord(key, hz);
		vector<Rect> key_vec = it->second;
		for(size_t m = 0; m< key_vec.size(); m++)
		{
			objects.push_back(OutBlock(key_vec[m], key, hz));
		}
	}
}