void SpatialAverageSpotter::maximizeAlignment(vector<vector<tuple<int,Point2f> > > &features)
{
    int stayCount=0;
    int iters=0;
    vector<bool> adjusted(features.size(),false);
    while (stayCount<STAY_THRESH*features.size() && iters<MAX_REF_ITER*features.size())//20
    {
        iters++;
        int imageNum= rand()%features.size();
        int imageNumOld=imageNum;
        while(1)
        {
            if (!adjusted[imageNum])
            {
                adjusted[imageNum]=true;
                break;
            }
            imageNum = (imageNum+1)%features.size();
            if ((imageNum) == imageNumOld)
            {
                adjusted.assign(features.size(),false);
                adjusted[imageNum]=true;
//                stayCount /= 2;
                stayCount=0;
                break;
            }
        }
        
        
        double shiftStep = 2*(1.0-iters/(0.0+MAX_REF_ITER*features.size()));//3* DD 2* TT
        if (shiftStep<1) shiftStep=1.0; //1.0 DD
        double scaleStep = .03*(1.0-iters/(0.0+MAX_REF_ITER*features.size()));//.01 DD
        double scaleStep2 = .06*(1.0-iters/(0.0+MAX_REF_ITER*features.size()));// .015 DD
        if (scaleStep<1) scaleStep=.003; //DD remove
        if (scaleStep2<1) scaleStep2=.006; //DD remove
        //examine gradient at each f point (discluding self)
        //if gradients agrre, make scale step
        guassColorOut(features[imageNum]);
        
        double bestScore=0;
        ExemplarTransform bestMove=STAY;
        
        double leftScore=0;
        double rightScore=0;
        double upScore=0;
        double downScore=0;
        double smallerScore=0;
        double biggerScore=0;
        double shortenScore=0;
        double hightenScore=0;
        double slimScore=0;
        double fattenScore=0;
//        double leftSmallerScore=0;
//        double rightSmallerScore=0;
//        double upSmallerScore=0;
//        double downSmallerScore=0;
//        double leftBiggerScore=0;
//        double rightBiggerScore=0;
//        double upBiggerScore=0;
//        double downBiggerScore=0;
        
              
        for (tuple<int,Point2f> f : features[imageNum])
        {
            bestScore += getUsingOffset(featureAverages[get<0>(f)],get<1>(f).x,get<1>(f).y);
            leftScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x-shiftStep, get<1>(f).y);
            rightScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x+shiftStep, get<1>(f).y);
            upScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x, get<1>(f).y-shiftStep);
            downScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x, get<1>(f).y+shiftStep);
            smallerScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x*(1-scaleStep), get<1>(f).y*(1-scaleStep));
            biggerScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x*(1+scaleStep), get<1>(f).y*(1+scaleStep));
            shortenScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x,get<1>(f).y*(1-scaleStep2));
            hightenScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x, get<1>(f).y*(1+scaleStep2));
            slimScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x*(1-scaleStep2), get<1>(f).y);
            fattenScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x*(1+scaleStep2), get<1>(f).y);
//            leftSmallerScore += getUsingOffset(featureAverages[get<0>(f)], (get<1>(f).x-shiftStep)*(1-scaleStep), get<1>(f).y*(1-scaleStep));
//            rightSmallerScore += getUsingOffset(featureAverages[get<0>(f)], (get<1>(f).x+shiftStep)*(1-scaleStep), get<1>(f).y*(1-scaleStep));
//            upSmallerScore += getUsingOffset(featureAverages[get<0>(f)], (get<1>(f).x)*(1-scaleStep), (get<1>(f).y-shiftStep)*(1-scaleStep));
//            downSmallerScore += getUsingOffset(featureAverages[get<0>(f)], (get<1>(f).x)*(1-scaleStep), (get<1>(f).y+shiftStep)*(1-scaleStep));
//            leftBiggerScore += getUsingOffset(featureAverages[get<0>(f)], (get<1>(f).x-shiftStep)*(1+scaleStep), get<1>(f).y*(1+scaleStep));
//            rightBiggerScore += getUsingOffset(featureAverages[get<0>(f)], (get<1>(f).x+shiftStep)*(1+scaleStep), get<1>(f).y*(1+scaleStep));
//            upBiggerScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x*(1+scaleStep), (get<1>(f).y-shiftStep)*(1+scaleStep));
//            downBiggerScore += getUsingOffset(featureAverages[get<0>(f)], get<1>(f).x*(1+scaleStep), (get<1>(f).y+shiftStep)*(1+scaleStep));
        }
        
        double test=bestScore;
        
        if (leftScore > bestScore)
        {
            bestScore=leftScore; bestMove = LEFT;
        }
        if (rightScore > bestScore)
        {
            bestScore=rightScore; bestMove = RIGHT;
        }
        if (upScore > bestScore)
        {
            bestScore=upScore; bestMove = UP;
        }
        if (downScore > bestScore)
        {
            bestScore=downScore; bestMove = DOWN;
        }
        if (smallerScore > bestScore)
        {
            bestScore=smallerScore; bestMove = SHRINK;
        }
        if (biggerScore > bestScore)
        {
            bestScore=biggerScore; bestMove = GROW;
        }
        if (shortenScore > bestScore)
        {
            bestScore=shortenScore; bestMove = SHORTEN;
        }
        if (hightenScore > bestScore)
        {
            bestScore=hightenScore; bestMove = HIGHTEN;
        }
        if (slimScore > bestScore)
        {
            bestScore=slimScore; bestMove = SLIM;
        }
        if (fattenScore > bestScore)
        {
            bestScore=fattenScore; bestMove = FATTEN;
        }
//        if (leftSmallerScore > bestScore)
//        {
//            bestScore=leftSmallerScore; bestMove = LEFT_SHRINK;
//        }
//        if (rightSmallerScore > bestScore)
//        {
//            bestScore=rightSmallerScore; bestMove = RIGHT_SHRINK;
//        }
//        if (upSmallerScore > bestScore)
//        {
//            bestScore=upSmallerScore; bestMove = UP_SHRINK;
//        }
//        if (downSmallerScore > bestScore)
//        {
//            bestScore=downSmallerScore; bestMove = DOWN_SHRINK;
//        }
//        if (leftBiggerScore > bestScore)
//        {
//            bestScore=leftBiggerScore; bestMove = LEFT_GROW;
//        }
//        if (rightBiggerScore > bestScore)
//        {
//            bestScore=rightBiggerScore; bestMove = RIGHT_GROW;
//        }
//        if (upBiggerScore > bestScore)
//        {
//            bestScore=upBiggerScore; bestMove = UP_GROW;
//        }
//        if (downBiggerScore > bestScore)
//        {
//            bestScore=downBiggerScore; bestMove = DOWN_GROW;
//        }
        
        auto fI = features[imageNum].begin();
        for(; fI!=features[imageNum].end(); fI++)
        {
            switch(bestMove)
            {
            case LEFT:
                get<1>(*fI) = Point2f(get<1>(*fI).x-shiftStep, get<1>(*fI).y);
                
                break;
            case RIGHT:
                get<1>(*fI) = Point2f(get<1>(*fI).x+shiftStep, get<1>(*fI).y);
                
                break;
            case UP:
                get<1>(*fI) = Point2f(get<1>(*fI).x, get<1>(*fI).y-shiftStep);
//                cout << "upscore:"<<upScore<<" stayscore:"<<test<<endl;
                break;
            case DOWN:
                get<1>(*fI) = Point2f(get<1>(*fI).x, get<1>(*fI).y+shiftStep);
                
                break;
            case SHRINK:
                get<1>(*fI) = Point2f(get<1>(*fI).x*(1-scaleStep), get<1>(*fI).y*(1-scaleStep));
                
                break;
            case GROW:
                get<1>(*fI) = Point2f(get<1>(*fI).x*(1+scaleStep), get<1>(*fI).y*(1+scaleStep));
                
                break;
            case SHORTEN:
                get<1>(*fI) = Point2f(get<1>(*fI).x, get<1>(*fI).y*(1-scaleStep2));
                
                break;
            case HIGHTEN:
                get<1>(*fI) = Point2f(get<1>(*fI).x, get<1>(*fI).y*(1+scaleStep2));
                
                break;
            case SLIM:
                get<1>(*fI) = Point2f(get<1>(*fI).x*(1-scaleStep2), get<1>(*fI).y);
                
                break;
            case FATTEN:
                get<1>(*fI) = Point2f(get<1>(*fI).x*(1+scaleStep2), get<1>(*fI).y);
                
                break;
//            case LEFT_SHRINK:
//                get<1>(*fI) = Point2f((get<1>(*fI).x-shiftStep)*(1-scaleStep), get<1>(*fI).y*(1-scaleStep));
                
//                break;
//            case RIGHT_SHRINK:
//                get<1>(*fI) = Point2f((get<1>(*fI).x+shiftStep)*(1-scaleStep), get<1>(*fI).y*(1-scaleStep));
                
//                break;
//            case UP_SHRINK:
//                get<1>(*fI) = Point2f((get<1>(*fI).x)*(1-scaleStep), (get<1>(*fI).y-shiftStep)*(1-scaleStep));
                
//                break;
//            case DOWN_SHRINK:
//                get<1>(*fI) = Point2f((get<1>(*fI).x)*(1-scaleStep), (get<1>(*fI).y+shiftStep)*(1-scaleStep));
                
//                break;
//            case LEFT_GROW:
//                get<1>(*fI) = Point2f((get<1>(*fI).x-shiftStep)*(1+scaleStep), get<1>(*fI).y*(1+scaleStep));
                
//                break;
//            case RIGHT_GROW:
//                get<1>(*fI) = Point2f((get<1>(*fI).x+shiftStep)*(1+scaleStep), get<1>(*fI).y*(1+scaleStep));
                
//                break;
//            case UP_GROW:
//                get<1>(*fI) = Point2f(get<1>(*fI).x*(1+scaleStep), (get<1>(*fI).y-shiftStep)*(1+scaleStep));
                
//                break;
//            case DOWN_GROW:
//                get<1>(*fI) = Point2f(get<1>(*fI).x*(1+scaleStep), (get<1>(*fI).y+shiftStep)*(1+scaleStep));
                
//                break;
            case STAY:
                break;
            }
        }
        if(bestMove == STAY)
        {
            stayCount+=1;
        }
        else if (stayCount>0)
        {
           stayCount--;
        }
        
        
        //////
        switch(bestMove)
        {
        case LEFT:
            translateImg(adjustedTrainingImages[imageNum],-shiftStep,0);
            
            break;
        case RIGHT:
            translateImg(adjustedTrainingImages[imageNum],shiftStep,0);
            
            break;
        case UP:
            translateImg(adjustedTrainingImages[imageNum],0,-shiftStep);
            break;
        case DOWN:
            translateImg(adjustedTrainingImages[imageNum],0,shiftStep);
            
            break;
        case SHRINK:
            strechImg(adjustedTrainingImages[imageNum],(1-scaleStep),(1-scaleStep));
            break;
        case GROW:
            strechImg(adjustedTrainingImages[imageNum],(1+scaleStep),(1+scaleStep));
            
            break;
        case SHORTEN:
            strechImg(adjustedTrainingImages[imageNum],1,(1-scaleStep2));
            
            break;
        case HIGHTEN:
            strechImg(adjustedTrainingImages[imageNum],1,(1+scaleStep2));
            
            break;
        case SLIM:
            strechImg(adjustedTrainingImages[imageNum],(1-scaleStep2),1);
            
            break;
        case FATTEN:
            strechImg(adjustedTrainingImages[imageNum],(1+scaleStep2),1);
            
            break;
        case STAY:
            break;
        }
        
        //////
        
        guassColorIn(features[imageNum]);
        
        cout <<"image "<<imageNum<<" move "<<bestMove<<", staycount="<<stayCount<<endl;
        showAverages();
        
        Mat averageImage(adjustedTrainingImages[0].rows,adjustedTrainingImages[0].cols,CV_8U);
        for (int x=0; x< averageImage.cols; x++)
            for (int y=0; y<averageImage.rows; y++)
            {
                int sum=0;
                for (Mat image : adjustedTrainingImages)
                {
                    sum += image.at<unsigned char>(y,x);
                }
                sum /= adjustedTrainingImages.size();
                assert(sum>=0 && sum<256);
                averageImage.at<unsigned char>(y,x) = sum;
            }
        
        imshow("average",averageImage);
        waitKey(5);
        
//        imshow("adjusted",adjustedTrainingImages[imageNum]);
//        waitKey();
    }
    
    Mat averageImage(adjustedTrainingImages[0].rows,adjustedTrainingImages[0].cols,CV_8U);
    for (int x=0; x< averageImage.cols; x++)
        for (int y=0; y<averageImage.rows; y++)
        {
            int sum=0;
            for (Mat image : adjustedTrainingImages)
            {
                sum += image.at<unsigned char>(y,x);
            }
            sum /= adjustedTrainingImages.size();
            assert(sum>=0 && sum<256);
            averageImage.at<unsigned char>(y,x) = sum;
        }
    int i=0;
    for (Mat image : adjustedTrainingImages)
    {
        imshow("adjusted",image);
        cout << "image "<<i++<<endl;
        waitKey(5);
    }
    
    imshow("average",averageImage);
    waitKey(5);
}
示例#2
0
  //static
  void GradientsMergeMosaic::mergeMosaic(imageListType_t const & rImageList_p,
					 realType_t dBlackPoint_p,
					 pcl_enum eType_p,
					 int32 shrinkCount_p,
					 int32 featherRadius_p,
					 imageType_t &rResultImage_p,
					 sumMaskImageType_t &rSumMaskImage_p)
  {
    Assert(rImageList_p.Length()>=1);
    bool firstImage=true;
    int nCols=0,nRows=0,nChannels=0; /// size and color space of first image
    imageType_t::color_space colorSpace;
    weightImageType_t countImageDx, countImageDy; /// number of pixels that contributed to sumImageDx,Dy in average mode
    imageType_t sumImageDx, sumImageDy; /// combined gradients in x and y direction. Note: these gradients are *between* the pixels
                                        /// of the original image, so size is one less then original image is direction of derivative
    int nImages=0; /// number of images read
    const int enlargeSize=1; // number of pixels added at the border

    TimeMessage startMergeMosaic("Gradient Domain Merge Mosaic");

    TimeMessage startLoadImages("Loading images");
    for(std::size_t i=0;i<rImageList_p.Length();++i){
      imageType_t currentImage;
      int imageIndex=0;
      // allow for multi-image files
      while(loadFile(rImageList_p[i],imageIndex,currentImage)){
	++nImages;
	++imageIndex;
	// expand image dimensions so I have sufficient border for morpological transform and convolution
	TimeMessage startEnlarge("creating border");
	currentImage.CropBy(enlargeSize,enlargeSize,enlargeSize,enlargeSize);
	startEnlarge.Stop();

	if(firstImage){
	  firstImage=false;
	  // determine those parameters that must be shared by all images
	  nCols=currentImage.Width();
	  nRows=currentImage.Height();
	  nChannels=currentImage.NumberOfChannels();
	  colorSpace=currentImage.ColorSpace();

	  //allocate necessary helper images
	  rSumMaskImage_p.AllocateData(nCols,nRows);
	  rSumMaskImage_p.ResetSelections();
	  rSumMaskImage_p.Black();
	  sumImageDx.AllocateData(nCols-1,nRows,nChannels,colorSpace);
	  sumImageDx.ResetSelections();
	  sumImageDx.Black();
	  sumImageDy.AllocateData(nCols,nRows-1,nChannels,colorSpace);
	  sumImageDy.ResetSelections();
	  sumImageDy.Black();

	  countImageDx.AllocateData(nCols-1,nRows);
	  countImageDx.Black();
	  countImageDy.AllocateData(nCols,nRows-1);
	  countImageDy.Black();
	} else {
	  // FIXME I wonder if I should check color space etc as well...
	  // check if properties of this image are identical to those of the first image
	  if(nCols!=currentImage.Width()) {
	    throw Error("Current image width differs from first image width.");
	  } else if(nRows!=currentImage.Height()) {
	    throw Error("Current image height differs from first image height.");
	  }	else if(nChannels!=currentImage.NumberOfChannels()) {
	    throw Error("Current image number of channels differs from first image number of channels.");
	  }
	}
	TimeMessage startProcessImage("Processing Image"+String(nImages));
	mergeMosaicProcessImage(currentImage,dBlackPoint_p,eType_p,shrinkCount_p,featherRadius_p,sumImageDx, sumImageDy ,rSumMaskImage_p,countImageDx, countImageDy);
      }
    }
    startLoadImages.Stop();
    if (eType_p==GradientsMergeMosaicType::Average) {
      TimeMessage startAverage("Averaging images");
      averageImage(eType_p,countImageDx,sumImageDx);
      averageImage(eType_p,countImageDy,sumImageDy);
      // we do not need count images any longer
      countImageDx.AllocateData(0,0);
      countImageDy.AllocateData(0,0);
    }
    // at this point:
    // sumImageDx: Average or overlay of gradients of images read in x direction
    // sumImageDy: Average or overlay of gradients of images read in y direction
    // rSumMaskImage_p: mask with different values for the different sources of images. 0 is background.
    //              We use this later for information of the user, but it is not needed in the following process
    TimeMessage startMerge("Merging Images");
    imageType_t laplaceImage;
    TimeMessage startLaplace("Creating Laplace image");
    createLaplaceVonNeumannImage(sumImageDx,sumImageDy,laplaceImage);
    startLaplace.Stop();
    TimeMessage startSolve("Solving Laplace");
    solveImage(laplaceImage,rResultImage_p);
    startSolve.Stop();
    startMerge.Stop();
    rResultImage_p.ResetSelections();
#if 0
    // for debugging laplaceImage
    //    rResultImage_p.Assign(laplaceImage);
    rResultImage_p.Assign(sumImageDx);
#else
    TimeMessage startEnlarge("shrinking border");
    rResultImage_p.CropBy(-enlargeSize,-enlargeSize,-enlargeSize,-enlargeSize);
    rSumMaskImage_p.CropBy(-enlargeSize,-enlargeSize,-enlargeSize,-enlargeSize);
    startEnlarge.Stop();
#endif
    TimeMessage startRescale("Rescaling Result");
    rResultImage_p.Rescale(); //FIXME something more clever?
    startRescale.Stop();
  }