Page 1 of 1

Wrong results of GetImageChannelRange after RotateImag

Posted: 2012-02-02T13:08:43-07:00
by jrrose
If I rotate an image I get values for image depth, minimum and maximum, which I does not expect. I use the following rotate-image_with_getChannelRange.c program:

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <wand/MagickWand.h>

print_stat(MagickWand *wand, long long unsigned max_img_val, long long unsigned max_IM_val) {
  double minimum, maximum, mean,stdev;
  const char *fmt=" %-13s  depth=%2lu  min=%8.1lf(%5.3lf)  max=%8.1lf(%5.3lf)  mean=%8.1lf(%5.3lf)  stdev=%8.1lf(%5.3lf)\n";
  fprintf(stderr,"img_depth=%lu\n",MagickGetImageDepth(wand));

#define print_chan(S,c) { \
    MagickGetImageChannelRange(wand,c,&minimum,&maximum); \
    MagickGetImageChannelMean(wand,c,&mean,&stdev);	\
    fprintf(stderr,fmt,S,MagickGetImageChannelDepth(wand,c),\
               max_img_val*minimum/max_IM_val,minimum/max_IM_val, max_img_val*maximum/max_IM_val,maximum/max_IM_val,\
               max_img_val*mean/max_IM_val,mean/max_IM_val, max_img_val*stdev/max_IM_val,stdev/max_IM_val); \
  }
  print_chan("RedChannel:",RedChannel);
  print_chan("GreenChannel:",GreenChannel);
  print_chan("BlueChannel:",BlueChannel);
  print_chan("GrayChannel:",GrayChannel);
}

int main(int argc,char **argv) {

#define ThrowWandException(wand) { \
    description=MagickGetException(wand,&severity);\
    (void) fprintf(stderr,"%s %s %lu %s\n",GetMagickModule(),description); \
    description=(char *) MagickRelinquishMemory(description);\
    exit(-1);\
  }

  char *description;
  ExceptionType severity;
  MagickBooleanType status;

  MagickWandGenesis();
  MagickWand *wand=NewMagickWand();
  status=MagickReadImage(wand,argv[1]);
  if (status == MagickFalse) ThrowWandException(wand);

  size_t IM_quantum_depth;
  const char *IM_quantum_depth_str=GetMagickQuantumDepth(&IM_quantum_depth);
  size_t img_depth=MagickGetImageDepth(wand);
  const char *quantum_format=MagickGetImageProperty(wand,"quantum:format");
  fprintf(stderr,"IM_quantum_depth_str=|%s|  IM_quantum_depth=|%lu|  img_depth=%lu  quantum_format=|%s|\n",
             IM_quantum_depth_str,IM_quantum_depth,img_depth,quantum_format);

  long long unsigned max_IM_val=1ULL<<IM_quantum_depth;
  long long unsigned max_img_val=(1ULL<<img_depth)-1;
  fprintf(stderr,"1L<<IM_quantum_depth=%Lu  max_IM_val=$Lu  max_img_val=%Lu\n",
            1ULL<<IM_quantum_depth,max_IM_val,max_img_val);
  print_stat(wand, max_img_val, max_IM_val);

  double degree=5;
  MagickWand *rotated_wand = CloneMagickWand(wand);
  PixelWand *background_color=NewPixelWand();
  printf("\n\nbefore RotateImage:   degree=%f\n",degree);
  status=MagickRotateImage(rotated_wand, background_color, degree);
  fprintf(stderr,"after MagickRotateImage:  background_color=%s[%%s]\n",
            PixelGetColorAsString(background_color));
  if(status == MagickFalse) {
    fprintf(stderr,"%s: MagickRotateImage failed, for degree=%f\n",
               argv[0],degree);
    exit(-1);
  }
  print_stat(rotated_wand,max_img_val,max_IM_val);

  char out_f[1024];
  sprintf(out_f,"OutImages/%s",argv[2]);
  printf("\n\nbefore MagickWriteImages(rotated_wand,%s,):\n",out_f);
  status=MagickWriteImages(rotated_wand,out_f,MagickTrue);
  printf("\n\nafter MagickWriteImages(rotated_wand):\n");
  if (status == MagickFalse) ThrowWandException(rotated_wand);

  rotated_wand=DestroyMagickWand(rotated_wand);
  wand=DestroyMagickWand(wand);
  MagickWandTerminus();
  return(0);
}
Running the programm I get the output:

rose@moose:/home_moose/rose/Txt/src/Test/C/ImageMagick/Wand(406)$ rotate-image_with_getChannelRange lena.png lena_rotated.png
IM_quantum_depth_str=|Q32| IM_quantum_depth=|32| img_depth=8 quantum_format=|(null)|
1L<<IM_quantum_depth=4294967296 max_IM_val=$Lu max_img_val=4294967296
img_depth=8
RedChannel: depth= 8 min= 38.0(0.149) max= 255.0(1.000) mean= 180.0(0.706) stdev= 49.4(0.194)
GreenChannel: depth= 8 min= 0.0(0.000) max= 243.0(0.953) mean= 99.4(0.390) stdev= 52.6(0.206)
BlueChannel: depth= 8 min= 9.0(0.035) max= 234.0(0.918) mean= 105.3(0.413) stdev= 34.1(0.134)
GrayChannel: depth= 8 min= 38.0(0.149) max= 255.0(1.000) mean= 180.0(0.706) stdev= 49.4(0.194)


before RotateImage: degree=5.000000
after MagickRotateImage: background_color=rgb(0,0,0)[%s]
img_depth=8
RedChannel: depth=32 min= -16.6(-0.065) max= 271.0(1.063) mean= 152.6(0.599) stdev= 78.8(0.309)
GreenChannel: depth=32 min= -14.1(-0.055) max= 241.9(0.949) mean= 84.3(0.331) stdev= 60.0(0.235)
BlueChannel: depth=32 min= -11.9(-0.047) max= 228.5(0.896) mean= 89.3(0.350) stdev= 49.0(0.192)
GrayChannel: depth=32 min= -16.6(-0.065) max= 271.0(1.063) mean= 152.6(0.599) stdev= 78.8(0.309)
...

I.e., after rotation the minimal pixel values are negative and the maximal red value is larger than 255. The channel depths changed from 8 to 32.
If I test the result with identify, I see the following values:

rose@moose:/home_moose/rose/Txt/src/Test/C/ImageMagick/Wand(407)$ identify -verbose OutImages/lena_rotated.png
Image: OutImages/lena_rotated.png
Format: PNG (Portable Network Graphics)
Class: DirectClass
Geometry: 556x556+0+0
...
Channel depth:
red: 8-bit
green: 8-bit
blue: 8-bit
Channel statistics:
Red:
min: 0 (0)
max: 255 (1)
mean: 152.666 (0.598692)
standard deviation: 78.7507 (0.308826)
kurtosis: -0.538735
skewness: -0.857874
Green:
min: 0 (0)
max: 242 (0.94902)
mean: 84.341 (0.330749)
standard deviation: 60.0008 (0.235297)
kurtosis: -0.915871
skewness: 0.210762
Blue:
min: 0 (0)
max: 229 (0.898039)
mean: 89.3244 (0.350292)
standard deviation: 48.9691 (0.192036)
kurtosis: -0.278467
skewness: -0.307794
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 108.777 (0.426577)
standard deviation: 63.7697 (0.250077)
kurtosis: 0.151732
skewness: 0.0844437


I.e., the channel depths are again 8, the negative minima disapeared, the maxima are not larger than 255. Mean and stdev are the same I got. So the rotated output looks nice. If I try to repeate the same procedure with a 16 bit tiff, the writing of the rotated image fails:

rose@moose:/home_moose/rose/Txt/src/Test/C/ImageMagick/Wand(408)$ rotate-image_with_getChannelRange 12Anti9_HgF2_100V_21x5s_40x__p008.tiff 12Anti9_HgF2_100V_21x5s_40x__p008_rotated.tiff
IM_quantum_depth_str=|Q32| IM_quantum_depth=|32| img_depth=16 quantum_format=|(null)|
1L<<IM_quantum_depth=4294967296 max_IM_val=$Lu max_img_val=4294967296
img_depth=16
RedChannel: depth=16 min= 5.0(0.000) max= 65295.0(0.996) mean= 32804.1(0.501) stdev= 19002.5(0.290)
GreenChannel: depth=16 min= 5.0(0.000) max= 65295.0(0.996) mean= 32804.1(0.501) stdev= 19002.5(0.290)
BlueChannel: depth=16 min= 5.0(0.000) max= 65295.0(0.996) mean= 32804.1(0.501) stdev= 19002.5(0.290)
GrayChannel: depth=16 min= 5.0(0.000) max= 65295.0(0.996) mean= 32804.1(0.501) stdev= 19002.5(0.290)


before RotateImage: degree=5.000000
after MagickRotateImage: background_color=rgb(0,0,0)[%s]
img_depth=16
RedChannel: depth=32 min=-11444.1(-0.175) max= 74949.4(1.144) mean= 27685.1(0.422) stdev= 19288.0(0.294)
GreenChannel: depth=32 min=-11444.1(-0.175) max= 74949.4(1.144) mean= 27685.1(0.422) stdev= 19288.0(0.294)
BlueChannel: depth=32 min=-11444.1(-0.175) max= 74949.4(1.144) mean= 27685.1(0.422) stdev= 19288.0(0.294)
GrayChannel: depth=32 min=-11444.1(-0.175) max= 74949.4(1.144) mean= 27685.1(0.422) stdev= 19288.0(0.294)


before MagickWriteImages(rotated_wand,OutImages/12Anti9_HgF2_100V_21x5s_40x__p008_rotated.tiff,):
rotate-image_with_getChannelRange: tif_dirwrite.c:2084: TIFFWriteDirectoryTagCheckedRational: Assertion `value>=0.0' failed.
Abgebrochen


I will deeply appreciate any hint, how to handle this issue.

Re: New strange results of GetImageChannelRange after Rotate

Posted: 2012-02-03T03:14:43-07:00
by jrrose
BTW, can anybody give me a hint, which algorithms is used, that some pixel values become negative or larger than the former maximal value (255)?