예제 #1
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   S h e a r I m a g e                                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Method ShearImage creates a new image that is a shear_image copy of an
%  existing one.  Shearing slides one edge of an image along the X or Y
%  axis, creating a parallelogram.  An X direction shear slides an edge
%  along the X axis, while a Y direction shear slides an edge along the Y
%  axis.  The amount of the shear is controlled by a shear angle.  For X
%  direction shears, x_shear is measured relative to the Y axis, and
%  similarly, for Y direction shears y_shear is measured relative to the
%  X axis.  Empty triangles left over from shearing the image are filled
%  with the color defined by the pixel at location (0,0).  ShearImage
%  allocates the memory necessary for the new Image structure and returns
%  a pointer to the new image.
%
%  Method ShearImage is based on the paper "A Fast Algorithm for General
%  Raster Rotatation" by Alan W. Paeth.
%
%  The format of the ShearImage method is:
%
%      Image *ShearImage(const Image *image,const double x_shear,
%        const double y_shear,ExceptionInfo *exception)
%
%  A description of each parameter follows.
%
%    o status: Method ShearImage returns a pointer to the image after
%      rotating.  A null image is returned if there is a memory shortage.
%
%    o image: The image;  returned from
%      ReadImage.
%
%    o x_shear, y_shear: Specifies the number of degrees to shear the image.
%
%    o exception: Return any errors or warnings in this structure.
%
%
*/
MagickExport Image *ShearImage(const Image *image,const double x_shear,
  const double y_shear,ExceptionInfo *exception)
{
  Image
    *integral_image,
    *shear_image;

  long
    x_offset,
    y_offset;

  PointInfo
    shear;

  RectangleInfo
    border_info;

  unsigned long
    y_width;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);
  if ((x_shear == 180.0) || (y_shear == 180.0))
    ThrowImageException3(ImageError,UnableToShearImage,AngleIsDiscontinuous);

  /*
    Initialize shear angle.
  */
  integral_image=IntegralRotateImage(image,0,exception);
  if (integral_image == (Image *) NULL)
    ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
      UnableToShearImage);
  shear.x=(-tan(DegreesToRadians(x_shear)/2.0));
  shear.y=sin(DegreesToRadians(y_shear));
  if ((shear.x == 0.0) || (shear.y == 0.0))
    return(integral_image);

  /*
    Compute image size.
  */
  x_offset=(long) ceil(fabs(2.0*image->rows*shear.x)-0.5);
  y_width=(unsigned long) floor(fabs(image->rows*shear.x)+image->columns+0.5);
  y_offset=(long) ceil(fabs(y_width*shear.y)-0.5);
  /*
    Surround image with border.
  */
  integral_image->border_color=integral_image->background_color;
  border_info.width=x_offset;
  border_info.height=y_offset;
  shear_image=BorderImage(integral_image,&border_info,exception);
  if (shear_image == (Image *) NULL)
    ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
      UnableToShearImage);
  DestroyImage(integral_image);
  /*
    Shear the image.
  */
  shear_image->storage_class=DirectClass;
  shear_image->matte|=shear_image->background_color.opacity != OpaqueOpacity;
  XShearImage(shear_image,shear.x,image->columns,image->rows,x_offset,
    (long) (shear_image->rows-image->rows)/2);
  YShearImage(shear_image,shear.y,y_width,image->rows,
    (long) (shear_image->columns-y_width)/2,y_offset);
  CropToFitImage(&shear_image,shear.x,shear.y,image->columns,image->rows,
    False,exception);
  shear_image->page.width=0;
  shear_image->page.height=0;
  return(shear_image);
}
예제 #2
0
파일: average.c 프로젝트: airhuman/cwf
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%     A v e r a g e I m a g e s                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  The Average() method takes a set of images and averages them together.
%  Each image in the set must have the same width and height.  Average()
%  returns a single image with each corresponding pixel component of
%  each image averaged.   On failure, a NULL image is returned and
%  exception describes the reason for the failure.
%
%  The format of the AverageImage method is:
%
%      Image *AverageImages(Image *image,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image: The image sequence.
%
%    o exception: Return any errors or warnings in this structure.
%
%
*/
MagickExport Image *AverageImages(const Image *image,ExceptionInfo *exception)
{
  ThreadViewDataSet
    *pixels_sums;

  Image
    *average_image;

  const Image
    *last_image;

  long
    y;

  unsigned long
    row_count=0;

  double
    number_scenes;
    
  unsigned long
    number_pixels;

  MagickPassFail
    status=MagickPass;

  /*
    Ensure the image are the same size.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);
  if (image->next == (Image *) NULL)
    ThrowImageException3(ImageError,ImageSequenceIsRequired,
                         UnableToAverageImage);
  {
    const Image
      *next;
      
    for (next=image; next != (Image *) NULL; next=next->next)
      {
        if ((next->columns != image->columns) || (next->rows != image->rows))
          ThrowImageException3(OptionError,UnableToAverageImageSequence,
                               ImageWidthsOrHeightsDiffer);
      }
  }
  /*
    Allocate sum accumulation buffer.
  */
  number_pixels=image->columns;
  pixels_sums=AllocateThreadViewDataArray(image,exception,number_pixels,
                                          sizeof(DoublePixelPacket));
  if (pixels_sums == (ThreadViewDataSet *) NULL)
    ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
                         UnableToAverageImageSequence);
  /*
    Initialize average next attributes.
  */
  average_image=CloneImage(image,image->columns,image->rows,True,exception);
  if (average_image == (Image *) NULL)
    {
      DestroyThreadViewDataSet(pixels_sums);
      return((Image *) NULL);
    }
  average_image->storage_class=DirectClass;

  number_scenes=(double) GetImageListLength(image);
  last_image=GetLastImageInList(image);
#if defined(HAVE_OPENMP)
#  pragma omp parallel for schedule(dynamic) shared(row_count, status)
#endif
  for (y=0; y < (long) image->rows; y++)
    {
      register DoublePixelPacket
        *pixels_sum;

      const Image
        *next;

      register const PixelPacket
        *p;

      register long
        x;

      MagickBool
        thread_status;

      thread_status=status;
      if (thread_status == MagickFail)
        continue;

      pixels_sum=AccessThreadViewData(pixels_sums);

      /*
        Compute sum over each pixel color component.
      */
      for (next=image; next != (Image *) NULL; next=next->next)
        {
          ViewInfo
            *next_view;

          next_view=OpenCacheView((Image *) next);
          if (next_view == (ViewInfo *) NULL)
            thread_status=MagickFail;
          if (next_view != (ViewInfo *) NULL)
            {
              p=AcquireCacheViewPixels(next_view,0,y,next->columns,1,exception);
              if (p == (const PixelPacket *) NULL)
                thread_status=MagickFail;
              if (p != (const PixelPacket *) NULL)
                {
                  if (next == image)
                    {
                      for (x=0; x < (long) next->columns; x++)
                        {
                          pixels_sum[x].red=p[x].red;
                          pixels_sum[x].green=p[x].green;
                          pixels_sum[x].blue=p[x].blue;
                          pixels_sum[x].opacity=p[x].opacity;
                        }
                    }
                  else
                    {
                      for (x=0; x < (long) next->columns; x++)
                        {
                          pixels_sum[x].red+=p[x].red;
                          pixels_sum[x].green+=p[x].green;
                          pixels_sum[x].blue+=p[x].blue;
                          pixels_sum[x].opacity+=p[x].opacity;
                        }
                    }
                }
              CloseCacheView(next_view);
            }
        }
      /*
        Average next pixels.
      */
      if (thread_status != MagickFail)
        {
          register PixelPacket
            *q;

          q=SetImagePixelsEx(average_image,0,y,average_image->columns,1,exception);
          if (q == (PixelPacket *) NULL)
            thread_status=MagickFail;
          if (q != (PixelPacket *) NULL)
            {
              for (x=0; x < (long) average_image->columns; x++)
                {
                  q[x].red=(Quantum) (pixels_sum[x].red/number_scenes+0.5);
                  q[x].green=(Quantum) (pixels_sum[x].green/number_scenes+0.5);
                  q[x].blue=(Quantum) (pixels_sum[x].blue/number_scenes+0.5);
                  q[x].opacity=(Quantum) (pixels_sum[x].opacity/number_scenes+0.5);
                }
              if (!SyncImagePixelsEx(average_image,exception))
                thread_status=MagickFail;
            }
        }

#if defined(HAVE_OPENMP)
#  pragma omp critical (GM_AverageImages)
#endif
      {
        row_count++;
        if (QuantumTick(row_count,average_image->rows))
          if (!MagickMonitorFormatted(row_count,average_image->rows,exception,
                                      "[%s,...,%s] Average image sequence...",
                                      image->filename,last_image->filename))
            thread_status=MagickFail;
      
        if (thread_status == MagickFail)
          status=MagickFail;
      }
    }

  DestroyThreadViewDataSet(pixels_sums);

  if (status == MagickFail)
    {
      DestroyImage(average_image);
      average_image=(Image *) NULL;
    }

  return(average_image);
}
예제 #3
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R o t a t e I m a g e                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Method RotateImage creates a new image that is a rotated copy of an
%  existing one.  Positive angles rotate counter-clockwise (right-hand rule),
%  while negative angles rotate clockwise.  Rotated images are usually larger
%  than the originals and have 'empty' triangular corners.  X axis.  Empty
%  triangles left over from shearing the image are filled with the color
%  specified by the image background_color.  RotateImage allocates the memory
%  necessary for the new Image structure and returns a pointer to the new
%  image.
%
%  Method RotateImage is based on the paper "A Fast Algorithm for General
%  Raster Rotatation" by Alan W. Paeth.  RotateImage is adapted from a similar
%  method based on the Paeth paper written by Michael Halle of the Spatial
%  Imaging Group, MIT Media Lab.
%
%  The format of the RotateImage method is:
%
%      Image *RotateImage(const Image *image,const double degrees,
%        ExceptionInfo *exception)
%
%  A description of each parameter follows.
%
%    o status: Method RotateImage returns a pointer to the image after
%      rotating.  A null image is returned if there is a memory shortage.
%
%    o image: The image;  returned from
%      ReadImage.
%
%    o degrees: Specifies the number of degrees to rotate the image.
%
%    o exception: Return any errors or warnings in this structure.
%
%
*/
MagickExport Image *RotateImage(const Image *image,const double degrees,
  ExceptionInfo *exception)
{
  double
    angle;

  Image
    *integral_image,
    *rotate_image;

  long
    x_offset,
    y_offset;

  PointInfo
    shear;

  RectangleInfo
    border_info;

  unsigned long
    height,
    rotations,
    width,
    y_width;

  /*
    Adjust rotation angle.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);
  angle=degrees;
  while (angle < -45.0)
    angle+=360.0;
  for (rotations=0; angle > 45.0; rotations++)
    angle-=90.0;
  rotations%=4;
  /*
    Calculate shear equations.
  */
  integral_image=IntegralRotateImage(image,rotations,exception);
  if (integral_image == (Image *) NULL)
    ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
      UnableToRotateImage);
  shear.x=(-tan(DegreesToRadians(angle)/2.0));
  shear.y=sin(DegreesToRadians(angle));
  if ((shear.x == 0.0) || (shear.y == 0.0))
    return(integral_image);
  /*
    Compute image size.
  */
  width=image->columns;
  height=image->rows;
  if ((rotations == 1) || (rotations == 3))
    {
      width=image->rows;
      height=image->columns;
    }
  x_offset=(long) ceil(fabs(2.0*height*shear.y)-0.5);
  y_width=(unsigned long) floor(fabs(height*shear.x)+width+0.5);
  y_offset=(long) ceil(fabs(y_width*shear.y)-0.5);
  /*
    Surround image with a border.
  */
  integral_image->border_color=integral_image->background_color;
  border_info.width=x_offset;
  border_info.height=y_offset;
  rotate_image=BorderImage(integral_image,&border_info,exception);
  DestroyImage(integral_image);
  if (rotate_image == (Image *) NULL)
    ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
      UnableToRotateImage);
  /*
    Rotate the image.
  */
  rotate_image->storage_class=DirectClass;
  rotate_image->matte|=rotate_image->background_color.opacity != OpaqueOpacity;
  XShearImage(rotate_image,shear.x,width,height,x_offset,
    (long) (rotate_image->rows-height)/2);
  YShearImage(rotate_image,shear.y,y_width,height,
    (long) (rotate_image->columns-y_width)/2,y_offset);
  XShearImage(rotate_image,shear.x,y_width,rotate_image->rows,
    (long) (rotate_image->columns-y_width)/2,0);
  CropToFitImage(&rotate_image,shear.x,shear.y,width,height,True,exception);
  rotate_image->page.width=0;
  rotate_image->page.height=0;
  return(rotate_image);
}