Commit 8324daaf authored by Emmanuel Christophe's avatar Emmanuel Christophe
Browse files

Seam carving

parent b958dcb3
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef __otbAddCarvingPathFilter_h
#define __otbAddCarvingPathFilter_h
#include "itkImageAndPathToImageFilter.h"
#include "itkImageSliceConstIteratorWithIndex.h"
#include "itkImageSliceIteratorWithIndex.h"
namespace otb
{
/** \class AddCarvingPathFilter
* \brief This class add pixels given in one path
*
* This filter add pixels found by the otb::ImageToCarvingPathFilter
* thus increasing the image size.
* the image (if Direction is set to 0) or from left to right
* (if direction is set to 1). Pixel value is computed as the average
* between the neighborhood pixels.
*
* This is one component necessary to apply the seam carving algorithm
* published by Shai Avidan, Ariel Shamir,
* Seam Carving for Content-Aware Image Resizing,
* ACM Transactions on Graphics, Volume 26, Number 3,
* SIGGRAPH 2007
*
* \par INPUTS
* The first input is an image, usually, the same one provided to the
* otb::ImageToCarvingPathFilter
* The second input is a path, typically the output of otb::ImageToCarvingPathFilter.
*
* \par OUTPUTS
* The output is an image with a bigger size than the input image. There is one more
* column if direction is 0 and one more line if direction is 1.
*
* \sa ImageToCarvingPathFilter
*
*
* \ingroup PathFilters
* \ingroup ImageFilters
*/
template <class TInputImage, class TInputPath,class TOutputImage>
class ITK_EXPORT AddCarvingPathFilter : public itk::ImageAndPathToImageFilter<TInputImage,TInputPath,TOutputImage>
{
public:
/** Standard class typedefs. */
typedef AddCarvingPathFilter Self;
typedef itk::ImageAndPathToImageFilter<TInputImage,TInputPath,TOutputImage> Superclass;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** Run-time type information (and related methods). */
itkTypeMacro(AddCarvingPathFilter, itk::ImageAndPathToImageFilter);
/** Some convenient typedefs. */
typedef TInputImage InputImageType;
typedef typename InputImageType::Pointer InputImagePointer;
typedef typename InputImageType::ConstPointer InputImageConstPointer;
typedef typename InputImageType::RegionType InputImageRegionType;
typedef typename InputImageType::PixelType InputImagePixelType;
typedef TInputPath InputPathType;
typedef typename InputPathType::Pointer InputPathPointer;
typedef typename InputPathType::ConstPointer InputPathConstPointer;
typedef typename InputPathType::InputType InputPathInputType;
typedef typename InputPathType::OutputType InputPathOutputType;
typedef typename InputPathType::IndexType InputPathIndexType;
typedef typename InputPathType::OffsetType InputPathOffsetType;
typedef TOutputImage OutputImageType;
typedef typename OutputImageType::Pointer OutputImagePointer;
typedef typename OutputImageType::ConstPointer OutputImageConstPointer;
typedef typename OutputImageType::RegionType OutputImageRegionType;
typedef typename OutputImageType::PixelType OutputImagePixelType;
typedef typename OutputImageType::ValueType OutputImageValueType;
// typedef typename itk::ImageRegionConstIterator<InputImageType> InputIteratorType;
// typedef typename itk::ImageRegionIterator<OutputImageType> OutputIteratorType;
typedef typename itk::ImageSliceConstIteratorWithIndex<InputImageType> InputIteratorType;
typedef typename itk::ImageSliceIteratorWithIndex<OutputImageType> OutputIteratorType;
itkSetMacro(Value, OutputImagePixelType);
itkGetConstReferenceMacro(Value, OutputImagePixelType);
/** Set and Get direction value */
itkSetMacro(Direction ,unsigned int);
itkGetConstMacro(Direction ,unsigned int);
virtual void GenerateOutputInformation();
virtual void GenerateInputRequestedRegion();
protected:
AddCarvingPathFilter();
virtual ~AddCarvingPathFilter() {};
virtual void PrintSelf(std::ostream& os, itk::Indent indent) const;
virtual void GenerateData();
private:
AddCarvingPathFilter(const Self&); //purposely not implemented
void operator=(const Self&); //purposely not implemented
OutputImagePixelType m_Value;
unsigned int m_Direction;
};
} // end namespace otb
#ifndef OTB_MANUAL_INSTANTIATION
#include "otbAddCarvingPathFilter.txx"
#endif
#endif
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef __otbAddCarvingPathFilter_txx
#define __otbAddCarvingPathFilter_txx
#include "otbAddCarvingPathFilter.h"
namespace otb
{
/**
* Constructor
*/
template <class TInputImage, class TInputPath,class TOutputImage>
AddCarvingPathFilter<TInputImage,TInputPath,TOutputImage>
::AddCarvingPathFilter()
{
m_Value = static_cast<OutputImagePixelType>(255.0);
m_Direction = 0;
}
/**
* Main computation method.
*/
template <class TInputImage, class TInputPath,class TOutputImage>
void
AddCarvingPathFilter<TInputImage,TInputPath,TOutputImage>
::GenerateData(void)
{
const InputImageType * inputImage = this->GetInput();
OutputImageType * outputImage = this->GetOutput();
InputPathType * inputPath = static_cast<const InputPathType *>
(this->itk::ProcessObject::GetInput(1));
outputImage->SetBufferedRegion( outputImage->GetRequestedRegion() );
outputImage->Allocate();
InputIteratorType inputIterator(inputImage,
inputImage->GetLargestPossibleRegion());
OutputIteratorType outputIterator(outputImage,
outputImage->GetLargestPossibleRegion());
unsigned int dir0;
unsigned int dir1;
if (m_Direction == 0)
{
dir0=0;
dir1=1;
}
else
{
dir0=1;
dir1=0;
}
inputIterator.SetFirstDirection( dir0 );
inputIterator.SetSecondDirection( dir1 );
inputIterator.GoToBegin();
outputIterator.SetFirstDirection( dir0 );
outputIterator.SetSecondDirection( dir1 );
outputIterator.GoToBegin();
int line=-1;
typename InputImageType::IndexType index;
typename InputPathType::VertexListType::ConstPointer vertexList = inputPath->GetVertexList();
typename InputPathType::VertexListType::ConstIterator pathIterator;
typename InputImageType::IndexType indexToAdd;
typename InputImageType::SizeType inputSize;
inputSize = inputImage->GetLargestPossibleRegion().GetSize();
//go to the end of the path
pathIterator = vertexList->Begin();
while(pathIterator != vertexList->End())
{
++pathIterator;
}
--pathIterator;
while (!outputIterator.IsAtEnd())
{
while (!outputIterator.IsAtEndOfSlice())
{
bool flag = false;
while(!outputIterator.IsAtEndOfLine())
{
index = outputIterator.GetIndex();
if(index[dir1] != line)
{
line = index[dir1];
typename InputImageType::PointType tmpIndex;
inputImage->TransformContinuousIndexToPhysicalPoint(pathIterator.Value(),tmpIndex);
inputImage->TransformPhysicalPointToIndex(tmpIndex,indexToAdd);
--pathIterator;
if(index[dir1] != indexToAdd[dir1])
{
std::cout << "Error : " << index[dir1] << " , " << indexToAdd[dir1] << std::endl;
}
}
if (flag || ((index[dir0] != indexToAdd[dir0]) && (index[dir0] < inputSize[dir0])))
{
outputIterator.Set(inputIterator.Get());
++inputIterator;
}
else
{
// std::cout << "Adding the value at " << outputIterator.GetIndex() << std::endl;
flag = true;
// std::cout << "[" << index[0] << "," << index[1] << "] ";
OutputImagePixelType newValue;
newValue = (--inputIterator).Get();
newValue += (++inputIterator).Get();
newValue /= 2;
// newValue = 0; //TODO just for test
outputIterator.Set(newValue);
}
++outputIterator;
}
if((outputIterator.GetIndex())[dir0] != (inputIterator.GetIndex())[dir0]+1)
{
std::cout << "Error 2: "<< (outputIterator.GetIndex())[dir0] << " , " << (inputIterator.GetIndex())[dir0] << std::endl;
}
inputIterator.NextLine();
outputIterator.NextLine();
}
inputIterator.NextSlice();
outputIterator.NextSlice();
}
}
/**
* Printself Method
*/
template <class TInputImage, class TInputPath,class TOutputImage>
void
AddCarvingPathFilter<TInputImage,TInputPath,TOutputImage>
::PrintSelf(std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf(os, indent);
os << indent << "Path Value: " << m_Value << std::endl;
}
template <class TInputImage, class TInputPath,class TOutputImage>
void
AddCarvingPathFilter<TInputImage,TInputPath,TOutputImage>
::GenerateOutputInformation()
{
// call the superclass' implementation of this method
Superclass::GenerateOutputInformation();
// get pointers to the input and output
typename Superclass::InputImageConstPointer inputPtr = this->GetInput();
typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
unsigned int dir0;
unsigned int dir1;
if (m_Direction == 0)
{
dir0=0;
dir1=1;
}
else
{
dir0=1;
dir1=0;
}
// we need to compute the output spacing, the output image size, and the
// output image start index
const typename TInputImage::SpacingType&
inputSpacing = inputPtr->GetSpacing();
const typename TInputImage::SizeType& inputSize
= inputPtr->GetLargestPossibleRegion().GetSize();
const typename TInputImage::IndexType& inputStartIndex
= inputPtr->GetLargestPossibleRegion().GetIndex();
typename TOutputImage::SpacingType outputSpacing;
typename TOutputImage::SizeType outputSize;
typename TOutputImage::IndexType outputStartIndex;
for (unsigned int i = 0; i < TOutputImage::ImageDimension; i++)
{
outputSpacing[i] = inputSpacing[i];
outputSize[i] = (unsigned int) (inputSize[i]);
outputStartIndex[i] = inputStartIndex[i];
}
// we remove one column of the image
outputSize[dir0] = inputSize[dir0] + 1;
outputPtr->SetSpacing( outputSpacing );
typename TOutputImage::RegionType outputLargestPossibleRegion;
outputLargestPossibleRegion.SetSize( outputSize );
outputLargestPossibleRegion.SetIndex( outputStartIndex );
outputPtr->SetLargestPossibleRegion( outputLargestPossibleRegion );
}
template <class TInputImage, class TInputPath,class TOutputImage>
void
AddCarvingPathFilter<TInputImage,TInputPath,TOutputImage>
::GenerateInputRequestedRegion()
{
// call the superclass' implementation of this method
Superclass::GenerateInputRequestedRegion();
// get pointers to the input and output
InputImagePointer inputPtr =
const_cast< InputImageType * >( this->GetInput() );
if ( !inputPtr )
{
itkExceptionMacro( << "Input has not been set." );
}
inputPtr->SetRequestedRegion( inputPtr->GetLargestPossibleRegion() );
}
} // end namespace otb
#endif
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef __otbImageToCarvingPathFilter_h
#define __otbImageToCarvingPathFilter_h
#include "otbImageToPathFilter.h"
#include "itkImageSliceConstIteratorWithIndex.h"
namespace otb {
/**
* \class ImageToCarvingPathFilter
* \brief This filter find the minimum energy path of an image.
*
* This filter find the minimum energy path from top to bottom of
* the image (if Direction is set to 0) or from left to right
* (if direction is set to 1).
*
* This is one component necessary to apply the seam carving algorithm
* published by Shai Avidan, Ariel Shamir,
* Seam Carving for Content-Aware Image Resizing,
* ACM Transactions on Graphics, Volume 26, Number 3,
* SIGGRAPH 2007
*
* \par INPUTS
* The input is an image, typically the output of a gradient filter.
*
* \par OUTPUTS
* The output is
* a polyline parametric path comprising one and only one pixel per line
* (resp. column) if direction is 0 (resp. 1).
*
* \sa RemoveCarvingPathFilter
*
* \ingroup PathFilters
* \ingroup ImageFilters
*/
template <class TInputImage, class TOutputPath>
class ITK_EXPORT ImageToCarvingPathFilter
: public ImageToPathFilter<TInputImage, TOutputPath>
{
public:
/** standards typedefs */
typedef ImageToCarvingPathFilter Self;
typedef ImageToPathFilter<TInputImage, TOutputPath> Superclass;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
/// Creation througth the object factory
itkNewMacro(Self);
/// Runtime information
itkTypeMacro(ImageToCarvingPathFilter,ImageToPathFilter);
/// Template parameters typedef
typedef typename Superclass::InputImageType InputImageType;
typedef typename Superclass::InputImagePointerType InputImagePointerType;
typedef typename Superclass::OutputPathType OutputPathType;
typedef typename Superclass::OutputPathPointerType OutputPathPointerType;
typedef typename InputImageType::PixelType PixelType;
/** Set and Get foreground value */
itkSetMacro(ForegroundValue,PixelType);
itkGetConstMacro(ForegroundValue,PixelType);
/** Set and Get direction value */
itkSetMacro(Direction ,unsigned int);
itkGetConstMacro(Direction ,unsigned int);
/** Get EnergyPerPix value */
itkGetConstMacro(EnergyPerPix ,double);
protected:
ImageToCarvingPathFilter();
virtual ~ImageToCarvingPathFilter(){};
virtual void PrintSelf(std::ostream& os, itk::Indent indent) const;
virtual void GenerateOutputInformation() {}; //does nothing
virtual void GenerateData();
private:
ImageToCarvingPathFilter(const Self&); // purposely not implemented
void operator=(const Self&); // purposely not implemented
PixelType m_ForegroundValue;
unsigned int m_Direction;
double m_EnergyPerPix;
};
} // end namespace otb
#ifndef OTB_MANUAL_INSTANTIATION
#include "otbImageToCarvingPathFilter.txx"
#endif
#endif
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef _otbImageToCarvingPathFilter_txx
#define _otbImageToCarvingPathFilter_txx
#include "otbImageToCarvingPathFilter.h"
#include "otbMacro.h"
#include "itkConstantPadImageFilter.h"
#include "itkConstShapedNeighborhoodIterator.h"
#include "itkImageRegionConstIterator.h"
#include "itkNumericTraits.h"
#include "itkImageLinearConstIteratorWithIndex.h"
namespace otb
{
/*
* Constructor.
*/
template <class TInputImage, class TOutputPath>
ImageToCarvingPathFilter<TInputImage, TOutputPath>
::ImageToCarvingPathFilter()
{
m_ForegroundValue = PixelType(255);
m_Direction = 0;
m_EnergyPerPix = 0.0;
}
/**
* Main computation method.
*/
template <class TInputImage, class TOutputPath>
void
ImageToCarvingPathFilter<TInputImage, TOutputPath>
::GenerateData(void)
{
const InputImageType * inputImage = this->GetInput();
OutputPathType * outputPath = this->GetOutput();
typedef itk::ImageSliceConstIteratorWithIndex
<InputImageType> IteratorType;
typedef itk::NeighborhoodIterator< InputImageType >
NeighborhoodIteratorType;
IteratorType it(inputImage,
inputImage->GetLargestPossibleRegion());
it.GoToBegin();
PixelType maxValue = itk::NumericTraits< PixelType >::max();
typename InputImageType::Pointer energyImage = InputImageType::New();
energyImage->SetRegions(inputImage-> GetLargestPossibleRegion());
energyImage->Allocate();
typename NeighborhoodIteratorType::RadiusType radius;
radius.Fill(1);
NeighborhoodIteratorType neighIt(radius, energyImage,
energyImage-> GetLargestPossibleRegion() );
neighIt.GoToBegin();
unsigned int dir0;
unsigned int dir1;
typename IteratorType::OffsetType UP0;
typename IteratorType::OffsetType UP1;
typename IteratorType::OffsetType UP2;
typename IteratorType::OffsetType NEXT;
if (m_Direction == 0)
{
dir0=0;
dir1=1;
const typename IteratorType::OffsetType LEFT ={{-1,0}};
const typename IteratorType::OffsetType RIGHT ={{1,0}};
const typename IteratorType::OffsetType UP ={{0,-1}};
const typename IteratorType::OffsetType DOWN ={{0,1}};
const typename IteratorType::OffsetType LEFTUP ={{-1,-1}};
const typename IteratorType::OffsetType RIGHTDOWN ={{1,1}};
const typename IteratorType::OffsetType RIGHTUP ={{1,-1}};
const typename IteratorType::OffsetType LEFTDOWN ={{-1,1}};
const typename IteratorType::OffsetType CENTER ={{0,0}};
UP0 = LEFTUP;
UP1 = UP;
UP2 = RIGHTUP;
NEXT = DOWN;
}
else
{
dir0=1;
dir1=0;
const typename IteratorType::OffsetType LEFT ={{-1,0}};
const typename IteratorType::OffsetType RIGHT ={{1,0}};
const typename IteratorType::OffsetType UP ={{0,-1}};
const typename IteratorType::OffsetType DOWN ={{0,1}};
const typename IteratorType::OffsetType LEFTUP ={{-1,-1}};
const typename IteratorType::OffsetType RIGHTDOWN ={{1,1}};
const typename IteratorType::OffsetType RIGHTUP ={{1,-1}};
const typename IteratorType::OffsetType LEFTDOWN ={{-1,1}};
const typename IteratorType::OffsetType CENTER ={{0,0}};
UP0 = LEFTUP;
UP1 = LEFT;
UP2 = LEFTDOWN;
NEXT = RIGHT;
}