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); }
//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(); }