cout << " unsharp mask ..." << endl;
example = model;
example.label( "Unsharp Mask" );
- // radius_, sigma_, gain_
- example.unsharpmask( 0.0, 1.0, 1.0);
+ // radius_, sigma_, amount_, threshold_
+ example.unsharpmask( 0.0, 1.0, 1.0, 0.05);
images.push_back( example );
cout << " wave ..." << endl;
// the threshold in pixels needed to apply the diffence amount.
void Magick::Image::unsharpmask ( const double radius_,
const double sigma_,
- const double gain_ )
+ const double amount_,
+ const double threshold_ )
{
ExceptionInfo exceptionInfo;
GetExceptionInfo( &exceptionInfo );
UnsharpMaskImage( image(),
radius_,
sigma_,
- gain_,
+ amount_,
+ threshold_,
&exceptionInfo );
replaceImage( newImage );
throwException( exceptionInfo );
void Magick::Image::unsharpmaskChannel ( const ChannelType channel_,
const double radius_,
const double sigma_,
- const double gain_ )
+ const double amount_,
+ const double threshold_ )
{
ExceptionInfo exceptionInfo;
GetExceptionInfo( &exceptionInfo );
UnsharpMaskImage( image(),
radius_,
sigma_,
- gain_,
+ amount_,
+ threshold_,
&exceptionInfo );
(void) SetPixelChannelMask( image(), channel_mask );
replaceImage( newImage );
void crop ( const Geometry &geometry_ );
// Cycle image colormap
- void cycleColormap ( const ::ssize_t gain_ );
+ void cycleColormap ( const ::ssize_t amount_ );
// Despeckle image (reduce speckle noise)
void despeckle ( void );
void splice ( const Geometry &geometry_ );
// Spread pixels randomly within image by specified ammount
- void spread ( const size_t gain_ = 3 );
+ void spread ( const size_t amount_ = 3 );
// Sparse color image, given a set of coordinates, interpolates the colors
// found at those coordinates, across the whole image, using various
// center pixel.
// sigma_
// the standard deviation of the Gaussian, in pixels.
- // gain_
+ // amount_
// the percentage of the difference between the original and
// the blur image that is added back into the original.
// threshold_
// the threshold in pixels needed to apply the diffence amount.
void unsharpmask ( const double radius_,
const double sigma_,
- const double gain_ );
+ const double amount_,
+ const double threshold_ );
void unsharpmaskChannel ( const ChannelType channel_,
const double radius_,
const double sigma_,
- const double gain_ );
+ const double amount_,
+ const double threshold_ );
// Map image pixels to a sine wave
void wave ( const double amplitude_ = 25.0,
class MagickPPExport edgeImage : public std::unary_function<Image&,void>
{
public:
- edgeImage( const double radius_ = 0.0 );
+ edgeImage( const double radius_ = 0.0, const double sigma_ = 0.5 );
void operator()( Image &image_ ) const;
private:
double _radius;
+ double _sigma;
};
// Emboss image (hilight edges with 3D effect)
% The format of the UnsharpMaskImage method is:
%
% Image *UnsharpMaskImage(const Image *image,const double radius,
-% const double sigma,const double gain,ExceptionInfo *exception)
+% const double sigma,const double amount,const double threshold,
+% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o gain: the percentage of the difference between the original and the
% blur image that is added back into the original.
%
+% o threshold: the threshold in pixels needed to apply the diffence gain.
+%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
- const double sigma,const double gain,ExceptionInfo *exception)
+ const double sigma,const double gain,const double threshold,
+ ExceptionInfo *exception)
{
- char
- geometry[MaxTextExtent];
+#define SharpenImageTag "Sharpen/Image"
- KernelInfo
- *kernel_info;
+ CacheView
+ *image_view,
+ *unsharp_view;
Image
*unsharp_image;
+ MagickBooleanType
+ status;
+
+ MagickOffsetType
+ progress;
+
+ double
+ quantum_threshold;
+
+ ssize_t
+ y;
+
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);
- (void) FormatLocaleString(geometry,MaxTextExtent,"Blur:%.20gx%.20g>",
- radius,sigma);
- kernel_info=AcquireKernelInfo(geometry);
- if (kernel_info == (KernelInfo *) NULL)
- ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
- (void) FormatLocaleString(geometry,MaxTextExtent,"%.20g,%.20g%%",
- -100.0+gain*100.0,200.0-gain*100.0);
- ScaleGeometryKernelInfo(kernel_info,geometry);
- unsharp_image=MorphologyImage(image,ConvolveMorphology,1,kernel_info,
- exception);
- kernel_info=DestroyKernelInfo(kernel_info);
+ unsharp_image=BlurImage(image,radius,sigma,exception);
+ if (unsharp_image == (Image *) NULL)
+ return((Image *) NULL);
+ quantum_threshold=(double) QuantumRange*threshold;
+ /*
+ Unsharp-mask image.
+ */
+ status=MagickTrue;
+ progress=0;
+ image_view=AcquireVirtualCacheView(image,exception);
+ unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(static,4) shared(progress,status) \
+ magick_threads(image,unsharp_image,image->rows,1)
+#endif
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ register const Quantum
+ *restrict p;
+
+ register Quantum
+ *restrict q;
+
+ register ssize_t
+ x;
+
+ if (status == MagickFalse)
+ continue;
+ p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+ q=QueueCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
+ exception);
+ if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+ {
+ status=MagickFalse;
+ continue;
+ }
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ register ssize_t
+ i;
+
+ for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+ {
+ double
+ pixel;
+
+ PixelChannel
+ channel;
+
+ PixelTrait
+ traits,
+ unsharp_traits;
+
+ channel=GetPixelChannelChannel(image,i);
+ traits=GetPixelChannelTraits(image,channel);
+ unsharp_traits=GetPixelChannelTraits(unsharp_image,channel);
+ if ((traits == UndefinedPixelTrait) ||
+ (unsharp_traits == UndefinedPixelTrait))
+ continue;
+ if (((unsharp_traits & CopyPixelTrait) != 0) ||
+ (GetPixelMask(image,p) != 0))
+ {
+ SetPixelChannel(unsharp_image,channel,p[i],q);
+ continue;
+ }
+ pixel=p[i]-(double) GetPixelChannel(unsharp_image,channel,q);
+ if (fabs(2.0*pixel) < quantum_threshold)
+ pixel=(double) p[i];
+ else
+ pixel=(double) p[i]+gain*pixel;
+ SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
+ }
+ p+=GetPixelChannels(image);
+ q+=GetPixelChannels(unsharp_image);
+ }
+ if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
+ status=MagickFalse;
+ if (image->progress_monitor != (MagickProgressMonitor) NULL)
+ {
+ MagickBooleanType
+ proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp critical (MagickCore_UnsharpMaskImage)
+#endif
+ proceed=SetImageProgress(image,SharpenImageTag,progress++,image->rows);
+ if (proceed == MagickFalse)
+ status=MagickFalse;
+ }
+ }
+ unsharp_image->type=image->type;
+ unsharp_view=DestroyCacheView(unsharp_view);
+ image_view=DestroyCacheView(image_view);
+ if (status == MagickFalse)
+ unsharp_image=DestroyImage(unsharp_image);
return(unsharp_image);
}
*SpreadImage(const Image *,const double,const PixelInterpolateMethod,
ExceptionInfo *),
*UnsharpMaskImage(const Image *,const double,const double,const double,
- ExceptionInfo *);
+ const double,ExceptionInfo *);
#if defined(__cplusplus) || defined(c_plusplus)
}
% The format of the MagickUnsharpMaskImage method is:
%
% MagickBooleanType MagickUnsharpMaskImage(MagickWand *wand,
-% const double radius,const double sigma,const double gain)
+% const double radius,const double sigma,const double gain,
+% const double threshold)
%
% A description of each parameter follows:
%
% o gain: the percentage of the difference between the original and the
% blur image that is added back into the original.
%
+% o threshold: the threshold in pixels needed to apply the diffence gain.
+%
*/
WandExport MagickBooleanType MagickUnsharpMaskImage(MagickWand *wand,
- const double radius,const double sigma,const double gain)
+ const double radius,const double sigma,const double gain,
+ const double threshold)
{
Image
*unsharp_image;
(void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
if (wand->images == (Image *) NULL)
ThrowWandException(WandError,"ContainsNoImages",wand->name);
- unsharp_image=UnsharpMaskImage(wand->images,radius,sigma,gain,
+ unsharp_image=UnsharpMaskImage(wand->images,radius,sigma,gain,threshold,
wand->exception);
if (unsharp_image == (Image *) NULL)
return(MagickFalse);
MagickThumbnailImage(MagickWand *,const size_t,const size_t),
MagickTrimImage(MagickWand *,const double),
MagickUniqueImageColors(MagickWand *),
- MagickUnsharpMaskImage(MagickWand *,const double,const double,const double),
+ MagickUnsharpMaskImage(MagickWand *,const double,const double,const double,
+ const double),
MagickVignetteImage(MagickWand *,const double,const double,const ssize_t,
const ssize_t),
MagickWaveImage(MagickWand *,const double,const double,
if ((flags & PsiValue) == 0)
geometry_info.psi=0.05;
mogrify_image=UnsharpMaskImage(*image,geometry_info.rho,
- geometry_info.sigma,geometry_info.xi,exception);
+ geometry_info.sigma,geometry_info.xi,geometry_info.psi,
+ exception);
break;
}
break;
if ((flags & PsiValue) == 0)
geometry_info.psi=0.05;
new_image=UnsharpMaskImage(_image,geometry_info.rho,
- geometry_info.sigma,geometry_info.xi,_exception);
+ geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
break;
}
CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
{ "black-point-compensation", MagickBooleanOptions} } },
{ "UnsharpMask", { {"geometry", StringReference},
{"radius", RealReference}, {"sigma", RealReference},
- {"gain", RealReference}, {"channel", MagickChannelOptions} } },
+ {"gain", RealReference}, {"threshold", RealReference},
+ {"channel", MagickChannelOptions} } },
{ "MotionBlur", { {"geometry", StringReference},
{"radius", RealReference}, {"sigma", RealReference},
{"angle", RealReference}, {"channel", MagickChannelOptions} } },
if (attribute_flag[3] != 0)
geometry_info.xi=argument_list[3].real_reference;
if (attribute_flag[4] != 0)
- channel=(ChannelType) argument_list[4].integer_reference;
+ geometry_info.psi=argument_list[4].real_reference;
+ if (attribute_flag[5] != 0)
+ channel=(ChannelType) argument_list[5].integer_reference;
channel_mask=SetImageChannelMask(image,channel);
image=UnsharpMaskImage(image,geometry_info.rho,geometry_info.sigma,
- geometry_info.xi,exception);
+ geometry_info.xi,geometry_info.psi,exception);
if (image != (Image *) NULL)
(void) SetImageChannelMask(image,channel_mask);
break;