예제 #1
0
  //static
  void GradientsBase::binarizeImage(imageType_t const & currentImage_p, realType_t dBlackPoint_p,
					   weightImageType_t & rMaskImage_p)
  {
#if 0
    imageType_t image(currentImage_p);
    image.ResetSelections();
    image.Binarize(dBlackPoint_p);
    // first channel
    image.ResetSelections();
    image.SelectChannel(0);
    rMaskImage_p.ResetSelections();
    rMaskImage_p.Assign(image);
    // compress into one channel
    for(int i=1;i<image.NumberOfChannels();++i){
      image.SelectChannel(i);
      rMaskImage_p.Max(image);
    }
#else
    int const nCols=currentImage_p.Width();
    int const nRows=currentImage_p.Height();
    int const nChannels=currentImage_p.NumberOfChannels();

    rMaskImage_p.AllocateData(nCols,nRows);
    rMaskImage_p.Black();
    for(int channel=0;channel<nChannels;++channel){
      for(int row=0;row<nRows;++row){
	for(int col=0;col<nCols;++col){
	  if(currentImage_p.Pixel(col,row,channel)>dBlackPoint_p) {
	    rMaskImage_p.Pixel(col,row)=1.0;
	  }
	}
      }
    }
#endif
  }
//static
void
GradientsHdrCompression::minMaxValImage(imageType_t const &rImage_p, realType_t &rdMin_p,realType_t &rdMax_p)
{
  AssertImage(rImage_p);
  rImage_p.ResetSelections();
  rImage_p.GetExtremePixelValues(rdMin_p, rdMax_p);
}
예제 #3
0
  //static
  void GradientsMergeMosaic::averageImage(pcl_enum eType_p,
					  weightImageType_t const &rCountImage_p,
					  imageType_t &rImage_p)
  {
    int const nCols=rImage_p.Width();
    int const nRows=rImage_p.Height();
    int const nChannels=rImage_p.NumberOfChannels();
    switch(eType_p) {
      // FIXME sure there must be a faster way to do this via masked ops?!?
    case GradientsMergeMosaicType::Overlay:
      // do nothing
      break;
    case GradientsMergeMosaicType::Average:
      // FIXME use builtin PCL for this
      for(int channel=0;channel<nChannels;++channel){
	for(int row=0;row<nRows;++row){
	  for(int col=0;col<nCols;++col){
       	    if(rCountImage_p.Pixel(col,row)>0.0){
	      rImage_p.Pixel(col,row,channel)/=static_cast<realType_t>(rCountImage_p.Pixel(col,row));
	    }
	  }
	}
      }
      break;
    default:
      Assert(false);
    }
  }
예제 #4
0
void
GradientsBase::AssertColImage(imageType_t const &rImage_p)
{
  Assert(rImage_p.Height()>2);
  Assert(rImage_p.Width()>2);
  Assert(rImage_p.NumberOfChannels()>=1);
}
예제 #5
0
  //static
  void GradientsHdrComposition::clipGradients(imageType_t &rImage_p)
  {
    for ( realType_t* f = rImage_p.PixelData(), * f1 = f + rImage_p.NumberOfPixels(); f != f1; ++f )
      {
	if ( std::abs(*f) > -MINLOGVALUE) {
	  *f = 0.0;
	}
      }
  }
//static
void
GradientsHdrCompression::zeroRangeImage(imageType_t &rImage_p, realType_t minRange_p, realType_t maxRange_p)
{
  AssertImage(rImage_p);
  Assert(maxRange_p>=minRange_p);
  // code from template <class P> void GenericImage<P>::Truncate( const sample* r0, const sample* r1 )

  for ( realType_t* f = rImage_p.PixelData(), * f1 = f + rImage_p.NumberOfPixels(); f != f1; ++f ){
    if ( *f > minRange_p && *f < maxRange_p) {
      *f = 0.0;
    }
  }
}
예제 #7
0
  //static
  void GradientsHdrComposition::logImage(imageType_t const & rCurrentImage_p,
					 imageType_t & rResultImage_p)
  {
    int const nCols=rCurrentImage_p.Width();
    int const nRows=rCurrentImage_p.Height();
    int const nChannels=rCurrentImage_p.NumberOfChannels();
    imageType_t::color_space  colorSpace=rCurrentImage_p.ColorSpace();

    if (&rCurrentImage_p != &rResultImage_p){
      rResultImage_p.AllocateData(nCols,nRows, nChannels, colorSpace);
    }
    for(int channel=0;channel<nChannels;++channel){
      for(int row=0;row<nRows;++row){
	for(int col=0;col<nCols;++col){
	  realType_t val=rCurrentImage_p.Pixel(col,row,channel);
	  if(val<=0.0) {
	    rResultImage_p.Pixel(col,row,channel)= -1000; //this is just some value to identify extremes
	  } else {
	    val=std::log(val);
	    rResultImage_p.Pixel(col,row,channel)=val;
	  }
	}
      }
    }
  }
//static
void
GradientsHdrCompression::absPowImage(imageType_t &rImage_p, realType_t exponent_p)
{
  AssertImage(rImage_p);
  Assert(exponent_p>0.0);

  for ( realType_t* f = rImage_p.PixelData(), * f1 = f + rImage_p.NumberOfPixels(); f != f1; ++f ){
    if ( *f > 0) {
      *f = std::pow(*f,exponent_p);
    }else{
      *f = -std::pow(- *f,exponent_p);
    }
  }
}
void
GradientsHdrCompression::hdrCompression(realType_t maxGradient_p, realType_t minGradient_p, realType_t expGradient_p,
			   bool bRescale01_p, imageType_t &rResultImage_p) const
{
  TimeMessage startHdrCompression("Gradient Domain HDR Compression");
  imageType_t li;
  {
    TimeMessage startClipValue("Determine clip values for gradients");
    imageType_t dx(m_imageDx);
    imageType_t dy(m_imageDy);
    // now clip values
    realType_t minGradientX,maxGradientX;
    minMaxValImage(dx,minGradientX,maxGradientX);
    realType_t minGradientY,maxGradientY;
    minMaxValImage(dy,minGradientY,maxGradientY);
    realType_t minValue=Min(minGradientX, minGradientY);
    realType_t maxValue=Max(maxGradientX, maxGradientY);
    double rangeValue=Max(-minValue, maxValue);
    realType_t const clipRange=rangeValue*maxGradient_p;
    realType_t const zeroRange=rangeValue*minGradient_p;
    startClipValue.Stop();

    TimeMessage startClip("Clipping Gradients");
    clipImage(dx,-clipRange,clipRange);
    zeroRangeImage(dx,-zeroRange,zeroRange);
    clipImage(dy,-clipRange,clipRange);
    zeroRangeImage(dy,-zeroRange,zeroRange);
    startClip.Stop();

    if(expGradient_p!=1.0){
      TimeMessage start("Pow() transformation of gradients");
      absPowImage(dx,expGradient_p);
      absPowImage(dy,expGradient_p);
    }

    TimeMessage startLaplace("Computing 2nd derivative");
    createLaplaceVonNeumannImage(dx,dy,li);
  }
  TimeMessage startSolve("Solving image");
  solveImage(li,rResultImage_p);
  startSolve.Stop();

  TimeMessage startRescale("Rescaling image");
  if(bRescale01_p){
    rResultImage_p.Rescale(0.0,1.0);
  } else {
    rResultImage_p.Rescale(m_dMinVal,m_dMaxVal);
  }
}
예제 #10
0
//static
void
GradientsHdrCompression::clipImage(imageType_t &rImage_p, realType_t minRange_p, realType_t maxRange_p)
{
  AssertImage(rImage_p);
  Assert(maxRange_p>=minRange_p);
#if 1
  rImage_p.ResetSelections();
  rImage_p.Truncate(minRange_p, maxRange_p);
#else
  // slow version for tests
  for ( realType_t* f = rImage_p.PixelData(), * f1 = f + rImage_p.NumberOfPixels(); f != f1; ++f ){
    if ( *f < minRange_p ) {
      *f = minRange_p;
      continue;
    }
    if ( *f > maxRange_p ) {
      *f = maxRange_p;
    }
  }
#endif
}
예제 #11
0
//static
void
GradientsBase::createDyImage(imageType_t const &rImage_p, imageType_t &rResultImage_p)
{
  AssertColImage(rImage_p);
  int const nRows=rImage_p.Height();
  int const nCols=rImage_p.Width();
  int const nChannels=rImage_p.NumberOfChannels();
  imageType_t::color_space colorSpace=rImage_p.ColorSpace();

  rResultImage_p.AllocateData(nCols,nRows-1,nChannels,colorSpace);
  for(int chan=0;chan<nChannels;++chan){
    for (int row=0;row<nRows-1;++row){
      for(int col=0;col<nCols;++col){
	rResultImage_p.Pixel(col,row,chan)=rImage_p.Pixel(col,row+1,chan)-rImage_p.Pixel(col,row,chan);
      }
    }
  }
}
예제 #12
0
  //static
  void GradientsHdrComposition::expImage(imageType_t const & rCurrentImage_p,
					 imageType_t & rResultImage_p)
  {
    int const nCols=rCurrentImage_p.Width();
    int const nRows=rCurrentImage_p.Height();
    int const nChannels=rCurrentImage_p.NumberOfChannels();
    imageType_t::color_space  colorSpace=rCurrentImage_p.ColorSpace();

    if (&rCurrentImage_p != &rResultImage_p){
      rResultImage_p.AllocateData(nCols,nRows, nChannels, colorSpace);
    }
    for(int channel=0;channel<nChannels;++channel){
      for(int row=0;row<nRows;++row){
	for(int col=0;col<nCols;++col){
	  realType_t val=rCurrentImage_p.Pixel(col,row,channel);
	  rResultImage_p.Pixel(col,row,channel)=std::exp(val);
	}
      }
    }
  }
예제 #13
0
  //static
  void GradientsHdrComposition::addToImage(imageType_t const & rImage_p,
					   int imageNum_p,
					   weightImageType_t const & rMask_p,
					   imageType_t &rSumImageDx_p,imageType_t &rSumImageDy_p,
					   numImageType_t &rDxImage_p,
					   numImageType_t &rDyImage_p)
  {
    int const nCols=rImage_p.Width();
    int const nRows=rImage_p.Height();
    int const nChannels=rImage_p.NumberOfChannels();

    Assert(nCols==rSumImageDx_p.Width()+1);
    Assert(nRows==rSumImageDx_p.Height());
    Assert(nChannels==rSumImageDx_p.NumberOfChannels());

    Assert(nCols==rSumImageDy_p.Width());
    Assert(nRows==rSumImageDy_p.Height()+1);
    Assert(nChannels==rSumImageDy_p.NumberOfChannels());

    Assert(nCols==rDxImage_p.Width());
    Assert(nRows==rDxImage_p.Height());
    Assert(nChannels==rDxImage_p.NumberOfChannels());

    Assert(nCols==rDyImage_p.Width());
    Assert(nRows==rDyImage_p.Height());
    Assert(nChannels==rDyImage_p.NumberOfChannels());

    imageType_t dxImage, dyImage;
    const double zeroLimit=0.0; /// limit for weight that is considered zero
    // handle Dx
    TimeMessage startDx("Creating Dx");
    createDxImage(rImage_p,dxImage);
    startDx.Stop();
    TimeMessage startAddDx("Adding Dx to gradients");
    // transfer useful dx pixels
    for(int row=0;row<nRows;++row){
      for(int col=0;col<nCols-1;++col){
	if(rMask_p.Pixel(col,row)>zeroLimit && rMask_p.Pixel(col+1,row)>zeroLimit) {
	  // we are inside of image, and have useful gradient there
	  for(int channel=0;channel<nChannels;++channel){
	    realType_t currentVal=dxImage.Pixel(col,row,channel);
	    realType_t sumVal=rSumImageDx_p.Pixel(col,row,channel);
	    if(std::abs(currentVal)>std::abs(sumVal)){
	      rSumImageDx_p.Pixel(col,row,channel)=currentVal;
	      rDxImage_p.Pixel(col,row,channel)=imageNum_p;
	    } //if abs
	  } // for chan
	  // FIXME may need to add border handling
	}  //if inside
      }  //for col
    }  //for row
    dxImage.AllocateData(0,0); //save some memory
    startAddDx.Stop();

    // handle Dy just as dx
    TimeMessage startDy("Creating Dy");
    createDyImage(rImage_p,dyImage);
    startDy.Stop();
    TimeMessage startAddDy("Adding Dxy to gradients");
    // transfer useful dy pixels
    for(int row=0;row<nRows-1;++row){
      for(int col=0;col<nCols;++col){
	if(rMask_p.Pixel(col,row)>zeroLimit && rMask_p.Pixel(col,row+1)>zeroLimit) {
	  for(int channel=0;channel<nChannels;++channel){
	    // we are inside of image, and have useful gradient there
	    realType_t currentVal=dyImage.Pixel(col,row,channel);
	    realType_t sumVal=rSumImageDy_p.Pixel(col,row,channel);
	    if(std::abs(currentVal)>std::abs(sumVal)){
	      rSumImageDy_p.Pixel(col,row,channel)=currentVal;
	      rDyImage_p.Pixel(col,row,channel)=imageNum_p;
	    } //if abs()
	  } // for chan
	  // FIXME may need to add border handling
	}  // if inside
      }  //for col
    }  //for row
    startAddDy.Stop();
  }
예제 #14
0
  //static
  void GradientsHdrComposition::hdrComposition(imageListType_t const & rImageList_p,
					       bool bKeepLog_p,
					       realType_t dBias_p,
					       imageType_t &rResultImage_p,
					       numImageType_t &rDxImage_p,
					       numImageType_t &rDyImage_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;
    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 startHdrComposition("Gradient Domain Hdr Composition");

    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
	  rDxImage_p.AllocateData(nCols,nRows,nChannels,colorSpace);
	  rDxImage_p.ResetSelections();
	  rDxImage_p.Black();
	  rDyImage_p.AllocateData(nCols,nRows,nChannels,colorSpace);
	  rDyImage_p.ResetSelections();
	  rDyImage_p.Black();

	  sumImageDx.AllocateData(nCols-1,nRows,nChannels,colorSpace);
	  sumImageDx.ResetSelections();
	  sumImageDx.Black();
	  sumImageDy.AllocateData(nCols,nRows-1,nChannels,colorSpace);
	  sumImageDy.ResetSelections();
	  sumImageDy.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));
	hdrCompositionProcessImage(currentImage,nImages,dBias_p,0.0,1,sumImageDx, sumImageDy ,rDxImage_p,rDyImage_p);
      }
    }
    startLoadImages.Stop();
    // at this point:
    // sumImageDx: max log gradient of images read in x direction
    // sumImageDy: max log gradient 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 startHdr("HDR Combining Images");
    imageType_t laplaceImage;
    TimeMessage startLaplace("Creating Laplace image");
    // eliminate gradients that come from singularities, i.e. <=0 pixels
    clipGradients(sumImageDx);
    clipGradients(sumImageDy);
    createLaplaceVonNeumannImage(sumImageDx,sumImageDy,laplaceImage);
    startLaplace.Stop();
    TimeMessage startSolve("Solving Laplace");
    solveImage(laplaceImage,rResultImage_p);
    startSolve.Stop();
    rResultImage_p.ResetSelections();
    if(!bKeepLog_p){
      TimeMessage startExp("Performing Exp()");
      realType_t dLogBias=std::log(1.0e-7);
      rResultImage_p.Rescale(dLogBias,0.0); //assumes result range is 1e-7..1
      expImage(rResultImage_p, rResultImage_p);
      startExp.Stop();
    }
    startHdr.Stop();
#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);
    rDxImage_p.CropBy(-enlargeSize,-enlargeSize,-enlargeSize,-enlargeSize);
    rDyImage_p.CropBy(-enlargeSize,-enlargeSize,-enlargeSize,-enlargeSize);
    startEnlarge.Stop();
#endif
    TimeMessage startRescale("Rescaling Result");
    rResultImage_p.Rescale(); //FIXME something more clever?
    startRescale.Stop();
  }
예제 #15
0
//static
void
GradientsBase::solveImage(imageType_t const &rLaplaceImage_p, imageType_t &rSolution_p)
{
  int const nRows=rLaplaceImage_p.Height();
  int const nCols=rLaplaceImage_p.Width();
  int const nChannels=rLaplaceImage_p.NumberOfChannels();
  imageType_t::color_space colorSpace=rLaplaceImage_p.ColorSpace();

#ifdef USE_FFTW
  // adapted from http://www.umiacs.umd.edu/~aagrawal/software.html,

  AssertColImage(rLaplaceImage_p);
  // just in case we accidentally change this, because code below believes in double...
  Assert(typeid(realType_t)==typeid(double));
  // check assumption of row major format
  Assert(rLaplaceImage_p.PixelAddress(0,0)+1==rLaplaceImage_p.PixelAddress(1,0));


  rSolution_p.AllocateData(nCols,nRows,nChannels,colorSpace);
  rSolution_p.ResetSelections();
  rSolution_p.Black();

#ifdef USE_THREADS
    // threaded version
    int const nElements=nRows*nCols;
    int const nThreads=Thread::NumberOfThreads(nElements);

    if(fftw_init_threads()==0){
      throw Error("Problem initilizing threads");
    }
    fftw_plan_with_nthreads(nThreads);
#endif

  for(int chan=0;chan<nChannels;++chan){
    TimeMessage startSolver(String("FFTW Solver, Channel ")+String(chan));

    // FIXME see if fttw_allocate gives us something...
    imageType_t fcos(nCols,nRows);

#if 0
    // During experiment, the higher optimization did not give us anything except for an additional delay. May change later.
    fftw_plan pForward= fftw_plan_r2r_2d(nRows, nCols, const_cast<double *>(rLaplaceImage_p.PixelData(chan)), fcos.PixelData(), FFTW_REDFT10, FFTW_REDFT10, FFTW_MEASURE);
    fftw_plan pInverse = fftw_plan_r2r_2d(nRows, nCols, fcos.PixelData(), rSolution_p.PixelData(chan), FFTW_REDFT01, FFTW_REDFT01, FFTW_ESTIMATE);
#else
    fftw_plan pForward= fftw_plan_r2r_2d(nRows, nCols, const_cast<double *>(rLaplaceImage_p.PixelData(chan)), fcos.PixelData(), FFTW_REDFT10, FFTW_REDFT10, FFTW_MEASURE);
    fftw_plan pInverse = fftw_plan_r2r_2d(nRows, nCols, fcos.PixelData(), rSolution_p.PixelData(chan), FFTW_REDFT01, FFTW_REDFT01, FFTW_ESTIMATE);
#endif

    // find DCT
    fftw_execute(pForward);

    realType_t const pi=pcl::Pi();

    for(int row = 0 ; row < nRows; ++row){
      for(int col = 0 ; col < nCols; ++col){
	fcos.Pixel(col,row) /= 2*cos(pi*col/( (double) nCols)) - 2 + 2*cos(pi*row/((double) nRows)) - 2;
      }
    }
    fcos.Pixel(0,0)=0.0;

    // Inverse DCT
    fftw_execute(pInverse);
    fftw_destroy_plan(pForward);
    fftw_destroy_plan(pInverse);
  }
#endif
#ifdef USE_PIFFT
  // use PI FFT based solver by Carlos Milovic F.
  rLaplaceImage_p.ResetSelections();
  rSolution_p.AllocateData(nCols,nRows,nChannels,colorSpace);
  rSolution_p.ResetSelections();
  // current solver handles only one channel per run.
  for(int chan=0;chan<nChannels;++chan){
    TimeMessage startSolver(String("PIFFT Solver, Channel ")+String(chan));
    imageType_t tmpImage(nCols,nRows);
    rLaplaceImage_p.SelectChannel(chan);
    tmpImage.Assign(rLaplaceImage_p);
    __SolvePoisson(tmpImage);
    rSolution_p.SelectChannel(chan);
    rSolution_p.Mov(tmpImage);
  }
#endif
}
예제 #16
0
//static
void
GradientsBase::createLaplaceVonNeumannImage(imageType_t const & rDx_p, imageType_t const rDy_p,
					imageType_t &rResultImage_p)
{

  AssertColImage(rDx_p);
  AssertColImage(rDy_p);
  int const nRowsX=rDx_p.Height();
#ifdef DEBUG
  int const nColsX=rDx_p.Width();
  int const nRowsY=rDy_p.Height();
#endif
  int const nColsY=rDy_p.Width();
  int const nRowsRes=nRowsX;
  int const nColsRes=nColsY;
  int const nChannels=rDx_p.NumberOfChannels();
  imageType_t::color_space colorSpace=rDx_p.ColorSpace();

  Assert(nRowsX>0 && nColsX>0);
  Assert(nRowsY>0 && nColsY>0);
  Assert(nRowsY+1==nRowsX && nColsY==nColsX+1);
  Assert(nChannels==rDy_p.NumberOfChannels());

  //d2x, inner part
  rResultImage_p.AllocateData(nColsRes,nRowsRes,nChannels,colorSpace);
  for(int chan=0;chan<nChannels;++chan){
    for(int row=0;row<nRowsRes;++row){
      for(int col=1;col<nColsRes-1;++col){
	rResultImage_p.Pixel(col,row,chan)=rDx_p.Pixel(col,row,chan)-rDx_p.Pixel(col-1,row,chan);
      }
    }
    //d2x, first and last column
    for(int row=0;row<nRowsRes;++row){
      rResultImage_p.Pixel(0,row,chan)=rDx_p.Pixel(0,row,chan);
      rResultImage_p.Pixel(nColsRes-1,row,chan)=-rDx_p.Pixel(nColsRes-2,row,chan);
    }

    //d2y, inner part
    for(int row=1;row<nRowsRes-1;++row){
      for(int col=0;col<nColsRes;++col){
	rResultImage_p.Pixel(col,row,chan)+=rDy_p.Pixel(col,row,chan)-rDy_p.Pixel(col,row-1,chan);
      }
    }
    //d2y, first and last row
    for(int col=0;col<nColsRes;++col){
      rResultImage_p.Pixel(col,0,chan)+=rDy_p.Pixel(col,0,chan);
      rResultImage_p.Pixel(col,nRowsRes-1,chan)-=rDy_p.Pixel(col,nRowsRes-2,chan);
    }
  }
}
예제 #17
0
  //static
  void GradientsMergeMosaic::addToImage(imageType_t const & rImage_p,pcl_enum eType_p,
					weightImageType_t const & rMask_p,
					imageType_t &rSumImageDx_p,imageType_t &rSumImageDy_p,
					weightImageType_t &rCountImageDx_p, weightImageType_t &rCountImageDy_p)
  {
    int const nCols=rImage_p.Width();
    int const nRows=rImage_p.Height();
    int const nChannels=rImage_p.NumberOfChannels();
    imageType_t dxImage, dyImage;

    const double zeroLimit=0.0; /// limit for weight that is considered zero


    TimeMessage startDx("Creating Dx");
    createDxImage(rImage_p,dxImage);
    startDx.Stop();
    TimeMessage startAddDx("Adding Dx");
    // transfer useful dx pixels
    // FIXME this is a relatively slow loop. Think about making it faster
    for(int row=0;row<nRows;++row){
      for(int col=0;col<nCols-1;++col){
	if(rMask_p.Pixel(col,row)>zeroLimit && rMask_p.Pixel(col+1,row)>zeroLimit) {
	  // we are inside of image
	  realType_t weight=(rMask_p.Pixel(col,row)+rMask_p.Pixel(col+1,row))/2.0;
	  if(eType_p==GradientsMergeMosaicType::Average){
	    if(rCountImageDx_p.Pixel(col,row)<=0.0){
	      // first foreground pixel on this location
	      for(int channel=0;channel<nChannels;++channel){
		rSumImageDx_p.Pixel(col,row,channel)=dxImage.Pixel(col,row,channel)*weight;
	      }
	    } else {
	      // there have been other pixels. Create average
	      for(int channel=0;channel<nChannels;++channel){
		rSumImageDx_p.Pixel(col,row,channel)+=dxImage.Pixel(col,row,channel)*weight;
	      }
	    }
	    rCountImageDx_p.Pixel(col,row)+=weight;
	  } else {
	    // type overlay, last gradient wins
	    if(rCountImageDx_p.Pixel(col,row)<=0.0){
		// first foreground pixel on this location
	      for(int channel=0;channel<nChannels;++channel){
		rSumImageDx_p.Pixel(col,row,channel)=dxImage.Pixel(col,row,channel);
	      }
	      rCountImageDx_p.Pixel(col,row)=1.0; //mark as used
	    } else {
	      // there have been other pixels. Blend
	      for(int channel=0;channel<nChannels;++channel){
		rSumImageDx_p.Pixel(col,row,channel)=dxImage.Pixel(col,row,channel)*weight+rSumImageDx_p.Pixel(col,row,channel)*(1.0-weight);
	      }
	    }
	  } //if type
	} else if(rCountImageDx_p.Pixel(col,row)==0.0 &&
		  (rMask_p.Pixel(col,row)<0.0 || rMask_p.Pixel(col+1,row)<0.0)) {
	  // we are at border of image and dont have values there. Just copy in gradient so if nothing else comes in, we have at least the border
	  for(int channel=0;channel<nChannels;++channel){
	    rSumImageDx_p.Pixel(col,row,channel)=dxImage.Pixel(col,row,channel);
	  }
	  // add if first should win. Otherwise last will win
	  //rCountImageDx_p.Pixel(col,row)=-1.0; // mark as background already occupied
	}
      }  //for col
    }  //for row
    dxImage.AllocateData(0,0); //save some memory
    startAddDx.Stop();

    TimeMessage startDy("Creating Dy");
    // transfer useful dy pixels
    createDyImage(rImage_p,dyImage);
    startDy.Stop();

    TimeMessage startAddDy("Adding Dy");
    for(int row=0;row<nRows-1;++row){
      for(int col=0;col<nCols;++col){
	if(rMask_p.Pixel(col,row)>zeroLimit && rMask_p.Pixel(col,row+1)>zeroLimit) {
	  realType_t weight=(rMask_p.Pixel(col,row)+rMask_p.Pixel(col,row+1))/2.0;
	  if(eType_p==GradientsMergeMosaicType::Average){
	    // type average and inside
	    if(rCountImageDy_p.Pixel(col,row)<=0.0){
	      // first foreground pixel on this location
	      for(int channel=0;channel<nChannels;++channel){
		rSumImageDy_p.Pixel(col,row,channel)=dyImage.Pixel(col,row,channel)*weight;
	      }
	    } else {
	      // we already were there. Blend
	      for(int channel=0;channel<nChannels;++channel){
		rSumImageDy_p.Pixel(col,row,channel)+=dyImage.Pixel(col,row,channel)*weight;
	      }
	    }
	    rCountImageDy_p.Pixel(col,row)+=weight;
	  } else {
	    // type overlay and inside, last gradient wins
	    if(rCountImageDy_p.Pixel(col,row)<=0.0){
	      // first foreground pixel on this location
	      for(int channel=0;channel<nChannels;++channel){
		rSumImageDy_p.Pixel(col,row,channel)=dyImage.Pixel(col,row,channel);
	      }
	      rCountImageDy_p.Pixel(col,row)=1.0; //mark as used
	    } else {
	      // we have been there, merge
	      for(int channel=0;channel<nChannels;++channel){
		rSumImageDy_p.Pixel(col,row,channel)=dyImage.Pixel(col,row,channel)*weight+rSumImageDy_p.Pixel(col,row,channel)*(1.0-weight);
	      }
	    }
	  }  //if type
	} else if(rCountImageDy_p.Pixel(col,row)==0.0 &&
		  (rMask_p.Pixel(col,row)<0.0 || rMask_p.Pixel(col,row+1)<0.0)){
	  // we are outside of image and dont have values there. Just copy in gradient
	  for(int channel=0;channel<nChannels;++channel){
	    rSumImageDy_p.Pixel(col,row,channel)=dyImage.Pixel(col,row,channel);
	  }
	  // add if first should win. Otherwise last will win
	  //rCountImageDy_p.Pixel(col,row)=-1.0;
	}
      } //for col
    } //for row
    startAddDy.Stop();
  }
예제 #18
0
  //static
  void GradientsHdrComposition::hdrCompositionProcessImage(
							   imageType_t const & rImage_p,
							   int imageNum_p,
							   realType_t dBias_p,
							   realType_t dBlackPoint_p,
							   int32 shrinkCount_p,
							   imageType_t &rSumImageDx_p,
							   imageType_t &rSumImageDy_p,
							   numImageType_t &rDxImage_p,
							   numImageType_t &rDyImage_p)
  {
#ifdef DEBUG
    int const nCols=rImage_p.Width();
    int const nRows=rImage_p.Height();
    int const nChannels=rImage_p.NumberOfChannels();
#endif
    Assert(nCols==rSumImageDx_p.Width()+1);
    Assert(nRows==rSumImageDx_p.Height());
    Assert(nChannels==rSumImageDx_p.NumberOfChannels());

    Assert(nCols==rSumImageDy_p.Width());
    Assert(nRows==rSumImageDy_p.Height()+1);
    Assert(nChannels==rSumImageDy_p.NumberOfChannels());

    Assert(nCols==rDxImage_p.Width());
    Assert(nRows==rDxImage_p.Height());
    Assert(nChannels==rDxImage_p.NumberOfChannels());

    Assert(nCols==rDyImage_p.Width());
    Assert(nRows==rDyImage_p.Height());
    Assert(nChannels==rDyImage_p.NumberOfChannels());

    Assert(shrinkCount_p>=0);
    Assert(dBlackPoint_p>=0.0);

    TimeMessage startAddImage("Adding image to data");

    TimeMessage startBiasImage("Applying bias()");
    imageType_t loggedImage=rImage_p;
    loggedImage.ResetSelections();
    loggedImage-=dBias_p;
    startBiasImage.Stop();

    TimeMessage startLogImage("Applying log()");
    logImage(loggedImage,loggedImage);
    startLogImage.Stop();

    // binarize image to find where background is.
    // actual image is then eroded by shrinkCount to make sure
    // that no aliased pixels are part of the image
    weightImageType_t maskImage;
    TimeMessage startBinarize("Binarize Image");
    binarizeImage(rImage_p,dBlackPoint_p,maskImage);
    TimeMessage startShrink("Shrinking mask");
    erodeMask(maskImage,shrinkCount_p);
    startShrink.Stop();

    TimeMessage startAddGradients("Adding gradients data");
    addToImage(loggedImage,imageNum_p,maskImage,rSumImageDx_p,rSumImageDy_p,rDxImage_p,rDyImage_p);
    startAddGradients.Stop();
  }
예제 #19
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();
  }
예제 #20
0
  //static
  void GradientsMergeMosaic::mergeMosaicProcessImage(imageType_t const & rImage_p, realType_t dBlackPoint_p,
						     pcl_enum eType_p,
						     int32 shrinkCount_p,
						     int32 featherRadius_p,
						     imageType_t &rSumImageDx_p,
						     imageType_t &rSumImageDy_p,
						     sumMaskImageType_t &rSumMaskImage_p,
						     weightImageType_t &rCountImageDx_p,
						     weightImageType_t &rCountImageDy_p)
  {
#ifdef DEBUG
    int const nCols=rImage_p.Width();
    int const nRows=rImage_p.Height();
    int const nChannels=rImage_p.NumberOfChannels();
#endif
    Assert(nCols==rSumImageDx_p.Width()+1);
    Assert(nRows==rSumImageDx_p.Height());
    Assert(nChannels==rSumImageDx_p.NumberOfChannels());

    Assert(nCols==rSumImageDy_p.Width());
    Assert(nRows==rSumImageDy_p.Height()+1);
    Assert(nChannels==rSumImageDy_p.NumberOfChannels());

    Assert(nCols==rSumMaskImage_p.Width());
    Assert(nRows==rSumMaskImage_p.Height());
    Assert(1==rSumMaskImage_p.NumberOfChannels());

    Assert(eType_p!=GradientsMergeMosaicType::Average || nCols==rCountImageDx_p.Width()+1);
    Assert(eType_p!=GradientsMergeMosaicType::Average || nRows==rCountImageDx_p.Height());
    Assert(eType_p!=GradientsMergeMosaicType::Average || 1==rCountImageDx_p.NumberOfChannels());
    Assert(eType_p!=GradientsMergeMosaicType::Average || nCols==rCountImageDy_p.Width());
    Assert(eType_p!=GradientsMergeMosaicType::Average || nRows==rCountImageDy_p.Height()+1);
    Assert(eType_p!=GradientsMergeMosaicType::Average || 1==rCountImageDy_p.NumberOfChannels());

    Assert(shrinkCount_p>=0);
    Assert(featherRadius_p>=0);
    Assert(dBlackPoint_p>=0.0);
    weightImageType_t maskImage;

    TimeMessage startAddImage("Adding image to data");

    TimeMessage startBinarize("Binarize Image");
    binarizeImage(rImage_p,dBlackPoint_p,maskImage);
    // save this for border computation later
    weightImageType_t fullMask(maskImage);
    startBinarize.Stop();

    // we are doing this because image after StarAlign usually contain aliased pixels.
    // These must not to be used during merge.
    TimeMessage startShrink("Shrinking mask");
    erodeMask(maskImage,shrinkCount_p);
    startShrink.Stop();
    TimeMessage startFeather("Feathering mask");
    featherMask(maskImage,featherRadius_p);
    startFeather.Stop();

    TimeMessage startBorder("Computing border");
    addBorder(fullMask,maskImage);
    fullMask.AllocateData(0,0); // save memory
    startBorder.Stop();

    TimeMessage startSumMask("Creating combined mask");
    addToMask(maskImage,eType_p,rSumMaskImage_p);
    startSumMask.Stop();
    TimeMessage startAddGradients("Adding gradients data");
    addToImage(rImage_p,eType_p,maskImage,rSumImageDx_p,rSumImageDy_p,rCountImageDx_p, rCountImageDy_p);
    startAddGradients.Stop();
  }