예제 #1
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%     C y c l e C o l o r m a p I m a g e                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  CycleColormap() displaces an image's colormap by a given number of
%  positions.  If you cycle the colormap a number of times you can produce
%  a psychodelic effect.
%
%  The format of the CycleColormapImage method is:
%
%      MagickBooleanType CycleColormapImage(Image *image,const ssize_t displace)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o displace:  displace the colormap this amount.
%
*/
MagickExport MagickBooleanType CycleColormapImage(Image *image,
  const ssize_t displace)
{
  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (image->storage_class == DirectClass)
    (void) SetImageType(image,PaletteType);
  status=MagickTrue;
  exception=(&image->exception);
  image_view=AcquireCacheView(image);
#if defined(MAGICKCORE_OPENMP_SUPPORT) 
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register IndexPacket
      *restrict indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    ssize_t
      index;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      index=(ssize_t) (GetIndexPixelComponent(indexes+x)+displace) %
        image->colors;
      if (index < 0)
        index+=(ssize_t) image->colors;
      SetIndexPixelComponent(indexes+x,index);
      SetRGBOPixelComponents(q,image->colormap+(ssize_t) index);
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}
예제 #2
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   a n a l y z e I m a g e                                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  analyzeImage() computes the brightness and saturation mean,  standard
%  deviation, kurtosis and skewness and stores these values as attributes 
%  of the image.
%
%  The format of the analyzeImage method is:
%
%      unsigned long analyzeImage(Image *images,const int argc,
%        char **argv,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image: the address of a structure of type Image.
%
%    o argc: Specifies a pointer to an integer describing the number of
%      elements in the argument vector.
%
%    o argv: Specifies a pointer to a text array containing the command line
%      arguments.
%
%    o exception: return any errors or warnings in this structure.
%
*/
ModuleExport unsigned long analyzeImage(Image **images,const int argc,
  const char **argv,ExceptionInfo *exception)
{
  CacheView
    *cache_view;

  char
    text[MaxTextExtent];

  double
    area,
    brightness_mean,
    brightness_standard_deviation,
    brightness_kurtosis,
    brightness_skewness,
    brightness_sum_x,
    brightness_sum_x2,
    brightness_sum_x3,
    brightness_sum_x4,
    saturation_mean,
    saturation_standard_deviation,
    saturation_kurtosis,
    saturation_skewness,
    saturation_sum_x,
    saturation_sum_x2,
    saturation_sum_x3,
    saturation_sum_x4;

  double
    brightness,
    hue,
    saturation;

  Image
    *image;

  long
    y;

  register const PixelPacket
    *p;

  register long
    x;

  assert(images != (Image **) NULL);
  assert(*images != (Image *) NULL);
  assert((*images)->signature == MagickSignature);
  (void) argc;
  (void) argv;
  image=(*images);
  for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
  {
    brightness_sum_x=0.0;
    brightness_sum_x2=0.0;
    brightness_sum_x3=0.0;
    brightness_sum_x4=0.0;
    brightness_mean=0.0;
    brightness_standard_deviation=0.0;
    brightness_kurtosis=0.0;
    brightness_skewness=0.0;
    saturation_sum_x=0.0;
    saturation_sum_x2=0.0;
    saturation_sum_x3=0.0;
    saturation_sum_x4=0.0;
    saturation_mean=0.0;
    saturation_standard_deviation=0.0;
    saturation_kurtosis=0.0;
    saturation_skewness=0.0;
    area=0.0;
    cache_view=AcquireCacheView(image);
    for (y=0; y < (long) image->rows; y++)
    {
      p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
      if (p == (const PixelPacket *) NULL)
        break;
      for (x=0; x < (long) image->columns; x++)
      {
        ConvertRGBToHSB(p->red,p->green,p->blue,&hue,&saturation,&brightness);
        brightness*=QuantumRange;
        brightness_sum_x+=brightness;
        brightness_sum_x2+=brightness*brightness;
        brightness_sum_x3+=brightness*brightness*brightness;
        brightness_sum_x4+=brightness*brightness*brightness*brightness;
        saturation*=QuantumRange;
        saturation_sum_x+=saturation;
        saturation_sum_x2+=saturation*saturation;
        saturation_sum_x3+=saturation*saturation*saturation;
        saturation_sum_x4+=saturation*saturation*saturation*saturation;
        area++;
        p++;
      }
    }
    cache_view=DestroyCacheView(image_view);
    if (area <= 0.0)
      break;
    brightness_mean=brightness_sum_x/area;
    (void) FormatMagickString(text,MaxTextExtent,"%g",brightness_mean);
    (void) SetImageProperty(image,"filter:brightness:mean",text);
    brightness_standard_deviation=sqrt(brightness_sum_x2/area-(brightness_sum_x/
      area*brightness_sum_x/area));
    (void) FormatMagickString(text,MaxTextExtent,"%g",
      brightness_standard_deviation);
    (void) SetImageProperty(image,"filter:brightness:standard-deviation",text);
    if (brightness_standard_deviation != 0)
      brightness_kurtosis=(brightness_sum_x4/area-4.0*brightness_mean*
        brightness_sum_x3/area+6.0*brightness_mean*brightness_mean*
        brightness_sum_x2/area-3.0*brightness_mean*brightness_mean*
        brightness_mean*brightness_mean)/(brightness_standard_deviation*
        brightness_standard_deviation*brightness_standard_deviation*
        brightness_standard_deviation)-3.0;
    (void) FormatMagickString(text,MaxTextExtent,"%g",brightness_kurtosis);
    (void) SetImageProperty(image,"filter:brightness:kurtosis",text);
    if (brightness_standard_deviation != 0)
      brightness_skewness=(brightness_sum_x3/area-3.0*brightness_mean*
        brightness_sum_x2/area+2.0*brightness_mean*brightness_mean*
        brightness_mean)/(brightness_standard_deviation*
        brightness_standard_deviation*brightness_standard_deviation);
    (void) FormatMagickString(text,MaxTextExtent,"%g",brightness_skewness);
    (void) SetImageProperty(image,"filter:brightness:skewness",text);
    saturation_mean=saturation_sum_x/area;
    (void) FormatMagickString(text,MaxTextExtent,"%g",saturation_mean);
    (void) SetImageProperty(image,"filter:saturation:mean",text);
    saturation_standard_deviation=sqrt(saturation_sum_x2/area-(saturation_sum_x/
      area*saturation_sum_x/area));
    (void) FormatMagickString(text,MaxTextExtent,"%g",
      saturation_standard_deviation);
    (void) SetImageProperty(image,"filter:saturation:standard-deviation",text);
    if (saturation_standard_deviation != 0)
      saturation_kurtosis=(saturation_sum_x4/area-4.0*saturation_mean*
        saturation_sum_x3/area+6.0*saturation_mean*saturation_mean*
        saturation_sum_x2/area-3.0*saturation_mean*saturation_mean*
        saturation_mean*saturation_mean)/(saturation_standard_deviation*
        saturation_standard_deviation*saturation_standard_deviation*
        saturation_standard_deviation)-3.0;
    (void) FormatMagickString(text,MaxTextExtent,"%g",saturation_kurtosis);
    (void) SetImageProperty(image,"filter:saturation:kurtosis",text);
    if (saturation_standard_deviation != 0)
      saturation_skewness=(saturation_sum_x3/area-3.0*saturation_mean*
        saturation_sum_x2/area+2.0*saturation_mean*saturation_mean*
        saturation_mean)/(saturation_standard_deviation*
        saturation_standard_deviation*saturation_standard_deviation);
    (void) FormatMagickString(text,MaxTextExtent,"%g",saturation_skewness);
    (void) SetImageProperty(image,"filter:saturation:skewness",text);
  }
  return(MagickImageFilterSignature);
}
예제 #3
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   G e t I m a g e T o t a l I n k D e n s i t y                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetImageTotalInkDensity() returns the total ink density for a CMYK image.
%  Total Ink Density (TID) is determined by adding the CMYK values in the
%  darkest shadow area in an image.
%
%  The format of the GetImageTotalInkDensity method is:
%
%      double GetImageTotalInkDensity(const Image *image)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
*/
MagickExport double GetImageTotalInkDensity(Image *image)
{
  double
    total_ink_density;

  ExceptionInfo
    *exception;

  long
    y;

  MagickBooleanType
    status;

  CacheView
    *image_view;

  assert(image != (Image *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(image->signature == MagickSignature);
  if (image->colorspace != CMYKColorspace)
    {
      (void) ThrowMagickException(&image->exception,GetMagickModule(),
        ImageError,"ColorSeparatedImageRequired","`%s'",image->filename);
      return(0.0);
    }
  status=MagickTrue;
  total_ink_density=0.0;
  exception=(&image->exception);
  image_view=AcquireCacheView(image);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (y=0; y < (long) image->rows; y++)
  {
    double
      density;

    register const IndexPacket
      *indexes;

    register const PixelPacket
      *p;

    register long
      x;

    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    if (p == (const PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewVirtualIndexQueue(image_view);
    for (x=0; x < (long) image->columns; x++)
    {
      density=(double) p->red+p->green+p->blue+indexes[x];
      if (density > total_ink_density)
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp critical (MagickCore_GetImageTotalInkDensity)
#endif
        {
          if (density > total_ink_density)
            total_ink_density=density;
        }
      p++;
    }
  }
  image_view=DestroyCacheView(image_view);
  if (status == MagickFalse)
    total_ink_density=0.0;
  return(total_ink_density);
}
예제 #4
0
MagickExport MagickBooleanType OpaquePaintImageChannel(Image *image,
  const ChannelType channel,const MagickPixelPacket *target,
  const MagickPixelPacket *fill,const MagickBooleanType invert)
{
#define OpaquePaintImageTag  "Opaque/Image"

  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  MagickPixelPacket
    zero;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(target != (MagickPixelPacket *) NULL);
  assert(fill != (MagickPixelPacket *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  /*
    Make image color opaque.
  */
  status=MagickTrue;
  progress=0;
  exception=(&image->exception);
  GetMagickPixelPacket(image,&zero);
  image_view=AcquireCacheView(image);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    MagickPixelPacket
      pixel;

    register IndexPacket
      *restrict indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    pixel=zero;
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      SetMagickPixelPacket(image,q,indexes+x,&pixel);
      if (IsMagickColorSimilar(&pixel,target) != invert)
        {
          if ((channel & RedChannel) != 0)
            SetPixelRed(q,ClampToQuantum(fill->red));
          if ((channel & GreenChannel) != 0)
            SetPixelGreen(q,ClampToQuantum(fill->green));
          if ((channel & BlueChannel) != 0)
            SetPixelBlue(q,ClampToQuantum(fill->blue));
          if ((channel & OpacityChannel) != 0)
            SetPixelOpacity(q,ClampToQuantum(fill->opacity));
          if (((channel & IndexChannel) != 0) &&
              (image->colorspace == CMYKColorspace))
            SetPixelIndex(indexes+x,ClampToQuantum(fill->index));
        }
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp critical (MagickCore_OpaquePaintImageChannel)
#endif
        proceed=SetImageProgress(image,OpaquePaintImageTag,progress++,
          image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}
예제 #5
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%     T r a n s p a r e n t P a i n t I m a g e                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  TransparentPaintImage() changes the opacity value associated with any pixel
%  that matches color to the value defined by opacity.
%
%  By default color must match a particular pixel color exactly.  However,
%  in many cases two colors may differ by a small amount.  Fuzz defines
%  how much tolerance is acceptable to consider two colors as the same.
%  For example, set fuzz to 10 and the color red at intensities of 100 and
%  102 respectively are now interpreted as the same color.
%
%  The format of the TransparentPaintImage method is:
%
%      MagickBooleanType TransparentPaintImage(Image *image,
%        const MagickPixelPacket *target,const Quantum opacity,
%        const MagickBooleanType invert)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o target: the target color.
%
%    o opacity: the replacement opacity value.
%
%    o invert: paint any pixel that does not match the target color.
%
*/
MagickExport MagickBooleanType TransparentPaintImage(Image *image,
  const MagickPixelPacket *target,const Quantum opacity,
  const MagickBooleanType invert)
{
#define TransparentPaintImageTag  "Transparent/Image"

  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  MagickPixelPacket
    zero;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(target != (MagickPixelPacket *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  if (image->matte == MagickFalse)
    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
  /*
    Make image color transparent.
  */
  status=MagickTrue;
  progress=0;
  exception=(&image->exception);
  GetMagickPixelPacket(image,&zero);
  image_view=AcquireCacheView(image);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    MagickPixelPacket
      pixel;

    register IndexPacket
      *restrict indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    pixel=zero;
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      SetMagickPixelPacket(image,q,indexes+x,&pixel);
      if (IsMagickColorSimilar(&pixel,target) != invert)
        q->opacity=opacity;
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp critical (MagickCore_TransparentPaintImage)
#endif
        proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
          image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}
예제 #6
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   a n a l y z e I m a g e                                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  analyzeImage() computes the brightness and saturation mean,  standard
%  deviation, kurtosis and skewness and stores these values as attributes
%  of the image.
%
%  The format of the analyzeImage method is:
%
%      size_t analyzeImage(Image *images,const int argc,
%        char **argv,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image: the address of a structure of type Image.
%
%    o argc: Specifies a pointer to an integer describing the number of
%      elements in the argument vector.
%
%    o argv: Specifies a pointer to a text array containing the command line
%      arguments.
%
%    o exception: return any errors or warnings in this structure.
%
*/
ModuleExport size_t analyzeImage(Image **images,const int argc,
                                 const char **argv,ExceptionInfo *exception)
{
    char
    text[MaxTextExtent];

    double
    area,
    brightness,
    brightness_mean,
    brightness_standard_deviation,
    brightness_kurtosis,
    brightness_skewness,
    brightness_sum_x,
    brightness_sum_x2,
    brightness_sum_x3,
    brightness_sum_x4,
    hue,
    saturation,
    saturation_mean,
    saturation_standard_deviation,
    saturation_kurtosis,
    saturation_skewness,
    saturation_sum_x,
    saturation_sum_x2,
    saturation_sum_x3,
    saturation_sum_x4;

    Image
    *image;

    assert(images != (Image **) NULL);
    assert(*images != (Image *) NULL);
    assert((*images)->signature == MagickSignature);
    (void) argc;
    (void) argv;
    image=(*images);
    for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
    {
        CacheView
        *image_view;

        ssize_t
        y;

        MagickBooleanType
        status;

        brightness_sum_x=0.0;
        brightness_sum_x2=0.0;
        brightness_sum_x3=0.0;
        brightness_sum_x4=0.0;
        brightness_mean=0.0;
        brightness_standard_deviation=0.0;
        brightness_kurtosis=0.0;
        brightness_skewness=0.0;
        saturation_sum_x=0.0;
        saturation_sum_x2=0.0;
        saturation_sum_x3=0.0;
        saturation_sum_x4=0.0;
        saturation_mean=0.0;
        saturation_standard_deviation=0.0;
        saturation_kurtosis=0.0;
        saturation_skewness=0.0;
        area=0.0;
        status=MagickTrue;
        image_view=AcquireCacheView(image);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
        #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
        for (y=0; y < (ssize_t) image->rows; y++)
        {
            register const PixelPacket
            *p;

            register ssize_t
            x;

            if (status == MagickFalse)
                continue;
            p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
            if (p == (const PixelPacket *) NULL)
            {
                status=MagickFalse;
                continue;
            }
            for (x=0; x < (ssize_t) image->columns; x++)
            {
                ConvertRGBToHSB(GetRedPixelComponent(p),GetGreenPixelComponent(p),GetBluePixelComponent(p),&hue,&saturation,&brightness);
                brightness*=QuantumRange;
                brightness_sum_x+=brightness;
                brightness_sum_x2+=brightness*brightness;
                brightness_sum_x3+=brightness*brightness*brightness;
                brightness_sum_x4+=brightness*brightness*brightness*brightness;
                saturation*=QuantumRange;
                saturation_sum_x+=saturation;
                saturation_sum_x2+=saturation*saturation;
                saturation_sum_x3+=saturation*saturation*saturation;
                saturation_sum_x4+=saturation*saturation*saturation*saturation;
                area++;
                p++;
            }
        }
        image_view=DestroyCacheView(image_view);
        if (area <= 0.0)
            break;
        brightness_mean=brightness_sum_x/area;
        (void) FormatLocaleString(text,MaxTextExtent,"%g",brightness_mean);
        (void) SetImageProperty(image,"filter:brightness:mean",text);
        brightness_standard_deviation=sqrt(brightness_sum_x2/area-(brightness_sum_x/
                                           area*brightness_sum_x/area));
        (void) FormatLocaleString(text,MaxTextExtent,"%g",
                                  brightness_standard_deviation);
        (void) SetImageProperty(image,"filter:brightness:standard-deviation",text);
        if (brightness_standard_deviation != 0)
            brightness_kurtosis=(brightness_sum_x4/area-4.0*brightness_mean*
                                 brightness_sum_x3/area+6.0*brightness_mean*brightness_mean*
                                 brightness_sum_x2/area-3.0*brightness_mean*brightness_mean*
                                 brightness_mean*brightness_mean)/(brightness_standard_deviation*
                                         brightness_standard_deviation*brightness_standard_deviation*
                                         brightness_standard_deviation)-3.0;
        (void) FormatLocaleString(text,MaxTextExtent,"%g",brightness_kurtosis);
        (void) SetImageProperty(image,"filter:brightness:kurtosis",text);
        if (brightness_standard_deviation != 0)
            brightness_skewness=(brightness_sum_x3/area-3.0*brightness_mean*
                                 brightness_sum_x2/area+2.0*brightness_mean*brightness_mean*
                                 brightness_mean)/(brightness_standard_deviation*
                                                   brightness_standard_deviation*brightness_standard_deviation);
        (void) FormatLocaleString(text,MaxTextExtent,"%g",brightness_skewness);
        (void) SetImageProperty(image,"filter:brightness:skewness",text);
        saturation_mean=saturation_sum_x/area;
        (void) FormatLocaleString(text,MaxTextExtent,"%g",saturation_mean);
        (void) SetImageProperty(image,"filter:saturation:mean",text);
        saturation_standard_deviation=sqrt(saturation_sum_x2/area-(saturation_sum_x/
                                           area*saturation_sum_x/area));
        (void) FormatLocaleString(text,MaxTextExtent,"%g",
                                  saturation_standard_deviation);
        (void) SetImageProperty(image,"filter:saturation:standard-deviation",text);
        if (saturation_standard_deviation != 0)
            saturation_kurtosis=(saturation_sum_x4/area-4.0*saturation_mean*
                                 saturation_sum_x3/area+6.0*saturation_mean*saturation_mean*
                                 saturation_sum_x2/area-3.0*saturation_mean*saturation_mean*
                                 saturation_mean*saturation_mean)/(saturation_standard_deviation*
                                         saturation_standard_deviation*saturation_standard_deviation*
                                         saturation_standard_deviation)-3.0;
        (void) FormatLocaleString(text,MaxTextExtent,"%g",saturation_kurtosis);
        (void) SetImageProperty(image,"filter:saturation:kurtosis",text);
        if (saturation_standard_deviation != 0)
            saturation_skewness=(saturation_sum_x3/area-3.0*saturation_mean*
                                 saturation_sum_x2/area+2.0*saturation_mean*saturation_mean*
                                 saturation_mean)/(saturation_standard_deviation*
                                                   saturation_standard_deviation*saturation_standard_deviation);
        (void) FormatLocaleString(text,MaxTextExtent,"%g",saturation_skewness);
        (void) SetImageProperty(image,"filter:saturation:skewness",text);
    }
    return(MagickImageFilterSignature);
}
예제 #7
0
MagickExport Image *OilPaintImage(const Image *image,const double radius,
  ExceptionInfo *exception)
{
#define NumberPaintBins  256
#define OilPaintImageTag  "OilPaint/Image"

  CacheView
    *image_view,
    *paint_view;

  Image
    *paint_image;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  size_t
    **restrict histograms,
    width;

  ssize_t
    y;

  /*
    Initialize painted image attributes.
  */
  assert(image != (const Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);
  width=GetOptimalKernelWidth2D(radius,0.5);
  paint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
  if (paint_image == (Image *) NULL)
    return((Image *) NULL);
  if (SetImageStorageClass(paint_image,DirectClass) == MagickFalse)
    {
      InheritException(exception,&paint_image->exception);
      paint_image=DestroyImage(paint_image);
      return((Image *) NULL);
    }
  histograms=AcquireHistogramThreadSet(NumberPaintBins);
  if (histograms == (size_t **) NULL)
    {
      paint_image=DestroyImage(paint_image);
      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
    }
  /*
    Oil paint image.
  */
  status=MagickTrue;
  progress=0;
  image_view=AcquireCacheView(image);
  paint_view=AcquireCacheView(paint_image);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register const IndexPacket
      *restrict indexes;

    register const PixelPacket
      *restrict p;

    register IndexPacket
      *restrict paint_indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    register size_t
      *histogram;

    if (status == MagickFalse)
      continue;
    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
      (width/2L),image->columns+width,width,exception);
    q=QueueCacheViewAuthenticPixels(paint_view,0,y,paint_image->columns,1,
      exception);
    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewVirtualIndexQueue(image_view);
    paint_indexes=GetCacheViewAuthenticIndexQueue(paint_view);
    histogram=histograms[GetOpenMPThreadId()];
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      register ssize_t
        i,
        u;

      size_t
        count;

      ssize_t
        j,
        k,
        v;

      /*
        Assign most frequent color.
      */
      i=0;
      j=0;
      count=0;
      (void) ResetMagickMemory(histogram,0,NumberPaintBins*sizeof(*histogram));
      for (v=0; v < (ssize_t) width; v++)
      {
        for (u=0; u < (ssize_t) width; u++)
        {
          k=(ssize_t) ScaleQuantumToChar(PixelIntensityToQuantum(p+u+i));
          histogram[k]++;
          if (histogram[k] > count)
            {
              j=i+u;
              count=histogram[k];
            }
        }
        i+=(ssize_t) (image->columns+width);
      }
      *q=(*(p+j));
      if (image->colorspace == CMYKColorspace)
        SetPixelIndex(paint_indexes+x,GetPixelIndex(
          indexes+x+j));
      p++;
      q++;
    }
    if (SyncCacheViewAuthenticPixels(paint_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp critical (MagickCore_OilPaintImage)
#endif
        proceed=SetImageProgress(image,OilPaintImageTag,progress++,image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  paint_view=DestroyCacheView(paint_view);
  image_view=DestroyCacheView(image_view);
  histograms=DestroyHistogramThreadSet(histograms);
  if (status == MagickFalse)
    paint_image=DestroyImage(paint_image);
  return(paint_image);
}
예제 #8
0
파일: paint.c 프로젝트: 0xPr0xy/ImageMagick
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%     T r a n s p a r e n t P a i n t I m a g e C h r o m a                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  TransparentPaintImageChroma() changes the opacity value associated with any
%  pixel that matches color to the value defined by opacity.
%
%  As there is one fuzz value for the all the channels, the
%  TransparentPaintImage() API is not suitable for the operations like chroma,
%  where the tolerance for similarity of two color component (RGB) can be
%  different, Thus we define this method take two target pixels (one
%  low and one hight) and all the pixels of an image which are lying between
%  these two pixels are made transparent.
%
%  The format of the TransparentPaintImage method is:
%
%      MagickBooleanType TransparentPaintImage(Image *image,
%        const MagickPixelPacket *low,const MagickPixelPacket *hight,
%        const Quantum opacity,const MagickBooleanType invert)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o low: the low target color.
%
%    o high: the high target color.
%
%    o opacity: the replacement opacity value.
%
%    o invert: paint any pixel that does not match the target color.
%
*/
MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
  const MagickPixelPacket *low,const MagickPixelPacket *high,
  const Quantum opacity,const MagickBooleanType invert)
{
#define TransparentPaintImageTag  "Transparent/Image"

  ExceptionInfo
    *exception;

  long
    progress,
    y;

  MagickBooleanType
    status;

  CacheView
    *image_view;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(high != (MagickPixelPacket *) NULL);
  assert(low != (MagickPixelPacket *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  if (image->matte == MagickFalse)
    (void) SetImageAlphaChannel(image,ResetAlphaChannel);
  /*
    Make image color transparent.
  */
  status=MagickTrue;
  progress=0;
  exception=(&image->exception);
  image_view=AcquireCacheView(image);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
  for (y=0; y < (long) image->rows; y++)
  {
    MagickBooleanType
      match;

    MagickPixelPacket
      pixel;

    register IndexPacket
      *__restrict indexes;

    register long
      x;

    register PixelPacket
      *__restrict q;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    GetMagickPixelPacket(image,&pixel);
    for (x=0; x < (long) image->columns; x++)
    {
      SetMagickPixelPacket(image,q,indexes+x,&pixel);
      match=((pixel.red >= low->red) && (pixel.red <= high->red) &&
        (pixel.green >= low->green) && (pixel.green <= high->green) &&
        (pixel.blue  >= low->blue) && (pixel.blue <= high->blue)) ?
        MagickTrue : MagickFalse;
      if (match != invert)
        q->opacity=opacity;
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp critical (MagickCore_TransparentPaintImageChroma)
#endif
        proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
          image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}
예제 #9
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   S i g n a t u r e I m a g e                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  SignatureImage() computes a message digest from an image pixel stream with
%  an implementation of the NIST SHA-256 Message Digest algorithm.  This
%  signature uniquely identifies the image and is convenient for determining
%  if an image has been modified or whether two images are identical.
%
%  The format of the SignatureImage method is:
%
%      MagickBooleanType SignatureImage(Image *image)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
*/
MagickExport MagickBooleanType SignatureImage(Image *image)
{
  CacheView
    *image_view;

  char
    *hex_signature;

  ExceptionInfo
    *exception;

  ssize_t
    y;

  QuantumInfo
    *quantum_info;

  QuantumType
    quantum_type;

  register const PixelPacket
    *p;

  SignatureInfo
    *signature_info;

  size_t
    length;

  StringInfo
    *signature;

  unsigned char
    *pixels;

  /*
    Compute image digital signature.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
  if (quantum_info == (QuantumInfo *) NULL)
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  quantum_type=RGBQuantum;
  if (image->matte != MagickFalse)
    quantum_type=RGBAQuantum;
  if (image->colorspace == CMYKColorspace)
    {
      quantum_type=CMYKQuantum;
      if (image->matte != MagickFalse)
        quantum_type=CMYKAQuantum;
    }
  signature_info=AcquireSignatureInfo();
  signature=AcquireStringInfo(quantum_info->extent);
  pixels=GetQuantumPixels(quantum_info);
  exception=(&image->exception);
  image_view=AcquireCacheView(image);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    if (p == (const PixelPacket *) NULL)
      break;
    length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
      pixels,&image->exception);
    SetStringInfoLength(signature,length);
    SetStringInfoDatum(signature,pixels);
    UpdateSignature(signature_info,signature);
  }
  image_view=DestroyCacheView(image_view);
  quantum_info=DestroyQuantumInfo(quantum_info);
  FinalizeSignature(signature_info);
  hex_signature=StringInfoToHexString(GetSignatureDigest(signature_info));
  (void) DeleteImageProperty(image,"signature");
  (void) SetImageProperty(image,"signature",hex_signature);
  /*
    Free resources.
  */
  hex_signature=DestroyString(hex_signature);
  signature=DestroyStringInfo(signature);
  signature_info=DestroySignatureInfo(signature_info);
  return(MagickTrue);
}
예제 #10
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   F r a m e I m a g e                                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  FrameImage() adds a simulated three-dimensional border around the image.
%  The color of the border is defined by the matte_color member of image.
%  Members width and height of frame_info specify the border width of the
%  vertical and horizontal sides of the frame.  Members inner and outer
%  indicate the width of the inner and outer shadows of the frame.
%
%  The format of the FrameImage method is:
%
%      Image *FrameImage(const Image *image,const FrameInfo *frame_info,
%        ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o frame_info: Define the width and height of the frame and its bevels.
%
%    o exception: return any errors or warnings in this structure.
%
*/
MagickExport Image *FrameImage(const Image *image,const FrameInfo *frame_info,
  ExceptionInfo *exception)
{
#define FrameImageTag  "Frame/Image"

  CacheView
    *image_view,
    *frame_view;

  Image
    *frame_image;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  MagickPixelPacket
    accentuate,
    border,
    highlight,
    interior,
    matte,
    shadow,
    trough;

  register ssize_t
    x;

  size_t
    bevel_width,
    height,
    width;

  ssize_t
    y;

  /*
    Check frame geometry.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(frame_info != (FrameInfo *) NULL);
  if ((frame_info->outer_bevel < 0) || (frame_info->inner_bevel < 0))
    ThrowImageException(OptionError,"FrameIsLessThanImageSize");
  bevel_width=(size_t) (frame_info->outer_bevel+frame_info->inner_bevel);
  width=frame_info->width-frame_info->x-bevel_width;
  height=frame_info->height-frame_info->y-bevel_width;
  if ((width < image->columns) || (height < image->rows))
    ThrowImageException(OptionError,"FrameIsLessThanImageSize");
  /*
    Initialize framed image attributes.
  */
  frame_image=CloneImage(image,frame_info->width,frame_info->height,MagickTrue,
    exception);
  if (frame_image == (Image *) NULL)
    return((Image *) NULL);
  if (SetImageStorageClass(frame_image,DirectClass) == MagickFalse)
    {
      InheritException(exception,&frame_image->exception);
      frame_image=DestroyImage(frame_image);
      return((Image *) NULL);
    }
  if (frame_image->matte_color.opacity != OpaqueOpacity)
    frame_image->matte=MagickTrue;
  frame_image->page=image->page;
  if ((image->page.width != 0) && (image->page.height != 0))
    {
      frame_image->page.width+=frame_image->columns-image->columns;
      frame_image->page.height+=frame_image->rows-image->rows;
    }
  /*
    Initialize 3D effects color.
  */
  GetMagickPixelPacket(frame_image,&interior);
  SetMagickPixelPacket(frame_image,&image->border_color,(IndexPacket *) NULL,
    &interior);
  GetMagickPixelPacket(frame_image,&matte);
  matte.colorspace=RGBColorspace;
  SetMagickPixelPacket(frame_image,&image->matte_color,(IndexPacket *) NULL,
    &matte);
  GetMagickPixelPacket(frame_image,&border);
  border.colorspace=RGBColorspace;
  SetMagickPixelPacket(frame_image,&image->border_color,(IndexPacket *) NULL,
    &border);
  GetMagickPixelPacket(frame_image,&accentuate);
  accentuate.red=(MagickRealType) (QuantumScale*((QuantumRange-
    AccentuateModulate)*matte.red+(QuantumRange*AccentuateModulate)));
  accentuate.green=(MagickRealType) (QuantumScale*((QuantumRange-
    AccentuateModulate)*matte.green+(QuantumRange*AccentuateModulate)));
  accentuate.blue=(MagickRealType) (QuantumScale*((QuantumRange-
    AccentuateModulate)*matte.blue+(QuantumRange*AccentuateModulate)));
  accentuate.opacity=matte.opacity;
  GetMagickPixelPacket(frame_image,&highlight);
  highlight.red=(MagickRealType) (QuantumScale*((QuantumRange-
    HighlightModulate)*matte.red+(QuantumRange*HighlightModulate)));
  highlight.green=(MagickRealType) (QuantumScale*((QuantumRange-
    HighlightModulate)*matte.green+(QuantumRange*HighlightModulate)));
  highlight.blue=(MagickRealType) (QuantumScale*((QuantumRange-
    HighlightModulate)*matte.blue+(QuantumRange*HighlightModulate)));
  highlight.opacity=matte.opacity;
  GetMagickPixelPacket(frame_image,&shadow);
  shadow.red=QuantumScale*matte.red*ShadowModulate;
  shadow.green=QuantumScale*matte.green*ShadowModulate;
  shadow.blue=QuantumScale*matte.blue*ShadowModulate;
  shadow.opacity=matte.opacity;
  GetMagickPixelPacket(frame_image,&trough);
  trough.red=QuantumScale*matte.red*TroughModulate;
  trough.green=QuantumScale*matte.green*TroughModulate;
  trough.blue=QuantumScale*matte.blue*TroughModulate;
  trough.opacity=matte.opacity;
  if (image->colorspace == CMYKColorspace)
    {
      ConvertRGBToCMYK(&interior);
      ConvertRGBToCMYK(&matte);
      ConvertRGBToCMYK(&border);
      ConvertRGBToCMYK(&accentuate);
      ConvertRGBToCMYK(&highlight);
      ConvertRGBToCMYK(&shadow);
      ConvertRGBToCMYK(&trough);
    }
  status=MagickTrue;
  progress=0;
  image_view=AcquireCacheView(image);
  frame_view=AcquireCacheView(frame_image);
  height=(size_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
    frame_info->inner_bevel);
  if (height != 0)
    {
      register IndexPacket
        *restrict frame_indexes;

      register ssize_t
        x;

      register PixelPacket
        *restrict q;

      /*
        Draw top of ornamental border.
      */
      q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns,
        height,exception);
      frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view);
      if (q != (PixelPacket *) NULL)
        {
          /*
            Draw top of ornamental border.
          */
          for (y=0; y < (ssize_t) frame_info->outer_bevel; y++)
          {
            for (x=0; x < (ssize_t) (frame_image->columns-y); x++)
            {
              if (x < y)
                SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              else
                SetPixelPacket(frame_image,&accentuate,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for ( ; x < (ssize_t) frame_image->columns; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          for (y=0; y < (ssize_t) (frame_info->y-bevel_width); y++)
          {
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            width=frame_image->columns-2*frame_info->outer_bevel;
            for (x=0; x < (ssize_t) width; x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          for (y=0; y < (ssize_t) frame_info->inner_bevel; y++)
          {
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            width=image->columns+((size_t) frame_info->inner_bevel << 1)-
              y;
            for (x=0; x < (ssize_t) width; x++)
            {
              if (x < y)
                SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              else
                SetPixelPacket(frame_image,&trough,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            width=frame_info->width-frame_info->x-image->columns-bevel_width;
            for (x=0; x < (ssize_t) width; x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          (void) SyncCacheViewAuthenticPixels(frame_view,exception);
        }
    }
  /*
    Draw sides of ornamental border.
  */
#if defined(MAGICKCORE_OPENMP_SUPPORT) 
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register IndexPacket
      *restrict frame_indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    /*
      Initialize scanline with matte color.
    */
    if (status == MagickFalse)
      continue;
    q=QueueCacheViewAuthenticPixels(frame_view,0,frame_info->y+y,
      frame_image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view);
    for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
    {
      SetPixelPacket(frame_image,&highlight,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
    {
      SetPixelPacket(frame_image,&matte,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
    {
      SetPixelPacket(frame_image,&shadow,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    /*
      Set frame interior to interior color.
    */
    if ((image->compose != CopyCompositeOp) &&
        ((image->compose != OverCompositeOp) || (image->matte != MagickFalse)))
      for (x=0; x < (ssize_t) image->columns; x++)
      {
        SetPixelPacket(frame_image,&interior,q,frame_indexes);
        q++;
        frame_indexes++;
      }
    else
      {
        register const IndexPacket
          *indexes;

        register const PixelPacket
          *p;

        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
        if (p == (const PixelPacket *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        indexes=GetCacheViewVirtualIndexQueue(image_view);
        (void) CopyMagickMemory(q,p,image->columns*sizeof(*p));
        if ((image->colorspace == CMYKColorspace) &&
            (frame_image->colorspace == CMYKColorspace))
          {
            (void) CopyMagickMemory(frame_indexes,indexes,image->columns*
              sizeof(*indexes));
            frame_indexes+=image->columns;
          }
        q+=image->columns;
      }
    for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
    {
      SetPixelPacket(frame_image,&highlight,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    width=frame_info->width-frame_info->x-image->columns-bevel_width;
    for (x=0; x < (ssize_t) width; x++)
    {
      SetPixelPacket(frame_image,&matte,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
    {
      SetPixelPacket(frame_image,&shadow,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    if (SyncCacheViewAuthenticPixels(frame_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT) 
  #pragma omp critical (MagickCore_FrameImage)
#endif
        proceed=SetImageProgress(image,FrameImageTag,progress++,image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  height=(size_t) (frame_info->inner_bevel+frame_info->height-
    frame_info->y-image->rows-bevel_width+frame_info->outer_bevel);
  if (height != 0)
    {
      register IndexPacket
        *restrict frame_indexes;

      register ssize_t
        x;

      register PixelPacket
        *restrict q;

      /*
        Draw bottom of ornamental border.
      */
      q=QueueCacheViewAuthenticPixels(frame_view,0,(ssize_t) (frame_image->rows-
        height),frame_image->columns,height,exception);
      if (q != (PixelPacket *) NULL)
        {
          /*
            Draw bottom of ornamental border.
          */
          frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view);
          for (y=frame_info->inner_bevel-1; y >= 0; y--)
          {
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < y; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
            {
              if (x >= (ssize_t) (image->columns+2*frame_info->inner_bevel-y))
                SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              else
                SetPixelPacket(frame_image,&accentuate,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            width=frame_info->width-frame_info->x-image->columns-bevel_width;
            for (x=0; x < (ssize_t) width; x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          height=frame_info->height-frame_info->y-image->rows-bevel_width;
          for (y=0; y < (ssize_t) height; y++)
          {
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            width=frame_image->columns-2*frame_info->outer_bevel;
            for (x=0; x < (ssize_t) width; x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          for (y=frame_info->outer_bevel-1; y >= 0; y--)
          {
            for (x=0; x < y; x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for ( ; x < (ssize_t) frame_image->columns; x++)
            {
              if (x >= (ssize_t) (frame_image->columns-y))
                SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              else
                SetPixelPacket(frame_image,&trough,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          (void) SyncCacheViewAuthenticPixels(frame_view,exception);
        }
    }
  frame_view=DestroyCacheView(frame_view);
  image_view=DestroyCacheView(image_view);
  if ((image->compose != CopyCompositeOp) &&
      ((image->compose != OverCompositeOp) || (image->matte != MagickFalse)))
    {
      x=(ssize_t) (frame_info->outer_bevel+(frame_info->x-bevel_width)+
        frame_info->inner_bevel);
      y=(ssize_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
        frame_info->inner_bevel);
      (void) CompositeImage(frame_image,image->compose,image,x,y);
    }
  return(frame_image);
}
예제 #11
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R a i s e I m a g e                                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  RaiseImage() creates a simulated three-dimensional button-like effect
%  by lightening and darkening the edges of the image.  Members width and
%  height of raise_info define the width of the vertical and horizontal
%  edge of the effect.
%
%  The format of the RaiseImage method is:
%
%      MagickBooleanType RaiseImage(const Image *image,
%        const RectangleInfo *raise_info,const MagickBooleanType raise)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o raise_info: Define the width and height of the raise area.
%
%    o raise: A value other than zero creates a 3-D raise effect,
%      otherwise it has a lowered effect.
%
*/
MagickExport MagickBooleanType RaiseImage(Image *image,
  const RectangleInfo *raise_info,const MagickBooleanType raise)
{
#define AccentuateFactor  ScaleCharToQuantum(135)
#define HighlightFactor  ScaleCharToQuantum(190)
#define ShadowFactor  ScaleCharToQuantum(190)
#define RaiseImageTag  "Raise/Image"
#define TroughFactor  ScaleCharToQuantum(135)

  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  Quantum
    foreground,
    background;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(raise_info != (RectangleInfo *) NULL);
  if ((image->columns <= (raise_info->width << 1)) ||
      (image->rows <= (raise_info->height << 1)))
    ThrowBinaryException(OptionError,"ImageSizeMustExceedBevelWidth",
      image->filename);
  foreground=(Quantum) QuantumRange;
  background=(Quantum) 0;
  if (raise == MagickFalse)
    {
      foreground=(Quantum) 0;
      background=(Quantum) QuantumRange;
    }
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  /*
    Raise image.
  */
  status=MagickTrue;
  progress=0;
  exception=(&image->exception);
  image_view=AcquireCacheView(image);
#if defined(MAGICKCORE_OPENMP_SUPPORT) 
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
  for (y=0; y < (ssize_t) raise_info->height; y++)
  {
    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    for (x=0; x < y; x++)
    {
      q->red=ClampToQuantum(QuantumScale*((MagickRealType) q->red*
        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
        HighlightFactor)));
      q->green=ClampToQuantum(QuantumScale*((MagickRealType) q->green*
        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
        HighlightFactor)));
      q->blue=ClampToQuantum(QuantumScale*((MagickRealType) q->blue*
        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
        HighlightFactor)));
      q++;
    }
    for ( ; x < (ssize_t) (image->columns-y); x++)
    {
      q->red=ClampToQuantum(QuantumScale*((MagickRealType) q->red*
        AccentuateFactor+(MagickRealType) foreground*(QuantumRange-
        AccentuateFactor)));
      q->green=ClampToQuantum(QuantumScale*((MagickRealType) q->green*
        AccentuateFactor+(MagickRealType) foreground*(QuantumRange-
        AccentuateFactor)));
      q->blue=ClampToQuantum(QuantumScale*((MagickRealType) q->blue*
        AccentuateFactor+(MagickRealType) foreground*(QuantumRange-
        AccentuateFactor)));
      q++;
    }
    for ( ; x < (ssize_t) image->columns; x++)
    {
      q->red=ClampToQuantum(QuantumScale*((MagickRealType) q->red*ShadowFactor+
        (MagickRealType) background*(QuantumRange-ShadowFactor)));
      q->green=ClampToQuantum(QuantumScale*((MagickRealType) q->green*
        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
      q->blue=ClampToQuantum(QuantumScale*((MagickRealType) q->blue*
        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

        proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
  for (y=(ssize_t) raise_info->height; y < (ssize_t) (image->rows-raise_info->height); y++)
  {
    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    for (x=0; x < (ssize_t) raise_info->width; x++)
    {
      q->red=ClampToQuantum(QuantumScale*((MagickRealType) q->red*
        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
        HighlightFactor)));
      q->green=ClampToQuantum(QuantumScale*((MagickRealType) q->green*
        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
        HighlightFactor)));
      q->blue=ClampToQuantum(QuantumScale*((MagickRealType) q->blue*
        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
        HighlightFactor)));
      q++;
    }
    for ( ; x < (ssize_t) (image->columns-raise_info->width); x++)
      q++;
    for ( ; x < (ssize_t) image->columns; x++)
    {
      q->red=ClampToQuantum(QuantumScale*((MagickRealType) q->red*ShadowFactor+
        (MagickRealType) background*(QuantumRange-ShadowFactor)));
      q->green=ClampToQuantum(QuantumScale*((MagickRealType) q->green*
        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
      q->blue=ClampToQuantum(QuantumScale*((MagickRealType) q->blue*
        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

        proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
#if defined(MAGICKCORE_OPENMP_SUPPORT) 
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
  for (y=(ssize_t) (image->rows-raise_info->height); y < (ssize_t) image->rows; y++)
  {
    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    for (x=0; x < (ssize_t) (image->rows-y); x++)
    {
      q->red=ClampToQuantum(QuantumScale*((MagickRealType) q->red*
        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
        HighlightFactor)));
      q->green=ClampToQuantum(QuantumScale*((MagickRealType) q->green*
        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
        HighlightFactor)));
      q->blue=ClampToQuantum(QuantumScale*((MagickRealType) q->blue*
        HighlightFactor+(MagickRealType) foreground*(QuantumRange-
        HighlightFactor)));
      q++;
    }
    for ( ; x < (ssize_t) (image->columns-(image->rows-y)); x++)
    {
      q->red=ClampToQuantum(QuantumScale*((MagickRealType) q->red*TroughFactor+
        (MagickRealType) background*(QuantumRange-TroughFactor)));
      q->green=ClampToQuantum(QuantumScale*((MagickRealType) q->green*
        TroughFactor+(MagickRealType) background*(QuantumRange-TroughFactor)));
      q->blue=ClampToQuantum(QuantumScale*((MagickRealType) q->blue*
        TroughFactor+(MagickRealType) background*(QuantumRange-TroughFactor)));
      q++;
    }
    for ( ; x < (ssize_t) image->columns; x++)
    {
      q->red=ClampToQuantum(QuantumScale*((MagickRealType) q->red*ShadowFactor+
        (MagickRealType) background*(QuantumRange-ShadowFactor)));
      q->green=ClampToQuantum(QuantumScale*((MagickRealType) q->green*
        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
      q->blue=ClampToQuantum(QuantumScale*((MagickRealType) q->blue*
        ShadowFactor+(MagickRealType) background*(QuantumRange-ShadowFactor)));
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp critical (MagickCore_RaiseImage)
#endif
        proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}
예제 #12
0
static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
  const Image *magnitude_image,const Image *phase_image,fftw_complex *fourier,
  ExceptionInfo *exception)
{
  CacheView
    *magnitude_view,
    *phase_view;

  double
    *magnitude,
    *phase,
    *magnitude_source,
    *phase_source;

  long
    y;

  MagickBooleanType
    status;

  register const IndexPacket
    *indexes;

  register const PixelPacket
    *p;

  register long
    i,
    x;

  /*
    Inverse fourier - read image and break down into a double array.
  */
  magnitude_source=(double *) AcquireQuantumMemory((size_t)
    fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
  if (magnitude_source == (double *) NULL)
    {
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",
        magnitude_image->filename);
      return(MagickFalse);
    }
  phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
    fourier_info->height*sizeof(*phase_source));
  if (phase_source == (double *) NULL)
    {
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",
        magnitude_image->filename);
      magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
      return(MagickFalse);
    }
  i=0L;
  magnitude_view=AcquireCacheView(magnitude_image);
  for (y=0L; y < (long) fourier_info->height; y++)
  {
    p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
      exception);
    if (p == (const PixelPacket *) NULL)
      break;
    indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
    for (x=0L; x < (long) fourier_info->width; x++)
    {
      switch (fourier_info->channel)
      {
        case RedChannel:
        default:
        {
          magnitude_source[i]=QuantumScale*GetRedPixelComponent(p);
          break;
        }
        case GreenChannel:
        {
          magnitude_source[i]=QuantumScale*GetGreenPixelComponent(p);
          break;
        }
        case BlueChannel:
        {
          magnitude_source[i]=QuantumScale*GetBluePixelComponent(p);
          break;
        }
        case OpacityChannel:
        {
          magnitude_source[i]=QuantumScale*GetOpacityPixelComponent(p);
          break;
        }
        case IndexChannel:
        {
          magnitude_source[i]=QuantumScale*indexes[x];
          break;
        }
        case GrayChannels:
        {
          magnitude_source[i]=QuantumScale*GetRedPixelComponent(p);
          break;
        }
      }
      i++;
      p++;
    }
  }
  i=0L;
  phase_view=AcquireCacheView(phase_image);
  for (y=0L; y < (long) fourier_info->height; y++)
  {
    p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
      exception);
    if (p == (const PixelPacket *) NULL)
      break;
    indexes=GetCacheViewAuthenticIndexQueue(phase_view);
    for (x=0L; x < (long) fourier_info->width; x++)
    {
      switch (fourier_info->channel)
      {
        case RedChannel:
        default:
        {
          phase_source[i]=QuantumScale*GetRedPixelComponent(p);
          break;
        }
        case GreenChannel:
        {
          phase_source[i]=QuantumScale*GetGreenPixelComponent(p);
          break;
        }
        case BlueChannel:
        {
          phase_source[i]=QuantumScale*GetBluePixelComponent(p);
          break;
        }
        case OpacityChannel:
        {
          phase_source[i]=QuantumScale*GetOpacityPixelComponent(p);
          break;
        }
        case IndexChannel:
        {
          phase_source[i]=QuantumScale*indexes[x];
          break;
        }
        case GrayChannels:
        {
          phase_source[i]=QuantumScale*GetRedPixelComponent(p);
          break;
        }
      }
      i++;
      p++;
    }
  }
  if (fourier_info->modulus != MagickFalse)
    {
      i=0L;
      for (y=0L; y < (long) fourier_info->height; y++)
        for (x=0L; x < (long) fourier_info->width; x++)
        {
          phase_source[i]-=0.5;
          phase_source[i]*=(2.0*MagickPI);
          i++;
        }
    }
  magnitude_view=DestroyCacheView(magnitude_view);
  phase_view=DestroyCacheView(phase_view);
  magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
    fourier_info->center*sizeof(*magnitude));
  if (magnitude == (double *) NULL)
    {
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",
        magnitude_image->filename);
      magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
      phase_source=(double *) RelinquishMagickMemory(phase_source);
      return(MagickFalse);
    }
  status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
    magnitude_source,magnitude);
  magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
  phase=(double *) AcquireQuantumMemory((size_t) fourier_info->width,
    fourier_info->height*sizeof(*phase));
  if (phase == (double *) NULL)
    {
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",
        magnitude_image->filename);
      phase_source=(double *) RelinquishMagickMemory(phase_source);
      return(MagickFalse);
    }
  CorrectPhaseLHS(fourier_info->width,fourier_info->width,phase_source);
  if (status != MagickFalse)
    status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
      phase_source,phase);
  phase_source=(double *) RelinquishMagickMemory(phase_source);
  /*
    Merge two sets.
  */
  i=0L;
  if (fourier_info->modulus != MagickFalse)
    for (y=0L; y < (long) fourier_info->height; y++)
       for (x=0L; x < (long) fourier_info->center; x++)
       {
#if defined(MAGICKCORE_HAVE_COMPLEX_H)
         fourier[i]=magnitude[i]*cos(phase[i])+I*magnitude[i]*sin(phase[i]);
#else
         fourier[i][0]=magnitude[i]*cos(phase[i]);
         fourier[i][1]=magnitude[i]*sin(phase[i]);
#endif
         i++;
      }
  else
    for (y=0L; y < (long) fourier_info->height; y++)
      for (x=0L; x < (long) fourier_info->center; x++)
      {
#if defined(MAGICKCORE_HAVE_COMPLEX_H)
        fourier[i]=magnitude[i]+I*phase[i];
#else
        fourier[i][0]=magnitude[i];
        fourier[i][1]=phase[i];
#endif
        i++;
      }
  phase=(double *) RelinquishMagickMemory(phase);
  magnitude=(double *) RelinquishMagickMemory(magnitude);
  return(status);
}
예제 #13
0
static MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
  const Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
{
  CacheView
    *image_view;

  double
    n,
    *source;

  fftw_complex
    *fourier;

  fftw_plan
    fftw_r2c_plan;

  long
    y;

  register const IndexPacket
    *indexes;

  register const PixelPacket
    *p;

  register long
    i,
    x;

  /*
    Generate the forward Fourier transform.
  */
  source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
    fourier_info->width*sizeof(*source));
  if (source == (double *) NULL)
    {
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
      return(MagickFalse);
    }
  ResetMagickMemory(source,0,fourier_info->width*fourier_info->height*
    sizeof(*source));
  i=0L;
  image_view=AcquireCacheView(image);
  for (y=0L; y < (long) fourier_info->height; y++)
  {
    p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
      exception);
    if (p == (const PixelPacket *) NULL)
      break;
    indexes=GetCacheViewVirtualIndexQueue(image_view);
    for (x=0L; x < (long) fourier_info->width; x++)
    {
      switch (fourier_info->channel)
      {
        case RedChannel:
        default:
        {
          source[i]=QuantumScale*GetRedPixelComponent(p);
          break;
        }
        case GreenChannel:
        {
          source[i]=QuantumScale*GetGreenPixelComponent(p);
          break;
        }
        case BlueChannel:
        {
          source[i]=QuantumScale*GetBluePixelComponent(p);
          break;
        }
        case OpacityChannel:
        {
          source[i]=QuantumScale*GetOpacityPixelComponent(p);
          break;
        }
        case IndexChannel:
        {
          source[i]=QuantumScale*indexes[x];
          break;
        }
        case GrayChannels:
        {
          source[i]=QuantumScale*GetRedPixelComponent(p);
          break;
        }
      }
      i++;
      p++;
    }
  }
  image_view=DestroyCacheView(image_view);
  fourier=(fftw_complex *) AcquireAlignedMemory((size_t) fourier_info->height,
    fourier_info->center*sizeof(*fourier));
  if (fourier == (fftw_complex *) NULL)
    {
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
      source=(double *) RelinquishMagickMemory(source);
      return(MagickFalse);
    }
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp critical (MagickCore_ForwardFourierTransform)
#endif
  fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->width,
    source,fourier,FFTW_ESTIMATE);
  fftw_execute(fftw_r2c_plan);
  fftw_destroy_plan(fftw_r2c_plan);
  source=(double *) RelinquishMagickMemory(source);
  /*
    Normalize Fourier transform.
  */
  n=(double) fourier_info->width*(double) fourier_info->width;
  i=0L;
  for (y=0L; y < (long) fourier_info->height; y++)
    for (x=0L; x < (long) fourier_info->center; x++)
    {
#if defined(MAGICKCORE_HAVE_COMPLEX_H)
      fourier[i]/=n;
#else
      fourier[i][0]/=n;
      fourier[i][1]/=n;
#endif
      i++;
    }
  /*
    Generate magnitude and phase (or real and imaginary).
  */
  i=0L;
  if (fourier_info->modulus != MagickFalse)
    for (y=0L; y < (long) fourier_info->height; y++)
      for (x=0L; x < (long) fourier_info->center; x++)
      {
        magnitude[i]=cabs(fourier[i]);
        phase[i]=carg(fourier[i]);
        i++;
      }
  else
    for (y=0L; y < (long) fourier_info->height; y++)
      for (x=0L; x < (long) fourier_info->center; x++)
      {
        magnitude[i]=creal(fourier[i]);
        phase[i]=cimag(fourier[i]);
        i++;
      }
  fourier=(fftw_complex *) RelinquishAlignedMemory(fourier);
  return(MagickTrue);
}
예제 #14
0
static MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
  Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
{
  CacheView
    *magnitude_view,
    *phase_view;

  double
    *magnitude_source,
    *phase_source;

  Image
    *magnitude_image,
    *phase_image;

  long
    i,
    y;

  MagickBooleanType
    status;

  register IndexPacket
    *indexes;

  register long
    x;

  register PixelPacket
    *q;

  magnitude_image=GetFirstImageInList(image);
  phase_image=GetNextImageInList(image);
  if (phase_image == (Image *) NULL)
    {
      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
        "ImageSequenceRequired","`%s'",image->filename);
      return(MagickFalse);
    }
  /*
    Create "Fourier Transform" image from constituent arrays.
  */
  magnitude_source=(double *) AcquireQuantumMemory((size_t)
    fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
  if (magnitude_source == (double *) NULL)
    return(MagickFalse);
  (void) ResetMagickMemory(magnitude_source,0,fourier_info->width*
    fourier_info->height*sizeof(*magnitude_source));
  phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
    fourier_info->width*sizeof(*phase_source));
  if (magnitude_source == (double *) NULL)
    {
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
      magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
      return(MagickFalse);
    }
  status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,
    magnitude,magnitude_source);
  if (status != MagickFalse)
    status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,phase,
      phase_source);
  CorrectPhaseLHS(fourier_info->height,fourier_info->height,phase_source);
  if (fourier_info->modulus != MagickFalse)
    {
      i=0L;
      for (y=0L; y < (long) fourier_info->height; y++)
        for (x=0L; x < (long) fourier_info->width; x++)
        {
          phase_source[i]/=(2.0*MagickPI);
          phase_source[i]+=0.5;
          i++;
        }
    }
  magnitude_view=AcquireCacheView(magnitude_image);
  phase_view=AcquireCacheView(phase_image);
  i=0L;
  for (y=0L; y < (long) fourier_info->height; y++)
  {
    q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->height,1UL,
      exception);
    if (q == (PixelPacket *) NULL)
      break;
    indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
    for (x=0L; x < (long) fourier_info->width; x++)
    {
      switch (fourier_info->channel)
      {
        case RedChannel:
        default:
        {
          q->red=ClampToQuantum(QuantumRange*magnitude_source[i]);
          break;
        }
        case GreenChannel:
        {
          q->green=ClampToQuantum(QuantumRange*magnitude_source[i]);
          break;
        }
        case BlueChannel:
        {
          q->blue=ClampToQuantum(QuantumRange*magnitude_source[i]);
          break;
        }
        case OpacityChannel:
        {
          q->opacity=ClampToQuantum(QuantumRange*magnitude_source[i]);
          break;
        }
        case IndexChannel:
        {
          indexes[x]=ClampToQuantum(QuantumRange*magnitude_source[i]);
          break;
        }
        case GrayChannels:
        {
          q->red=ClampToQuantum(QuantumRange*magnitude_source[i]);
          q->green=q->red;
          q->blue=q->red;
          break;
        }
      }
      i++;
      q++;
    }
    status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
    if (status == MagickFalse)
      break;
  }
  i=0L;
  for (y=0L; y < (long) fourier_info->height; y++)
  {
    q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->height,1UL,
      exception);
    if (q == (PixelPacket *) NULL)
      break;
    indexes=GetCacheViewAuthenticIndexQueue(phase_view);
    for (x=0L; x < (long) fourier_info->width; x++)
    {
      switch (fourier_info->channel)
      {
        case RedChannel:
        default:
        {
          q->red=ClampToQuantum(QuantumRange*phase_source[i]);
          break;
        }
        case GreenChannel:
        {
          q->green=ClampToQuantum(QuantumRange*phase_source[i]);
          break;
        }
        case BlueChannel:
        {
          q->blue=ClampToQuantum(QuantumRange*phase_source[i]);
          break;
        }
        case OpacityChannel:
        {
          q->opacity=ClampToQuantum(QuantumRange*phase_source[i]);
          break;
        }
        case IndexChannel:
        {
          indexes[x]=ClampToQuantum(QuantumRange*phase_source[i]);
          break;
        }
        case GrayChannels:
        {
          q->red=ClampToQuantum(QuantumRange*phase_source[i]);
          q->green=q->red;
          q->blue=q->red;
          break;
        }
      }
      i++;
      q++;
    }
    status=SyncCacheViewAuthenticPixels(phase_view,exception);
    if (status == MagickFalse)
      break;
   }
  phase_view=DestroyCacheView(phase_view);
  magnitude_view=DestroyCacheView(magnitude_view);
  phase_source=(double *) RelinquishMagickMemory(phase_source);
  magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
  return(status);
}
예제 #15
0
MagickExport MagickBooleanType SortColormapByIntensity(Image *image)
{
  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  register ssize_t
    i;

  ssize_t
    y;

  unsigned short
    *pixels;

  assert(image != (Image *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(image->signature == MagickSignature);
  if (image->storage_class != PseudoClass)
    return(MagickTrue);
  /*
    Allocate memory for pixel indexes.
  */
  pixels=(unsigned short *) AcquireQuantumMemory((size_t) image->colors,
    sizeof(*pixels));
  if (pixels == (unsigned short *) NULL)
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  /*
    Assign index values to colormap entries.
  */
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (i=0; i < (ssize_t) image->colors; i++)
    image->colormap[i].opacity=(IndexPacket) i;
  /*
    Sort image colormap by decreasing color popularity.
  */
  qsort((void *) image->colormap,(size_t) image->colors,
    sizeof(*image->colormap),IntensityCompare);
  /*
    Update image colormap indexes to sorted colormap order.
  */
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (i=0; i < (ssize_t) image->colors; i++)
    pixels[(ssize_t) image->colormap[i].opacity]=(unsigned short) i;
  status=MagickTrue;
  exception=(&image->exception);
  image_view=AcquireCacheView(image);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    IndexPacket
      index;

    register ssize_t
      x;

    register IndexPacket
      *restrict indexes;

    register PixelPacket
      *restrict q;

    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      index=(IndexPacket) pixels[(ssize_t) GetIndexPixelComponent(indexes+x)];
      SetIndexPixelComponent(indexes+x,index);
      SetRGBOPixelComponents(q,image->colormap+(ssize_t) index);
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (status == MagickFalse)
      break;
  }
  image_view=DestroyCacheView(image_view);
  pixels=(unsigned short *) RelinquishMagickMemory(pixels);
  return(status);
}
예제 #16
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   F l o o d f i l l P a i n t I m a g e                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  FloodfillPaintImage() changes the color value of any pixel that matches
%  target and is an immediate neighbor.  If the method FillToBorderMethod is
%  specified, the color value is changed for any neighbor pixel that does not
%  match the bordercolor member of image.
%
%  By default target must match a particular pixel color exactly.
%  However, in many cases two colors may differ by a small amount.  The
%  fuzz member of image defines how much tolerance is acceptable to
%  consider two colors as the same.  For example, set fuzz to 10 and the
%  color red at intensities of 100 and 102 respectively are now
%  interpreted as the same color for the purposes of the floodfill.
%
%  The format of the FloodfillPaintImage method is:
%
%      MagickBooleanType FloodfillPaintImage(Image *image,
%        const ChannelType channel,const DrawInfo *draw_info,
%        const MagickPixelPacket target,const ssize_t x_offset,
%        const ssize_t y_offset,const MagickBooleanType invert)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o channel: the channel(s).
%
%    o draw_info: the draw info.
%
%    o target: the RGB value of the target color.
%
%    o x_offset,y_offset: the starting location of the operation.
%
%    o invert: paint any pixel that does not match the target color.
%
*/
MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
  const ChannelType channel,const DrawInfo *draw_info,
  const MagickPixelPacket *target,const ssize_t x_offset,const ssize_t y_offset,
  const MagickBooleanType invert)
{
#define MaxStacksize  (1UL << 15)
#define PushSegmentStack(up,left,right,delta) \
{ \
  if (s >= (segment_stack+MaxStacksize)) \
    ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \
  else \
    { \
      if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (ssize_t) image->rows)) \
        { \
          s->x1=(double) (left); \
          s->y1=(double) (up); \
          s->x2=(double) (right); \
          s->y2=(double) (delta); \
          s++; \
        } \
    } \
}

  CacheView
    *floodplane_view,
    *image_view;

  ExceptionInfo
    *exception;

  Image
    *floodplane_image;

  MagickBooleanType
    skip;

  MagickPixelPacket
    fill,
    pixel;

  PixelPacket
    fill_color;

  register SegmentInfo
    *s;

  SegmentInfo
    *segment_stack;

  ssize_t
    offset,
    start,
    x,
    x1,
    x2,
    y;

  /*
    Check boundary conditions.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(draw_info != (DrawInfo *) NULL);
  assert(draw_info->signature == MagickSignature);
  if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
    return(MagickFalse);
  if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
    return(MagickFalse);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  if (image->matte == MagickFalse)
    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
  /*
    Set floodfill state.
  */
  floodplane_image=CloneImage(image,0,0,MagickTrue,&image->exception);
  if (floodplane_image == (Image *) NULL)
    return(MagickFalse);
  (void) SetImageAlphaChannel(floodplane_image,OpaqueAlphaChannel);
  segment_stack=(SegmentInfo *) AcquireQuantumMemory(MaxStacksize,
    sizeof(*segment_stack));
  if (segment_stack == (SegmentInfo *) NULL)
    {
      floodplane_image=DestroyImage(floodplane_image);
      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
        image->filename);
    }
  /*
    Push initial segment on stack.
  */
  exception=(&image->exception);
  x=x_offset;
  y=y_offset;
  start=0;
  s=segment_stack;
  PushSegmentStack(y,x,x,1);
  PushSegmentStack(y+1,x,x,-1);
  GetMagickPixelPacket(image,&fill);
  GetMagickPixelPacket(image,&pixel);
  image_view=AcquireCacheView(image);
  floodplane_view=AcquireCacheView(floodplane_image);
  while (s > segment_stack)
  {
    register const IndexPacket
      *restrict indexes;

    register const PixelPacket
      *restrict p;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    /*
      Pop segment off stack.
    */
    s--;
    x1=(ssize_t) s->x1;
    x2=(ssize_t) s->x2;
    offset=(ssize_t) s->y2;
    y=(ssize_t) s->y1+offset;
    /*
      Recolor neighboring pixels.
    */
    p=GetCacheViewVirtualPixels(image_view,0,y,(size_t) (x1+1),1,exception);
    q=GetCacheViewAuthenticPixels(floodplane_view,0,y,(size_t) (x1+1),1,
      exception);
    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
      break;
    indexes=GetCacheViewVirtualIndexQueue(image_view);
    p+=x1;
    q+=x1;
    for (x=x1; x >= 0; x--)
    {
      if (q->opacity == (Quantum) TransparentOpacity)
        break;
      SetMagickPixelPacket(image,p,indexes+x,&pixel);
      if (IsMagickColorSimilar(&pixel,target) == invert)
        break;
      q->opacity=(Quantum) TransparentOpacity;
      p--;
      q--;
    }
    if (SyncCacheViewAuthenticPixels(floodplane_view,exception) == MagickFalse)
      break;
    skip=x >= x1 ? MagickTrue : MagickFalse;
    if (skip == MagickFalse)
      {
        start=x+1;
        if (start < x1)
          PushSegmentStack(y,start,x1-1,-offset);
        x=x1+1;
      }
    do
    {
      if (skip == MagickFalse)
        {
          if (x < (ssize_t) image->columns)
            {
              p=GetCacheViewVirtualPixels(image_view,x,y,image->columns-x,1,
                exception);
              q=GetCacheViewAuthenticPixels(floodplane_view,x,y,
                image->columns-x,1,exception);
              if ((p == (const PixelPacket *) NULL) ||
                  (q == (PixelPacket *) NULL))
                break;
              indexes=GetCacheViewVirtualIndexQueue(image_view);
              for ( ; x < (ssize_t) image->columns; x++)
              {
                if (q->opacity == (Quantum) TransparentOpacity)
                  break;
                SetMagickPixelPacket(image,p,indexes+x,&pixel);
                if (IsMagickColorSimilar(&pixel,target) == invert)
                  break;
                q->opacity=(Quantum) TransparentOpacity;
                p++;
                q++;
              }
              if (SyncCacheViewAuthenticPixels(floodplane_view,exception) == MagickFalse)
                break;
            }
          PushSegmentStack(y,start,x-1,offset);
          if (x > (x2+1))
            PushSegmentStack(y,x2+1,x-1,-offset);
        }
      skip=MagickFalse;
      x++;
      if (x <= x2)
        {
          p=GetCacheViewVirtualPixels(image_view,x,y,(size_t) (x2-x+1),1,
            exception);
          q=GetCacheViewAuthenticPixels(floodplane_view,x,y,(size_t) (x2-x+1),1,
            exception);
          if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
            break;
          indexes=GetCacheViewVirtualIndexQueue(image_view);
          for ( ; x <= x2; x++)
          {
            if (q->opacity == (Quantum) TransparentOpacity)
              break;
            SetMagickPixelPacket(image,p,indexes+x,&pixel);
            if (IsMagickColorSimilar(&pixel,target) != invert)
              break;
            p++;
            q++;
          }
        }
      start=x;
    } while (x <= x2);
  }
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register const PixelPacket
      *restrict p;

    register IndexPacket
      *restrict indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    /*
      Tile fill color onto floodplane.
    */
    p=GetCacheViewVirtualPixels(floodplane_view,0,y,image->columns,1,
      exception);
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
      break;
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      if (GetPixelOpacity(p) != OpaqueOpacity)
        {
          (void) GetFillColor(draw_info,x,y,&fill_color);
          SetMagickPixelPacket(image,&fill_color,(IndexPacket *) NULL,&fill);
          if (image->colorspace == CMYKColorspace)
            ConvertRGBToCMYK(&fill);
          if ((channel & RedChannel) != 0)
            SetPixelRed(q,ClampToQuantum(fill.red));
          if ((channel & GreenChannel) != 0)
            SetPixelGreen(q,ClampToQuantum(fill.green));
          if ((channel & BlueChannel) != 0)
            SetPixelBlue(q,ClampToQuantum(fill.blue));
          if ((channel & OpacityChannel) != 0)
            SetPixelOpacity(q,ClampToQuantum(fill.opacity));
          if (((channel & IndexChannel) != 0) &&
              (image->colorspace == CMYKColorspace))
            SetPixelIndex(indexes+x,ClampToQuantum(fill.index));
        }
      p++;
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      break;
  }
  floodplane_view=DestroyCacheView(floodplane_view);
  image_view=DestroyCacheView(image_view);
  segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
  floodplane_image=DestroyImage(floodplane_image);
  return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
}
예제 #17
0
static MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
  fftw_complex *fourier,Image *image,ExceptionInfo *exception)
{
  CacheView
    *image_view;

  double
    *source;

  fftw_plan
    fftw_c2r_plan;

  register IndexPacket
    *indexes;

  register PixelPacket
    *q;

  register ssize_t
    i,
    x;

  ssize_t
    y;

  source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
    fourier_info->width*sizeof(*source));
  if (source == (double *) NULL)
    {
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
      return(MagickFalse);
    }
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp critical (MagickCore_InverseFourierTransform)
#endif
  {
    fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
      fourier,source,FFTW_ESTIMATE);
    fftw_execute(fftw_c2r_plan);
    fftw_destroy_plan(fftw_c2r_plan);
  }
  i=0L;
  image_view=AcquireCacheView(image);
  for (y=0L; y < (ssize_t) fourier_info->height; y++)
  {
    if (y >= (ssize_t) image->rows)
      break;
    q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width >
      image->columns ? image->columns : fourier_info->width,1UL,exception);
    if (q == (PixelPacket *) NULL)
      break;
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    for (x=0L; x < (ssize_t) fourier_info->width; x++)
    {
      switch (fourier_info->channel)
      {
        case RedChannel:
        default:
        {
          q->red=ClampToQuantum(QuantumRange*source[i]);
          break;
        }
        case GreenChannel:
        {
          q->green=ClampToQuantum(QuantumRange*source[i]);
          break;
        }
        case BlueChannel:
        {
          q->blue=ClampToQuantum(QuantumRange*source[i]);
          break;
        }
        case OpacityChannel:
        {
          q->opacity=ClampToQuantum(QuantumRange*source[i]);
          break;
        }
        case IndexChannel:
        {
          indexes[x]=ClampToQuantum(QuantumRange*source[i]);
          break;
        }
        case GrayChannels:
        {
          SetGrayPixelComponent(q,ClampToQuantum(QuantumRange*source[i]));
          break;
        }
      }
      i++;
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      break;
  }
  image_view=DestroyCacheView(image_view);
  source=(double *) RelinquishMagickMemory(source);
  return(MagickTrue);
}
예제 #18
0
MagickExport ChannelFeatures *GetImageChannelFeatures(const Image *image,
  const size_t distance,ExceptionInfo *exception)
{
  typedef struct _ChannelStatistics
  {
    DoublePixelPacket
      direction[4];  /* horizontal, vertical, left and right diagonals */
  } ChannelStatistics;

  CacheView
    *image_view;

  ChannelFeatures
    *channel_features;

  ChannelStatistics
    **cooccurrence,
    correlation,
    *density_x,
    *density_xy,
    *density_y,
    entropy_x,
    entropy_xy,
    entropy_xy1,
    entropy_xy2,
    entropy_y,
    mean,
    **Q,
    *sum,
    sum_squares,
    variance;

  LongPixelPacket
    gray,
    *grays;

  MagickBooleanType
    status;

  register ssize_t
    i;

  size_t
    length;

  ssize_t
    y,
    z;

  unsigned int
    number_grays;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if ((image->columns < (distance+1)) || (image->rows < (distance+1)))
    return((ChannelFeatures *) NULL);
  length=CompositeChannels+1UL;
  channel_features=(ChannelFeatures *) AcquireQuantumMemory(length,
    sizeof(*channel_features));
  if (channel_features == (ChannelFeatures *) NULL)
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  (void) ResetMagickMemory(channel_features,0,length*
    sizeof(*channel_features));
  /*
    Form grays.
  */
  grays=(LongPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*grays));
  if (grays == (LongPixelPacket *) NULL)
    {
      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
        channel_features);
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
      return(channel_features);
    }
  for (i=0; i <= (ssize_t) MaxMap; i++)
  {
    grays[i].red=(~0U);
    grays[i].green=(~0U);
    grays[i].blue=(~0U);
    grays[i].opacity=(~0U);
    grays[i].index=(~0U);
  }
  status=MagickTrue;
  image_view=AcquireCacheView(image);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register const IndexPacket
      *restrict indexes;

    register const PixelPacket
      *restrict p;

    register ssize_t
      x;

    if (status == MagickFalse)
      continue;
    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    if (p == (const PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewVirtualIndexQueue(image_view);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      grays[ScaleQuantumToMap(GetPixelRed(p))].red=
        ScaleQuantumToMap(GetPixelRed(p));
      grays[ScaleQuantumToMap(GetPixelGreen(p))].green=
        ScaleQuantumToMap(GetPixelGreen(p));
      grays[ScaleQuantumToMap(GetPixelBlue(p))].blue=
        ScaleQuantumToMap(GetPixelBlue(p));
      if (image->colorspace == CMYKColorspace)
        grays[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index=
          ScaleQuantumToMap(GetPixelIndex(indexes+x));
      if (image->matte != MagickFalse)
        grays[ScaleQuantumToMap(GetPixelOpacity(p))].opacity=
          ScaleQuantumToMap(GetPixelOpacity(p));
      p++;
    }
  }
  image_view=DestroyCacheView(image_view);
  if (status == MagickFalse)
    {
      grays=(LongPixelPacket *) RelinquishMagickMemory(grays);
      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
        channel_features);
      return(channel_features);
    }
  (void) ResetMagickMemory(&gray,0,sizeof(gray));
  for (i=0; i <= (ssize_t) MaxMap; i++)
  {
    if (grays[i].red != ~0U)
      grays[(ssize_t) gray.red++].red=grays[i].red;
    if (grays[i].green != ~0U)
      grays[(ssize_t) gray.green++].green=grays[i].green;
    if (grays[i].blue != ~0U)
      grays[(ssize_t) gray.blue++].blue=grays[i].blue;
    if (image->colorspace == CMYKColorspace)
      if (grays[i].index != ~0U)
        grays[(ssize_t) gray.index++].index=grays[i].index;
    if (image->matte != MagickFalse)
      if (grays[i].opacity != ~0U)
        grays[(ssize_t) gray.opacity++].opacity=grays[i].opacity;
  }
  /*
    Allocate spatial dependence matrix.
  */
  number_grays=gray.red;
  if (gray.green > number_grays)
    number_grays=gray.green;
  if (gray.blue > number_grays)
    number_grays=gray.blue;
  if (image->colorspace == CMYKColorspace)
    if (gray.index > number_grays)
      number_grays=gray.index;
  if (image->matte != MagickFalse)
    if (gray.opacity > number_grays)
      number_grays=gray.opacity;
  cooccurrence=(ChannelStatistics **) AcquireQuantumMemory(number_grays,
    sizeof(*cooccurrence));
  density_x=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1),
    sizeof(*density_x));
  density_xy=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1),
    sizeof(*density_xy));
  density_y=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1),
    sizeof(*density_y));
  Q=(ChannelStatistics **) AcquireQuantumMemory(number_grays,sizeof(*Q));
  sum=(ChannelStatistics *) AcquireQuantumMemory(number_grays,sizeof(*sum));
  if ((cooccurrence == (ChannelStatistics **) NULL) ||
      (density_x == (ChannelStatistics *) NULL) ||
      (density_xy == (ChannelStatistics *) NULL) ||
      (density_y == (ChannelStatistics *) NULL) ||
      (Q == (ChannelStatistics **) NULL) ||
      (sum == (ChannelStatistics *) NULL))
    {
      if (Q != (ChannelStatistics **) NULL)
        {
          for (i=0; i < (ssize_t) number_grays; i++)
            Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]);
          Q=(ChannelStatistics **) RelinquishMagickMemory(Q);
        }
      if (sum != (ChannelStatistics *) NULL)
        sum=(ChannelStatistics *) RelinquishMagickMemory(sum);
      if (density_y != (ChannelStatistics *) NULL)
        density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y);
      if (density_xy != (ChannelStatistics *) NULL)
        density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy);
      if (density_x != (ChannelStatistics *) NULL)
        density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x);
      if (cooccurrence != (ChannelStatistics **) NULL)
        {
          for (i=0; i < (ssize_t) number_grays; i++)
            cooccurrence[i]=(ChannelStatistics *)
              RelinquishMagickMemory(cooccurrence[i]);
          cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(
            cooccurrence);
        }
      grays=(LongPixelPacket *) RelinquishMagickMemory(grays);
      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
        channel_features);
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
      return(channel_features);
    }
  (void) ResetMagickMemory(&correlation,0,sizeof(correlation));
  (void) ResetMagickMemory(density_x,0,2*(number_grays+1)*sizeof(*density_x));
  (void) ResetMagickMemory(density_xy,0,2*(number_grays+1)*sizeof(*density_xy));
  (void) ResetMagickMemory(density_y,0,2*(number_grays+1)*sizeof(*density_y));
  (void) ResetMagickMemory(&mean,0,sizeof(mean));
  (void) ResetMagickMemory(sum,0,number_grays*sizeof(*sum));
  (void) ResetMagickMemory(&sum_squares,0,sizeof(sum_squares));
  (void) ResetMagickMemory(density_xy,0,2*number_grays*sizeof(*density_xy));
  (void) ResetMagickMemory(&entropy_x,0,sizeof(entropy_x));
  (void) ResetMagickMemory(&entropy_xy,0,sizeof(entropy_xy));
  (void) ResetMagickMemory(&entropy_xy1,0,sizeof(entropy_xy1));
  (void) ResetMagickMemory(&entropy_xy2,0,sizeof(entropy_xy2));
  (void) ResetMagickMemory(&entropy_y,0,sizeof(entropy_y));
  (void) ResetMagickMemory(&variance,0,sizeof(variance));
  for (i=0; i < (ssize_t) number_grays; i++)
  {
    cooccurrence[i]=(ChannelStatistics *) AcquireQuantumMemory(number_grays,
      sizeof(**cooccurrence));
    Q[i]=(ChannelStatistics *) AcquireQuantumMemory(number_grays,sizeof(**Q));
    if ((cooccurrence[i] == (ChannelStatistics *) NULL) ||
        (Q[i] == (ChannelStatistics *) NULL))
      break;
    (void) ResetMagickMemory(cooccurrence[i],0,number_grays*
      sizeof(**cooccurrence));
    (void) ResetMagickMemory(Q[i],0,number_grays*sizeof(**Q));
  }
  if (i < (ssize_t) number_grays)
    {
      for (i--; i >= 0; i--)
      {
        if (Q[i] != (ChannelStatistics *) NULL)
          Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]);
        if (cooccurrence[i] != (ChannelStatistics *) NULL)
          cooccurrence[i]=(ChannelStatistics *)
            RelinquishMagickMemory(cooccurrence[i]);
      }
      Q=(ChannelStatistics **) RelinquishMagickMemory(Q);
      cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence);
      sum=(ChannelStatistics *) RelinquishMagickMemory(sum);
      density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y);
      density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy);
      density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x);
      grays=(LongPixelPacket *) RelinquishMagickMemory(grays);
      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
        channel_features);
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
      return(channel_features);
    }
  /*
    Initialize spatial dependence matrix.
  */
  status=MagickTrue;
  image_view=AcquireCacheView(image);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register const IndexPacket
      *restrict indexes;

    register const PixelPacket
      *restrict p;

    register ssize_t
      x;

    ssize_t
      i,
      offset,
      u,
      v;

    if (status == MagickFalse)
      continue;
    p=GetCacheViewVirtualPixels(image_view,-(ssize_t) distance,y,image->columns+
      2*distance,distance+2,exception);
    if (p == (const PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewVirtualIndexQueue(image_view);
    p+=distance;
    indexes+=distance;
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      for (i=0; i < 4; i++)
      {
        switch (i)
        {
          case 0:
          default:
          {
            /*
              Horizontal adjacency.
            */
            offset=(ssize_t) distance;
            break;
          }
          case 1:
          {
            /*
              Vertical adjacency.
            */
            offset=(ssize_t) (image->columns+2*distance);
            break;
          }
          case 2:
          {
            /*
              Right diagonal adjacency.
            */
            offset=(ssize_t) ((image->columns+2*distance)-distance);
            break;
          }
          case 3:
          {
            /*
              Left diagonal adjacency.
            */
            offset=(ssize_t) ((image->columns+2*distance)+distance);
            break;
          }
        }
        u=0;
        v=0;
        while (grays[u].red != ScaleQuantumToMap(GetPixelRed(p)))
          u++;
        while (grays[v].red != ScaleQuantumToMap(GetPixelRed(p+offset)))
          v++;
        cooccurrence[u][v].direction[i].red++;
        cooccurrence[v][u].direction[i].red++;
        u=0;
        v=0;
        while (grays[u].green != ScaleQuantumToMap(GetPixelGreen(p)))
          u++;
        while (grays[v].green != ScaleQuantumToMap(GetPixelGreen(p+offset)))
          v++;
        cooccurrence[u][v].direction[i].green++;
        cooccurrence[v][u].direction[i].green++;
        u=0;
        v=0;
        while (grays[u].blue != ScaleQuantumToMap(GetPixelBlue(p)))
          u++;
        while (grays[v].blue != ScaleQuantumToMap((p+offset)->blue))
          v++;
        cooccurrence[u][v].direction[i].blue++;
        cooccurrence[v][u].direction[i].blue++;
        if (image->colorspace == CMYKColorspace)
          {
            u=0;
            v=0;
            while (grays[u].index != ScaleQuantumToMap(GetPixelIndex(indexes+x)))
              u++;
            while (grays[v].index != ScaleQuantumToMap(GetPixelIndex(indexes+x+offset)))
              v++;
            cooccurrence[u][v].direction[i].index++;
            cooccurrence[v][u].direction[i].index++;
          }
        if (image->matte != MagickFalse)
          {
            u=0;
            v=0;
            while (grays[u].opacity != ScaleQuantumToMap(GetPixelOpacity(p)))
              u++;
            while (grays[v].opacity != ScaleQuantumToMap((p+offset)->opacity))
              v++;
            cooccurrence[u][v].direction[i].opacity++;
            cooccurrence[v][u].direction[i].opacity++;
          }
      }
      p++;
    }
  }
  grays=(LongPixelPacket *) RelinquishMagickMemory(grays);
  image_view=DestroyCacheView(image_view);
  if (status == MagickFalse)
    {
      for (i=0; i < (ssize_t) number_grays; i++)
        cooccurrence[i]=(ChannelStatistics *)
          RelinquishMagickMemory(cooccurrence[i]);
      cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence);
      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
        channel_features);
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
      return(channel_features);
    }
  /*
    Normalize spatial dependence matrix.
  */
  for (i=0; i < 4; i++)
  {
    double
      normalize;

    register ssize_t
      y;

    switch (i)
    {
      case 0:
      default:
      {
        /*
          Horizontal adjacency.
        */
        normalize=2.0*image->rows*(image->columns-distance);
        break;
      }
      case 1:
      {
        /*
          Vertical adjacency.
        */
        normalize=2.0*(image->rows-distance)*image->columns;
        break;
      }
      case 2:
      {
        /*
          Right diagonal adjacency.
        */
        normalize=2.0*(image->rows-distance)*(image->columns-distance);
        break;
      }
      case 3:
      {
        /*
          Left diagonal adjacency.
        */
        normalize=2.0*(image->rows-distance)*(image->columns-distance);
        break;
      }
    }
    normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 : normalize);
    for (y=0; y < (ssize_t) number_grays; y++)
    {
      register ssize_t
        x;

      for (x=0; x < (ssize_t) number_grays; x++)
      {
        cooccurrence[x][y].direction[i].red*=normalize;
        cooccurrence[x][y].direction[i].green*=normalize;
        cooccurrence[x][y].direction[i].blue*=normalize;
        if (image->colorspace == CMYKColorspace)
          cooccurrence[x][y].direction[i].index*=normalize;
        if (image->matte != MagickFalse)
          cooccurrence[x][y].direction[i].opacity*=normalize;
      }
    }
  }
  /*
    Compute texture features.
  */
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (i=0; i < 4; i++)
  {
    register ssize_t
      y;

    for (y=0; y < (ssize_t) number_grays; y++)
    {
      register ssize_t
        x;

      for (x=0; x < (ssize_t) number_grays; x++)
      {
        /*
          Angular second moment:  measure of homogeneity of the image.
        */
        channel_features[RedChannel].angular_second_moment[i]+=
          cooccurrence[x][y].direction[i].red*
          cooccurrence[x][y].direction[i].red;
        channel_features[GreenChannel].angular_second_moment[i]+=
          cooccurrence[x][y].direction[i].green*
          cooccurrence[x][y].direction[i].green;
        channel_features[BlueChannel].angular_second_moment[i]+=
          cooccurrence[x][y].direction[i].blue*
          cooccurrence[x][y].direction[i].blue;
        if (image->colorspace == CMYKColorspace)
          channel_features[BlackChannel].angular_second_moment[i]+=
            cooccurrence[x][y].direction[i].index*
            cooccurrence[x][y].direction[i].index;
        if (image->matte != MagickFalse)
          channel_features[OpacityChannel].angular_second_moment[i]+=
            cooccurrence[x][y].direction[i].opacity*
            cooccurrence[x][y].direction[i].opacity;
        /*
          Correlation: measure of linear-dependencies in the image.
        */
        sum[y].direction[i].red+=cooccurrence[x][y].direction[i].red;
        sum[y].direction[i].green+=cooccurrence[x][y].direction[i].green;
        sum[y].direction[i].blue+=cooccurrence[x][y].direction[i].blue;
        if (image->colorspace == CMYKColorspace)
          sum[y].direction[i].index+=cooccurrence[x][y].direction[i].index;
        if (image->matte != MagickFalse)
          sum[y].direction[i].opacity+=cooccurrence[x][y].direction[i].opacity;
        correlation.direction[i].red+=x*y*cooccurrence[x][y].direction[i].red;
        correlation.direction[i].green+=x*y*
          cooccurrence[x][y].direction[i].green;
        correlation.direction[i].blue+=x*y*
          cooccurrence[x][y].direction[i].blue;
        if (image->colorspace == CMYKColorspace)
          correlation.direction[i].index+=x*y*
            cooccurrence[x][y].direction[i].index;
        if (image->matte != MagickFalse)
          correlation.direction[i].opacity+=x*y*
            cooccurrence[x][y].direction[i].opacity;
        /*
          Inverse Difference Moment.
        */
        channel_features[RedChannel].inverse_difference_moment[i]+=
          cooccurrence[x][y].direction[i].red/((y-x)*(y-x)+1);
        channel_features[GreenChannel].inverse_difference_moment[i]+=
          cooccurrence[x][y].direction[i].green/((y-x)*(y-x)+1);
        channel_features[BlueChannel].inverse_difference_moment[i]+=
          cooccurrence[x][y].direction[i].blue/((y-x)*(y-x)+1);
        if (image->colorspace == CMYKColorspace)
          channel_features[IndexChannel].inverse_difference_moment[i]+=
            cooccurrence[x][y].direction[i].index/((y-x)*(y-x)+1);
        if (image->matte != MagickFalse)
          channel_features[OpacityChannel].inverse_difference_moment[i]+=
            cooccurrence[x][y].direction[i].opacity/((y-x)*(y-x)+1);
        /*
          Sum average.
        */
        density_xy[y+x+2].direction[i].red+=
          cooccurrence[x][y].direction[i].red;
        density_xy[y+x+2].direction[i].green+=
          cooccurrence[x][y].direction[i].green;
        density_xy[y+x+2].direction[i].blue+=
          cooccurrence[x][y].direction[i].blue;
        if (image->colorspace == CMYKColorspace)
          density_xy[y+x+2].direction[i].index+=
            cooccurrence[x][y].direction[i].index;
        if (image->matte != MagickFalse)
          density_xy[y+x+2].direction[i].opacity+=
            cooccurrence[x][y].direction[i].opacity;
        /*
          Entropy.
        */
        channel_features[RedChannel].entropy[i]-=
          cooccurrence[x][y].direction[i].red*
          log10(cooccurrence[x][y].direction[i].red+MagickEpsilon);
        channel_features[GreenChannel].entropy[i]-=
          cooccurrence[x][y].direction[i].green*
          log10(cooccurrence[x][y].direction[i].green+MagickEpsilon);
        channel_features[BlueChannel].entropy[i]-=
          cooccurrence[x][y].direction[i].blue*
          log10(cooccurrence[x][y].direction[i].blue+MagickEpsilon);
        if (image->colorspace == CMYKColorspace)
          channel_features[IndexChannel].entropy[i]-=
            cooccurrence[x][y].direction[i].index*
            log10(cooccurrence[x][y].direction[i].index+MagickEpsilon);
        if (image->matte != MagickFalse)
          channel_features[OpacityChannel].entropy[i]-=
            cooccurrence[x][y].direction[i].opacity*
            log10(cooccurrence[x][y].direction[i].opacity+MagickEpsilon);
        /*
          Information Measures of Correlation.
        */
        density_x[x].direction[i].red+=cooccurrence[x][y].direction[i].red;
        density_x[x].direction[i].green+=cooccurrence[x][y].direction[i].green;
        density_x[x].direction[i].blue+=cooccurrence[x][y].direction[i].blue;
        if (image->colorspace == CMYKColorspace)
          density_x[x].direction[i].index+=
            cooccurrence[x][y].direction[i].index;
        if (image->matte != MagickFalse)
          density_x[x].direction[i].opacity+=
            cooccurrence[x][y].direction[i].opacity;
        density_y[y].direction[i].red+=cooccurrence[x][y].direction[i].red;
        density_y[y].direction[i].green+=cooccurrence[x][y].direction[i].green;
        density_y[y].direction[i].blue+=cooccurrence[x][y].direction[i].blue;
        if (image->colorspace == CMYKColorspace)
          density_y[y].direction[i].index+=
            cooccurrence[x][y].direction[i].index;
        if (image->matte != MagickFalse)
          density_y[y].direction[i].opacity+=
            cooccurrence[x][y].direction[i].opacity;
      }
      mean.direction[i].red+=y*sum[y].direction[i].red;
      sum_squares.direction[i].red+=y*y*sum[y].direction[i].red;
      mean.direction[i].green+=y*sum[y].direction[i].green;
      sum_squares.direction[i].green+=y*y*sum[y].direction[i].green;
      mean.direction[i].blue+=y*sum[y].direction[i].blue;
      sum_squares.direction[i].blue+=y*y*sum[y].direction[i].blue;
      if (image->colorspace == CMYKColorspace)
        {
          mean.direction[i].index+=y*sum[y].direction[i].index;
          sum_squares.direction[i].index+=y*y*sum[y].direction[i].index;
        }
      if (image->matte != MagickFalse)
        {
          mean.direction[i].opacity+=y*sum[y].direction[i].opacity;
          sum_squares.direction[i].opacity+=y*y*sum[y].direction[i].opacity;
        }
    }
    /*
      Correlation: measure of linear-dependencies in the image.
    */
    channel_features[RedChannel].correlation[i]=
      (correlation.direction[i].red-mean.direction[i].red*
      mean.direction[i].red)/(sqrt(sum_squares.direction[i].red-
      (mean.direction[i].red*mean.direction[i].red))*sqrt(
      sum_squares.direction[i].red-(mean.direction[i].red*
      mean.direction[i].red)));
    channel_features[GreenChannel].correlation[i]=
      (correlation.direction[i].green-mean.direction[i].green*
      mean.direction[i].green)/(sqrt(sum_squares.direction[i].green-
      (mean.direction[i].green*mean.direction[i].green))*sqrt(
      sum_squares.direction[i].green-(mean.direction[i].green*
      mean.direction[i].green)));
    channel_features[BlueChannel].correlation[i]=
      (correlation.direction[i].blue-mean.direction[i].blue*
      mean.direction[i].blue)/(sqrt(sum_squares.direction[i].blue-
      (mean.direction[i].blue*mean.direction[i].blue))*sqrt(
      sum_squares.direction[i].blue-(mean.direction[i].blue*
      mean.direction[i].blue)));
    if (image->colorspace == CMYKColorspace)
      channel_features[IndexChannel].correlation[i]=
        (correlation.direction[i].index-mean.direction[i].index*
        mean.direction[i].index)/(sqrt(sum_squares.direction[i].index-
        (mean.direction[i].index*mean.direction[i].index))*sqrt(
        sum_squares.direction[i].index-(mean.direction[i].index*
        mean.direction[i].index)));
    if (image->matte != MagickFalse)
      channel_features[OpacityChannel].correlation[i]=
        (correlation.direction[i].opacity-mean.direction[i].opacity*
        mean.direction[i].opacity)/(sqrt(sum_squares.direction[i].opacity-
        (mean.direction[i].opacity*mean.direction[i].opacity))*sqrt(
        sum_squares.direction[i].opacity-(mean.direction[i].opacity*
        mean.direction[i].opacity)));
  }
  /*
    Compute more texture features.
  */
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (i=0; i < 4; i++)
  {
    register ssize_t
      x;

    for (x=2; x < (ssize_t) (2*number_grays); x++)
    {
      /*
        Sum average.
      */
      channel_features[RedChannel].sum_average[i]+=
        x*density_xy[x].direction[i].red;
      channel_features[GreenChannel].sum_average[i]+=
        x*density_xy[x].direction[i].green;
      channel_features[BlueChannel].sum_average[i]+=
        x*density_xy[x].direction[i].blue;
      if (image->colorspace == CMYKColorspace)
        channel_features[IndexChannel].sum_average[i]+=
          x*density_xy[x].direction[i].index;
      if (image->matte != MagickFalse)
        channel_features[OpacityChannel].sum_average[i]+=
          x*density_xy[x].direction[i].opacity;
      /*
        Sum entropy.
      */
      channel_features[RedChannel].sum_entropy[i]-=
        density_xy[x].direction[i].red*
        log10(density_xy[x].direction[i].red+MagickEpsilon);
      channel_features[GreenChannel].sum_entropy[i]-=
        density_xy[x].direction[i].green*
        log10(density_xy[x].direction[i].green+MagickEpsilon);
      channel_features[BlueChannel].sum_entropy[i]-=
        density_xy[x].direction[i].blue*
        log10(density_xy[x].direction[i].blue+MagickEpsilon);
      if (image->colorspace == CMYKColorspace)
        channel_features[IndexChannel].sum_entropy[i]-=
          density_xy[x].direction[i].index*
          log10(density_xy[x].direction[i].index+MagickEpsilon);
      if (image->matte != MagickFalse)
        channel_features[OpacityChannel].sum_entropy[i]-=
          density_xy[x].direction[i].opacity*
          log10(density_xy[x].direction[i].opacity+MagickEpsilon);
      /*
        Sum variance.
      */
      channel_features[RedChannel].sum_variance[i]+=
        (x-channel_features[RedChannel].sum_entropy[i])*
        (x-channel_features[RedChannel].sum_entropy[i])*
        density_xy[x].direction[i].red;
      channel_features[GreenChannel].sum_variance[i]+=
        (x-channel_features[GreenChannel].sum_entropy[i])*
        (x-channel_features[GreenChannel].sum_entropy[i])*
        density_xy[x].direction[i].green;
      channel_features[BlueChannel].sum_variance[i]+=
        (x-channel_features[BlueChannel].sum_entropy[i])*
        (x-channel_features[BlueChannel].sum_entropy[i])*
        density_xy[x].direction[i].blue;
      if (image->colorspace == CMYKColorspace)
        channel_features[IndexChannel].sum_variance[i]+=
          (x-channel_features[IndexChannel].sum_entropy[i])*
          (x-channel_features[IndexChannel].sum_entropy[i])*
          density_xy[x].direction[i].index;
      if (image->matte != MagickFalse)
        channel_features[OpacityChannel].sum_variance[i]+=
          (x-channel_features[OpacityChannel].sum_entropy[i])*
          (x-channel_features[OpacityChannel].sum_entropy[i])*
          density_xy[x].direction[i].opacity;
    }
  }
  /*
    Compute more texture features.
  */
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (i=0; i < 4; i++)
  {
    register ssize_t
      y;

    for (y=0; y < (ssize_t) number_grays; y++)
    {
      register ssize_t
        x;

      for (x=0; x < (ssize_t) number_grays; x++)
      {
        /*
          Sum of Squares: Variance
        */
        variance.direction[i].red+=(y-mean.direction[i].red+1)*
          (y-mean.direction[i].red+1)*cooccurrence[x][y].direction[i].red;
        variance.direction[i].green+=(y-mean.direction[i].green+1)*
          (y-mean.direction[i].green+1)*cooccurrence[x][y].direction[i].green;
        variance.direction[i].blue+=(y-mean.direction[i].blue+1)*
          (y-mean.direction[i].blue+1)*cooccurrence[x][y].direction[i].blue;
        if (image->colorspace == CMYKColorspace)
          variance.direction[i].index+=(y-mean.direction[i].index+1)*
            (y-mean.direction[i].index+1)*cooccurrence[x][y].direction[i].index;
        if (image->matte != MagickFalse)
          variance.direction[i].opacity+=(y-mean.direction[i].opacity+1)*
            (y-mean.direction[i].opacity+1)*
            cooccurrence[x][y].direction[i].opacity;
        /*
          Sum average / Difference Variance.
        */
        density_xy[MagickAbsoluteValue(y-x)].direction[i].red+=
          cooccurrence[x][y].direction[i].red;
        density_xy[MagickAbsoluteValue(y-x)].direction[i].green+=
          cooccurrence[x][y].direction[i].green;
        density_xy[MagickAbsoluteValue(y-x)].direction[i].blue+=
          cooccurrence[x][y].direction[i].blue;
        if (image->colorspace == CMYKColorspace)
          density_xy[MagickAbsoluteValue(y-x)].direction[i].index+=
            cooccurrence[x][y].direction[i].index;
        if (image->matte != MagickFalse)
          density_xy[MagickAbsoluteValue(y-x)].direction[i].opacity+=
            cooccurrence[x][y].direction[i].opacity;
        /*
          Information Measures of Correlation.
        */
        entropy_xy.direction[i].red-=cooccurrence[x][y].direction[i].red*
          log10(cooccurrence[x][y].direction[i].red+MagickEpsilon);
        entropy_xy.direction[i].green-=cooccurrence[x][y].direction[i].green*
          log10(cooccurrence[x][y].direction[i].green+MagickEpsilon);
        entropy_xy.direction[i].blue-=cooccurrence[x][y].direction[i].blue*
          log10(cooccurrence[x][y].direction[i].blue+MagickEpsilon);
        if (image->colorspace == CMYKColorspace)
          entropy_xy.direction[i].index-=cooccurrence[x][y].direction[i].index*
            log10(cooccurrence[x][y].direction[i].index+MagickEpsilon);
        if (image->matte != MagickFalse)
          entropy_xy.direction[i].opacity-=
            cooccurrence[x][y].direction[i].opacity*log10(
            cooccurrence[x][y].direction[i].opacity+MagickEpsilon);
        entropy_xy1.direction[i].red-=(cooccurrence[x][y].direction[i].red*
          log10(density_x[x].direction[i].red*density_y[y].direction[i].red+
          MagickEpsilon));
        entropy_xy1.direction[i].green-=(cooccurrence[x][y].direction[i].green*
          log10(density_x[x].direction[i].green*density_y[y].direction[i].green+
          MagickEpsilon));
        entropy_xy1.direction[i].blue-=(cooccurrence[x][y].direction[i].blue*
          log10(density_x[x].direction[i].blue*density_y[y].direction[i].blue+
          MagickEpsilon));
        if (image->colorspace == CMYKColorspace)
          entropy_xy1.direction[i].index-=(
            cooccurrence[x][y].direction[i].index*log10(
            density_x[x].direction[i].index*density_y[y].direction[i].index+
            MagickEpsilon));
        if (image->matte != MagickFalse)
          entropy_xy1.direction[i].opacity-=(
            cooccurrence[x][y].direction[i].opacity*log10(
            density_x[x].direction[i].opacity*density_y[y].direction[i].opacity+
            MagickEpsilon));
        entropy_xy2.direction[i].red-=(density_x[x].direction[i].red*
          density_y[y].direction[i].red*log10(density_x[x].direction[i].red*
          density_y[y].direction[i].red+MagickEpsilon));
        entropy_xy2.direction[i].green-=(density_x[x].direction[i].green*
          density_y[y].direction[i].green*log10(density_x[x].direction[i].green*
          density_y[y].direction[i].green+MagickEpsilon));
        entropy_xy2.direction[i].blue-=(density_x[x].direction[i].blue*
          density_y[y].direction[i].blue*log10(density_x[x].direction[i].blue*
          density_y[y].direction[i].blue+MagickEpsilon));
        if (image->colorspace == CMYKColorspace)
          entropy_xy2.direction[i].index-=(density_x[x].direction[i].index*
            density_y[y].direction[i].index*log10(
            density_x[x].direction[i].index*density_y[y].direction[i].index+
            MagickEpsilon));
        if (image->matte != MagickFalse)
          entropy_xy2.direction[i].opacity-=(density_x[x].direction[i].opacity*
            density_y[y].direction[i].opacity*log10(
            density_x[x].direction[i].opacity*density_y[y].direction[i].opacity+
            MagickEpsilon));
      }
    }
    channel_features[RedChannel].variance_sum_of_squares[i]=
      variance.direction[i].red;
    channel_features[GreenChannel].variance_sum_of_squares[i]=
      variance.direction[i].green;
    channel_features[BlueChannel].variance_sum_of_squares[i]=
      variance.direction[i].blue;
    if (image->colorspace == CMYKColorspace)
      channel_features[RedChannel].variance_sum_of_squares[i]=
        variance.direction[i].index;
    if (image->matte != MagickFalse)
      channel_features[RedChannel].variance_sum_of_squares[i]=
        variance.direction[i].opacity;
  }
  /*
    Compute more texture features.
  */
  (void) ResetMagickMemory(&variance,0,sizeof(variance));
  (void) ResetMagickMemory(&sum_squares,0,sizeof(sum_squares));
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (i=0; i < 4; i++)
  {
    register ssize_t
      x;

    for (x=0; x < (ssize_t) number_grays; x++)
    {
      /*
        Difference variance.
      */
      variance.direction[i].red+=density_xy[x].direction[i].red;
      variance.direction[i].green+=density_xy[x].direction[i].green;
      variance.direction[i].blue+=density_xy[x].direction[i].blue;
      if (image->colorspace == CMYKColorspace)
        variance.direction[i].index+=density_xy[x].direction[i].index;
      if (image->matte != MagickFalse)
        variance.direction[i].opacity+=density_xy[x].direction[i].opacity;
      sum_squares.direction[i].red+=density_xy[x].direction[i].red*
        density_xy[x].direction[i].red;
      sum_squares.direction[i].green+=density_xy[x].direction[i].green*
        density_xy[x].direction[i].green;
      sum_squares.direction[i].blue+=density_xy[x].direction[i].blue*
        density_xy[x].direction[i].blue;
      if (image->colorspace == CMYKColorspace)
        sum_squares.direction[i].index+=density_xy[x].direction[i].index*
          density_xy[x].direction[i].index;
      if (image->matte != MagickFalse)
        sum_squares.direction[i].opacity+=density_xy[x].direction[i].opacity*
          density_xy[x].direction[i].opacity;
      /*
        Difference entropy.
      */
      channel_features[RedChannel].difference_entropy[i]-=
        density_xy[x].direction[i].red*
        log10(density_xy[x].direction[i].red+MagickEpsilon);
      channel_features[GreenChannel].difference_entropy[i]-=
        density_xy[x].direction[i].green*
        log10(density_xy[x].direction[i].green+MagickEpsilon);
      channel_features[BlueChannel].difference_entropy[i]-=
        density_xy[x].direction[i].blue*
        log10(density_xy[x].direction[i].blue+MagickEpsilon);
      if (image->colorspace == CMYKColorspace)
        channel_features[IndexChannel].difference_entropy[i]-=
          density_xy[x].direction[i].index*
          log10(density_xy[x].direction[i].index+MagickEpsilon);
      if (image->matte != MagickFalse)
        channel_features[OpacityChannel].difference_entropy[i]-=
          density_xy[x].direction[i].opacity*
          log10(density_xy[x].direction[i].opacity+MagickEpsilon);
      /*
        Information Measures of Correlation.
      */
      entropy_x.direction[i].red-=(density_x[x].direction[i].red*
        log10(density_x[x].direction[i].red+MagickEpsilon));
      entropy_x.direction[i].green-=(density_x[x].direction[i].green*
        log10(density_x[x].direction[i].green+MagickEpsilon));
      entropy_x.direction[i].blue-=(density_x[x].direction[i].blue*
        log10(density_x[x].direction[i].blue+MagickEpsilon));
      if (image->colorspace == CMYKColorspace)
        entropy_x.direction[i].index-=(density_x[x].direction[i].index*
          log10(density_x[x].direction[i].index+MagickEpsilon));
      if (image->matte != MagickFalse)
        entropy_x.direction[i].opacity-=(density_x[x].direction[i].opacity*
          log10(density_x[x].direction[i].opacity+MagickEpsilon));
      entropy_y.direction[i].red-=(density_y[x].direction[i].red*
        log10(density_y[x].direction[i].red+MagickEpsilon));
      entropy_y.direction[i].green-=(density_y[x].direction[i].green*
        log10(density_y[x].direction[i].green+MagickEpsilon));
      entropy_y.direction[i].blue-=(density_y[x].direction[i].blue*
        log10(density_y[x].direction[i].blue+MagickEpsilon));
      if (image->colorspace == CMYKColorspace)
        entropy_y.direction[i].index-=(density_y[x].direction[i].index*
          log10(density_y[x].direction[i].index+MagickEpsilon));
      if (image->matte != MagickFalse)
        entropy_y.direction[i].opacity-=(density_y[x].direction[i].opacity*
          log10(density_y[x].direction[i].opacity+MagickEpsilon));
    }
    /*
      Difference variance.
    */
    channel_features[RedChannel].difference_variance[i]=
      (((double) number_grays*number_grays*sum_squares.direction[i].red)-
      (variance.direction[i].red*variance.direction[i].red))/
      ((double) number_grays*number_grays*number_grays*number_grays);
    channel_features[GreenChannel].difference_variance[i]=
      (((double) number_grays*number_grays*sum_squares.direction[i].green)-
      (variance.direction[i].green*variance.direction[i].green))/
      ((double) number_grays*number_grays*number_grays*number_grays);
    channel_features[BlueChannel].difference_variance[i]=
      (((double) number_grays*number_grays*sum_squares.direction[i].blue)-
      (variance.direction[i].blue*variance.direction[i].blue))/
      ((double) number_grays*number_grays*number_grays*number_grays);
    if (image->matte != MagickFalse)
      channel_features[OpacityChannel].difference_variance[i]=
        (((double) number_grays*number_grays*sum_squares.direction[i].opacity)-
        (variance.direction[i].opacity*variance.direction[i].opacity))/
        ((double) number_grays*number_grays*number_grays*number_grays);
    if (image->colorspace == CMYKColorspace)
      channel_features[IndexChannel].difference_variance[i]=
        (((double) number_grays*number_grays*sum_squares.direction[i].index)-
        (variance.direction[i].index*variance.direction[i].index))/
        ((double) number_grays*number_grays*number_grays*number_grays);
    /*
      Information Measures of Correlation.
    */
    channel_features[RedChannel].measure_of_correlation_1[i]=
      (entropy_xy.direction[i].red-entropy_xy1.direction[i].red)/
      (entropy_x.direction[i].red > entropy_y.direction[i].red ?
       entropy_x.direction[i].red : entropy_y.direction[i].red);
    channel_features[GreenChannel].measure_of_correlation_1[i]=
      (entropy_xy.direction[i].green-entropy_xy1.direction[i].green)/
      (entropy_x.direction[i].green > entropy_y.direction[i].green ?
       entropy_x.direction[i].green : entropy_y.direction[i].green);
    channel_features[BlueChannel].measure_of_correlation_1[i]=
      (entropy_xy.direction[i].blue-entropy_xy1.direction[i].blue)/
      (entropy_x.direction[i].blue > entropy_y.direction[i].blue ?
       entropy_x.direction[i].blue : entropy_y.direction[i].blue);
    if (image->colorspace == CMYKColorspace)
      channel_features[IndexChannel].measure_of_correlation_1[i]=
        (entropy_xy.direction[i].index-entropy_xy1.direction[i].index)/
        (entropy_x.direction[i].index > entropy_y.direction[i].index ?
         entropy_x.direction[i].index : entropy_y.direction[i].index);
    if (image->matte != MagickFalse)
      channel_features[OpacityChannel].measure_of_correlation_1[i]=
        (entropy_xy.direction[i].opacity-entropy_xy1.direction[i].opacity)/
        (entropy_x.direction[i].opacity > entropy_y.direction[i].opacity ?
         entropy_x.direction[i].opacity : entropy_y.direction[i].opacity);
    channel_features[RedChannel].measure_of_correlation_2[i]=
      (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].red-
      entropy_xy.direction[i].red)))));
    channel_features[GreenChannel].measure_of_correlation_2[i]=
      (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].green-
      entropy_xy.direction[i].green)))));
    channel_features[BlueChannel].measure_of_correlation_2[i]=
      (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].blue-
      entropy_xy.direction[i].blue)))));
    if (image->colorspace == CMYKColorspace)
      channel_features[IndexChannel].measure_of_correlation_2[i]=
        (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].index-
        entropy_xy.direction[i].index)))));
    if (image->matte != MagickFalse)
      channel_features[OpacityChannel].measure_of_correlation_2[i]=
        (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].opacity-
        entropy_xy.direction[i].opacity)))));
  }
  /*
    Compute more texture features.
  */
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (i=0; i < 4; i++)
  {
    for (z=0; z < (ssize_t) number_grays; z++)
    {
      register ssize_t
        y;

      ChannelStatistics
        pixel;

      (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
      for (y=0; y < (ssize_t) number_grays; y++)
      {
        register ssize_t
          x;

        for (x=0; x < (ssize_t) number_grays; x++)
        {
          /*
            Contrast:  amount of local variations present in an image.
          */
          if (((y-x) == z) || ((x-y) == z))
            {
              pixel.direction[i].red+=cooccurrence[x][y].direction[i].red;
              pixel.direction[i].green+=cooccurrence[x][y].direction[i].green;
              pixel.direction[i].blue+=cooccurrence[x][y].direction[i].blue;
              if (image->colorspace == CMYKColorspace)
                pixel.direction[i].index+=cooccurrence[x][y].direction[i].index;
              if (image->matte != MagickFalse)
                pixel.direction[i].opacity+=
                  cooccurrence[x][y].direction[i].opacity;
            }
          /*
            Maximum Correlation Coefficient.
          */
          Q[z][y].direction[i].red+=cooccurrence[z][x].direction[i].red*
            cooccurrence[y][x].direction[i].red/density_x[z].direction[i].red/
            density_y[x].direction[i].red;
          Q[z][y].direction[i].green+=cooccurrence[z][x].direction[i].green*
            cooccurrence[y][x].direction[i].green/
            density_x[z].direction[i].green/density_y[x].direction[i].red;
          Q[z][y].direction[i].blue+=cooccurrence[z][x].direction[i].blue*
            cooccurrence[y][x].direction[i].blue/density_x[z].direction[i].blue/
            density_y[x].direction[i].blue;
          if (image->colorspace == CMYKColorspace)
            Q[z][y].direction[i].index+=cooccurrence[z][x].direction[i].index*
              cooccurrence[y][x].direction[i].index/
              density_x[z].direction[i].index/density_y[x].direction[i].index;
          if (image->matte != MagickFalse)
            Q[z][y].direction[i].opacity+=
              cooccurrence[z][x].direction[i].opacity*
              cooccurrence[y][x].direction[i].opacity/
              density_x[z].direction[i].opacity/
              density_y[x].direction[i].opacity;
        }
      }
      channel_features[RedChannel].contrast[i]+=z*z*pixel.direction[i].red;
      channel_features[GreenChannel].contrast[i]+=z*z*pixel.direction[i].green;
      channel_features[BlueChannel].contrast[i]+=z*z*pixel.direction[i].blue;
      if (image->colorspace == CMYKColorspace)
        channel_features[BlackChannel].contrast[i]+=z*z*
          pixel.direction[i].index;
      if (image->matte != MagickFalse)
        channel_features[OpacityChannel].contrast[i]+=z*z*
          pixel.direction[i].opacity;
    }
    /*
      Maximum Correlation Coefficient.
      Future: return second largest eigenvalue of Q.
    */
    channel_features[RedChannel].maximum_correlation_coefficient[i]=
      sqrt((double) -1.0);
    channel_features[GreenChannel].maximum_correlation_coefficient[i]=
      sqrt((double) -1.0);
    channel_features[BlueChannel].maximum_correlation_coefficient[i]=
      sqrt((double) -1.0);
    if (image->colorspace == CMYKColorspace)
      channel_features[IndexChannel].maximum_correlation_coefficient[i]=
        sqrt((double) -1.0);
    if (image->matte != MagickFalse)
      channel_features[OpacityChannel].maximum_correlation_coefficient[i]=
        sqrt((double) -1.0);
  }
  /*
    Relinquish resources.
  */
  sum=(ChannelStatistics *) RelinquishMagickMemory(sum);
  for (i=0; i < (ssize_t) number_grays; i++)
    Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]);
  Q=(ChannelStatistics **) RelinquishMagickMemory(Q);
  density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y);
  density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy);
  density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x);
  for (i=0; i < (ssize_t) number_grays; i++)
    cooccurrence[i]=(ChannelStatistics *)
      RelinquishMagickMemory(cooccurrence[i]);
  cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence);
  return(channel_features);
}