morphology.c revision 5e6b259130f9dbe0da4666f734937017babe573a
1701db3105315e7d7d9cf2734ae94524c6bc38e80cristy/* 2701db3105315e7d7d9cf2734ae94524c6bc38e80cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 4701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 5701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 6701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% M M OOO RRRR PPPP H H OOO L OOO GGGG Y Y % 7701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% MM MM O O R R P P H H O O L O O G Y Y % 8701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% M M M O O RRRR PPPP HHHHH O O L O O G GGG Y % 9701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% M M O O R R P H H O O L O O G G Y % 10701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% M M OOO R R P H H OOO LLLLL OOO GGG Y % 11701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 12701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 13701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% MagickCore Morphology Methods % 14701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 15701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% Software Design % 16701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% Anthony Thyssen % 17c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% January 2010 % 18701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 19701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 2045ef08fd6a09813e4a8f5ddadf85ba9e0ec2cdc7cristy% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization % 21701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% dedicated to making software imaging solutions freely available. % 22701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 23701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% You may not use this file except in compliance with the License. You may % 24701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% obtain a copy of the License at % 25701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 26701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% http://www.imagemagick.org/script/license.php % 27701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 28701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% Unless required by applicable law or agreed to in writing, software % 29701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% distributed under the License is distributed on an "AS IS" BASIS, % 30701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% See the License for the specific language governing permissions and % 32701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% limitations under the License. % 33701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 34701db3105315e7d7d9cf2734ae94524c6bc38e80cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% 361b2bc0a7da432e6e1cc0480280402df213faa940anthony% Morpology is the the application of various kernels, of any size and even 37602ab9b30b644a78a4057da93d838a77391ec0acanthony% shape, to a image in various ways (typically binary, but not always). 38701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% 39602ab9b30b644a78a4057da93d838a77391ec0acanthony% Convolution (weighted sum or average) is just one specific type of 40602ab9b30b644a78a4057da93d838a77391ec0acanthony% morphology. Just one that is very common for image bluring and sharpening 41602ab9b30b644a78a4057da93d838a77391ec0acanthony% effects. Not only 2D Gaussian blurring, but also 2-pass 1D Blurring. 42602ab9b30b644a78a4057da93d838a77391ec0acanthony% 43602ab9b30b644a78a4057da93d838a77391ec0acanthony% This module provides not only a general morphology function, and the ability 44602ab9b30b644a78a4057da93d838a77391ec0acanthony% to apply more advanced or iterative morphologies, but also functions for the 45602ab9b30b644a78a4057da93d838a77391ec0acanthony% generation of many different types of kernel arrays from user supplied 46602ab9b30b644a78a4057da93d838a77391ec0acanthony% arguments. Prehaps even the generation of a kernel from a small image. 47701db3105315e7d7d9cf2734ae94524c6bc38e80cristy*/ 48701db3105315e7d7d9cf2734ae94524c6bc38e80cristy 49701db3105315e7d7d9cf2734ae94524c6bc38e80cristy/* 50701db3105315e7d7d9cf2734ae94524c6bc38e80cristy Include declarations. 51701db3105315e7d7d9cf2734ae94524c6bc38e80cristy*/ 524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h" 534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/artifact.h" 544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache-view.h" 554c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color-private.h" 564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/enhance.h" 574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h" 584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h" 594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/gem.h" 608ea81224e9ff022e56eb2cddb12860a8b2e90411cristy#include "MagickCore/gem-private.h" 614c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/hashmap.h" 624c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h" 634c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h" 644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/list.h" 654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/magick.h" 664c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h" 67e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy#include "MagickCore/memory-private.h" 684c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h" 694c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/morphology.h" 704c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/morphology-private.h" 714c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/option.h" 724c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h" 734c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/prepress.h" 744c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantize.h" 75ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy#include "MagickCore/resource_.h" 764c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/registry.h" 774c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/semaphore.h" 784c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/splay-tree.h" 794c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/statistic.h" 804c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h" 814c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string-private.h" 8216881e68c6165c6191fc44151a8a4320e3dd1ffdcristy#include "MagickCore/thread-private.h" 834c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/token.h" 844c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/utility.h" 85d1dd6e4fefa0810b9893e6ac9418f79c97c1b39acristy#include "MagickCore/utility-private.h" 86a29d45f897949f04a47bb3da077395969f13dcbacristy 87c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony 88c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony/* 89c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** The following test is for special floating point numbers of value NaN (not 90c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** a number), that may be used within a Kernel Definition. NaN's are defined 91c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** as part of the IEEE standard for floating point number representation. 92c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** 93c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** These are used as a Kernel value to mean that this kernel position is not 94c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** part of the kernel neighbourhood for convolution or morphology processing, 95c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** and thus should be ignored. This allows the use of 'shaped' kernels. 96c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** 9797fc9f3f47bd7bb92d17366594e1b77c9072660ccristy** The special property that two NaN's are never equal, even if they are from 98c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** the same variable allow you to test if a value is special NaN value. 99c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** 100c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** This macro IsNaN() is thus is only true if the value given is NaN. 101a29d45f897949f04a47bb3da077395969f13dcbacristy*/ 102602ab9b30b644a78a4057da93d838a77391ec0acanthony#define IsNan(a) ((a)!=(a)) 103602ab9b30b644a78a4057da93d838a77391ec0acanthony 10429188a8682a98d4b7882cca434b170517555fc7danthony/* 105a29d45f897949f04a47bb3da077395969f13dcbacristy Other global definitions used by module. 106a29d45f897949f04a47bb3da077395969f13dcbacristy*/ 10729188a8682a98d4b7882cca434b170517555fc7danthonystatic inline double MagickMin(const double x,const double y) 10829188a8682a98d4b7882cca434b170517555fc7danthony{ 10929188a8682a98d4b7882cca434b170517555fc7danthony return( x < y ? x : y); 11029188a8682a98d4b7882cca434b170517555fc7danthony} 11129188a8682a98d4b7882cca434b170517555fc7danthonystatic inline double MagickMax(const double x,const double y) 11229188a8682a98d4b7882cca434b170517555fc7danthony{ 11329188a8682a98d4b7882cca434b170517555fc7danthony return( x > y ? x : y); 11429188a8682a98d4b7882cca434b170517555fc7danthony} 11529188a8682a98d4b7882cca434b170517555fc7danthony#define Minimize(assign,value) assign=MagickMin(assign,value) 11629188a8682a98d4b7882cca434b170517555fc7danthony#define Maximize(assign,value) assign=MagickMax(assign,value) 11729188a8682a98d4b7882cca434b170517555fc7danthony 11840ca0b982379d4ab2716435a46603d56b5b218b1anthony/* Integer Factorial Function - for a Binomial kernel */ 11940ca0b982379d4ab2716435a46603d56b5b218b1anthony#if 1 12040ca0b982379d4ab2716435a46603d56b5b218b1anthonystatic inline size_t fact(size_t n) 12140ca0b982379d4ab2716435a46603d56b5b218b1anthony{ 122f13c594b1d9509e479fd845c3b8a5bb1351c32eacristy size_t f,l; 12340ca0b982379d4ab2716435a46603d56b5b218b1anthony for(f=1, l=2; l <= n; f=f*l, l++); 12440ca0b982379d4ab2716435a46603d56b5b218b1anthony return(f); 12540ca0b982379d4ab2716435a46603d56b5b218b1anthony} 12640ca0b982379d4ab2716435a46603d56b5b218b1anthony#elif 1 /* glibc floating point alternatives */ 12740ca0b982379d4ab2716435a46603d56b5b218b1anthony#define fact(n) ((size_t)tgamma((double)n+1)) 12840ca0b982379d4ab2716435a46603d56b5b218b1anthony#else 12940ca0b982379d4ab2716435a46603d56b5b218b1anthony#define fact(n) ((size_t)lgamma((double)n+1)) 13040ca0b982379d4ab2716435a46603d56b5b218b1anthony#endif 13140ca0b982379d4ab2716435a46603d56b5b218b1anthony 13240ca0b982379d4ab2716435a46603d56b5b218b1anthony 133c4c86e0ad78bebf6b9f931a659fb82987a7042e3anthony/* Currently these are only internal to this module */ 134c4c86e0ad78bebf6b9f931a659fb82987a7042e3anthonystatic void 13546a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(KernelInfo *), 136bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(KernelInfo *), 137bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(KernelInfo *, const double), 138ef656913b0b30d713ae94c82c47693c9dc69c9f4cristy RotateKernelInfo(KernelInfo *, double); 139602ab9b30b644a78a4057da93d838a77391ec0acanthony 1403dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony 1413dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony/* Quick function to find last kernel in a kernel list */ 1423dd0f620e7a1d12f747ce167844cd7269bfa9f12anthonystatic inline KernelInfo *LastKernelInfo(KernelInfo *kernel) 1433dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony{ 1443dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony while (kernel->next != (KernelInfo *) NULL) 1453dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony kernel = kernel->next; 1463dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony return(kernel); 1473dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony} 1483dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony 149602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 150602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 151602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 152602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 153602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 15483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A c q u i r e K e r n e l I n f o % 155602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 156602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 157602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 158602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 159602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1602be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% AcquireKernelInfo() takes the given string (generally supplied by the 161602ab9b30b644a78a4057da93d838a77391ec0acanthony% user) and converts it into a Morphology/Convolution Kernel. This allows 162602ab9b30b644a78a4057da93d838a77391ec0acanthony% users to specify a kernel from a number of pre-defined kernels, or to fully 163602ab9b30b644a78a4057da93d838a77391ec0acanthony% specify their own kernel for a specific Convolution or Morphology 164602ab9b30b644a78a4057da93d838a77391ec0acanthony% Operation. 165602ab9b30b644a78a4057da93d838a77391ec0acanthony% 166602ab9b30b644a78a4057da93d838a77391ec0acanthony% The kernel so generated can be any rectangular array of floating point 167602ab9b30b644a78a4057da93d838a77391ec0acanthony% values (doubles) with the 'control point' or 'pixel being affected' 168602ab9b30b644a78a4057da93d838a77391ec0acanthony% anywhere within that array of values. 169602ab9b30b644a78a4057da93d838a77391ec0acanthony% 17083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% Previously IM was restricted to a square of odd size using the exact 17119910ef25dd3d99d1981a9e42c934133170ee714anthony% center as origin, this is no longer the case, and any rectangular kernel 17283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% with any value being declared the origin. This in turn allows the use of 17383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% highly asymmetrical kernels. 174602ab9b30b644a78a4057da93d838a77391ec0acanthony% 175602ab9b30b644a78a4057da93d838a77391ec0acanthony% The floating point values in the kernel can also include a special value 17683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% known as 'nan' or 'not a number' to indicate that this value is not part 17783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% of the kernel array. This allows you to shaped the kernel within its 17883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% rectangular area. That is 'nan' values provide a 'mask' for the kernel 17983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% shape. However at least one non-nan value must be provided for correct 18083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% working of a kernel. 181602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1827a01dcf50ce12cb2a789bedff51e9345f022432eanthony% The returned kernel should be freed using the DestroyKernelInfo() when you 1837a01dcf50ce12cb2a789bedff51e9345f022432eanthony% are finished with it. Do not free this memory yourself. 184602ab9b30b644a78a4057da93d838a77391ec0acanthony% 185602ab9b30b644a78a4057da93d838a77391ec0acanthony% Input kernel defintion strings can consist of any of three types. 186602ab9b30b644a78a4057da93d838a77391ec0acanthony% 187bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% "name:args[[@><]" 18829188a8682a98d4b7882cca434b170517555fc7danthony% Select from one of the built in kernels, using the name and 18929188a8682a98d4b7882cca434b170517555fc7danthony% geometry arguments supplied. See AcquireKernelBuiltIn() 190602ab9b30b644a78a4057da93d838a77391ec0acanthony% 191bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% "WxH[+X+Y][@><]:num, num, num ..." 1921b2bc0a7da432e6e1cc0480280402df213faa940anthony% a kernel of size W by H, with W*H floating point numbers following. 193602ab9b30b644a78a4057da93d838a77391ec0acanthony% the 'center' can be optionally be defined at +X+Y (such that +0+0 19429188a8682a98d4b7882cca434b170517555fc7danthony% is top left corner). If not defined the pixel in the center, for 19529188a8682a98d4b7882cca434b170517555fc7danthony% odd sizes, or to the immediate top or left of center for even sizes 19629188a8682a98d4b7882cca434b170517555fc7danthony% is automatically selected. 197602ab9b30b644a78a4057da93d838a77391ec0acanthony% 19829188a8682a98d4b7882cca434b170517555fc7danthony% "num, num, num, num, ..." 19929188a8682a98d4b7882cca434b170517555fc7danthony% list of floating point numbers defining an 'old style' odd sized 20029188a8682a98d4b7882cca434b170517555fc7danthony% square kernel. At least 9 values should be provided for a 3x3 20129188a8682a98d4b7882cca434b170517555fc7danthony% square kernel, 25 for a 5x5 square kernel, 49 for 7x7, etc. 20229188a8682a98d4b7882cca434b170517555fc7danthony% Values can be space or comma separated. This is not recommended. 203602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2047a01dcf50ce12cb2a789bedff51e9345f022432eanthony% You can define a 'list of kernels' which can be used by some morphology 2051e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp% operators A list is defined as a semi-colon separated list kernels. 2067a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 207dbc8989a61339951c6434d9a43e7b6fefb5da374anthony% " kernel ; kernel ; kernel ; " 2087a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 2091dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% Any extra ';' characters, at start, end or between kernel defintions are 21043c4925e5305a26e48d68f7893e94f55d0831c39anthony% simply ignored. 21143c4925e5305a26e48d68f7893e94f55d0831c39anthony% 212bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The special flags will expand a single kernel, into a list of rotated 213bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% kernels. A '@' flag will expand a 3x3 kernel into a list of 45-degree 214bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% cyclic rotations, while a '>' will generate a list of 90-degree rotations. 215bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The '<' also exands using 90-degree rotates, but giving a 180-degree 216bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% reflected kernel before the +/- 90-degree rotations, which can be important 217bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% for Thinning operations. 218bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 21943c4925e5305a26e48d68f7893e94f55d0831c39anthony% Note that 'name' kernels will start with an alphabetic character while the 22043c4925e5305a26e48d68f7893e94f55d0831c39anthony% new kernel specification has a ':' character in its specification string. 22143c4925e5305a26e48d68f7893e94f55d0831c39anthony% If neither is the case, it is assumed an old style of a simple list of 22243c4925e5305a26e48d68f7893e94f55d0831c39anthony% numbers generating a odd-sized square kernel has been given. 2237a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 224602ab9b30b644a78a4057da93d838a77391ec0acanthony% The format of the AcquireKernal method is: 225602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2262be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% KernelInfo *AcquireKernelInfo(const char *kernel_string) 227602ab9b30b644a78a4057da93d838a77391ec0acanthony% 228602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 229602ab9b30b644a78a4057da93d838a77391ec0acanthony% 230602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel_string: the Morphology/Convolution kernel wanted. 231602ab9b30b644a78a4057da93d838a77391ec0acanthony% 232602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 233602ab9b30b644a78a4057da93d838a77391ec0acanthony 234c84dce50867229e4872193e8eed5dbab58eb9f02anthony/* This was separated so that it could be used as a separate 2355ef8e94ff55717be2387d537bd49025780a1a558anthony** array input handling function, such as for -color-matrix 236c84dce50867229e4872193e8eed5dbab58eb9f02anthony*/ 2375ef8e94ff55717be2387d537bd49025780a1a558anthonystatic KernelInfo *ParseKernelArray(const char *kernel_string) 238602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 2392be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy KernelInfo 240602ab9b30b644a78a4057da93d838a77391ec0acanthony *kernel; 241602ab9b30b644a78a4057da93d838a77391ec0acanthony 242602ab9b30b644a78a4057da93d838a77391ec0acanthony char 243602ab9b30b644a78a4057da93d838a77391ec0acanthony token[MaxTextExtent]; 244602ab9b30b644a78a4057da93d838a77391ec0acanthony 245602ab9b30b644a78a4057da93d838a77391ec0acanthony const char 2465ef8e94ff55717be2387d537bd49025780a1a558anthony *p, 2475ef8e94ff55717be2387d537bd49025780a1a558anthony *end; 248602ab9b30b644a78a4057da93d838a77391ec0acanthony 249bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 250c84dce50867229e4872193e8eed5dbab58eb9f02anthony i; 251602ab9b30b644a78a4057da93d838a77391ec0acanthony 25229188a8682a98d4b7882cca434b170517555fc7danthony double 25329188a8682a98d4b7882cca434b170517555fc7danthony nan = sqrt((double)-1.0); /* Special Value : Not A Number */ 25429188a8682a98d4b7882cca434b170517555fc7danthony 25543c4925e5305a26e48d68f7893e94f55d0831c39anthony MagickStatusType 25643c4925e5305a26e48d68f7893e94f55d0831c39anthony flags; 25743c4925e5305a26e48d68f7893e94f55d0831c39anthony 25843c4925e5305a26e48d68f7893e94f55d0831c39anthony GeometryInfo 25943c4925e5305a26e48d68f7893e94f55d0831c39anthony args; 26043c4925e5305a26e48d68f7893e94f55d0831c39anthony 261a64b85d7873d5e540fe6e2941aa98ec7653a4e2dcristy kernel=(KernelInfo *) AcquireQuantumMemory(1,sizeof(*kernel)); 2622be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy if (kernel == (KernelInfo *)NULL) 263602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 264602ab9b30b644a78a4057da93d838a77391ec0acanthony (void) ResetMagickMemory(kernel,0,sizeof(*kernel)); 26543c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->minimum = kernel->maximum = kernel->angle = 0.0; 2667a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel->negative_range = kernel->positive_range = 0.0; 267602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->type = UserDefinedKernel; 2687a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel->next = (KernelInfo *) NULL; 269d43a46bc9598004091eae232bc7938e009b494a1cristy kernel->signature = MagickSignature; 2705e6be1e6a77c230e4a204fa9163d873104730c35cristy if (kernel_string == (const char *) NULL) 2715e6be1e6a77c230e4a204fa9163d873104730c35cristy return(kernel); 272602ab9b30b644a78a4057da93d838a77391ec0acanthony 2735ef8e94ff55717be2387d537bd49025780a1a558anthony /* find end of this specific kernel definition string */ 2745ef8e94ff55717be2387d537bd49025780a1a558anthony end = strchr(kernel_string, ';'); 2755ef8e94ff55717be2387d537bd49025780a1a558anthony if ( end == (char *) NULL ) 2765ef8e94ff55717be2387d537bd49025780a1a558anthony end = strchr(kernel_string, '\0'); 2775ef8e94ff55717be2387d537bd49025780a1a558anthony 278a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* clear flags - for Expanding kernel lists thorugh rotations */ 27943c4925e5305a26e48d68f7893e94f55d0831c39anthony flags = NoValue; 28043c4925e5305a26e48d68f7893e94f55d0831c39anthony 281f68116b9d5afef3c343faeb599a3c0ffc8e9b244anthony /* Has a ':' in argument - New user kernel specification 282f68116b9d5afef3c343faeb599a3c0ffc8e9b244anthony FUTURE: this split on ':' could be done by StringToken() 283f68116b9d5afef3c343faeb599a3c0ffc8e9b244anthony */ 284602ab9b30b644a78a4057da93d838a77391ec0acanthony p = strchr(kernel_string, ':'); 2855ef8e94ff55717be2387d537bd49025780a1a558anthony if ( p != (char *) NULL && p < end) 286602ab9b30b644a78a4057da93d838a77391ec0acanthony { 287602ab9b30b644a78a4057da93d838a77391ec0acanthony /* ParseGeometry() needs the geometry separated! -- Arrgghh */ 288150989ed67ef9da53141a65e5f3ebdb05dd025abcristy memcpy(token, kernel_string, (size_t) (p-kernel_string)); 289602ab9b30b644a78a4057da93d838a77391ec0acanthony token[p-kernel_string] = '\0'; 290c84dce50867229e4872193e8eed5dbab58eb9f02anthony SetGeometryInfo(&args); 291602ab9b30b644a78a4057da93d838a77391ec0acanthony flags = ParseGeometry(token, &args); 292602ab9b30b644a78a4057da93d838a77391ec0acanthony 29329188a8682a98d4b7882cca434b170517555fc7danthony /* Size handling and checks of geometry settings */ 294602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( (flags & WidthValue) == 0 ) /* if no width then */ 295602ab9b30b644a78a4057da93d838a77391ec0acanthony args.rho = args.sigma; /* then width = height */ 296602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.rho < 1.0 ) /* if width too small */ 297602ab9b30b644a78a4057da93d838a77391ec0acanthony args.rho = 1.0; /* then width = 1 */ 298602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.sigma < 1.0 ) /* if height too small */ 299602ab9b30b644a78a4057da93d838a77391ec0acanthony args.sigma = args.rho; /* then height = width */ 300bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args.rho; 301bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t)args.sigma; 302602ab9b30b644a78a4057da93d838a77391ec0acanthony 303602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Offset Handling and Checks */ 304602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.xi < 0.0 || args.psi < 0.0 ) 30583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 306bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi 307ea068a53d23d6dca08f1bce44c8937d54f83b983anthony : (ssize_t) (kernel->width-1)/2; 308bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi 309ea068a53d23d6dca08f1bce44c8937d54f83b983anthony : (ssize_t) (kernel->height-1)/2; 310bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( kernel->x >= (ssize_t) kernel->width || 311bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y >= (ssize_t) kernel->height ) 31283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 313602ab9b30b644a78a4057da93d838a77391ec0acanthony 314602ab9b30b644a78a4057da93d838a77391ec0acanthony p++; /* advance beyond the ':' */ 315602ab9b30b644a78a4057da93d838a77391ec0acanthony } 316602ab9b30b644a78a4057da93d838a77391ec0acanthony else 317c84dce50867229e4872193e8eed5dbab58eb9f02anthony { /* ELSE - Old old specification, forming odd-square kernel */ 318602ab9b30b644a78a4057da93d838a77391ec0acanthony /* count up number of values given */ 319602ab9b30b644a78a4057da93d838a77391ec0acanthony p=(const char *) kernel_string; 320a699b171eff7e0178463e8f271b35a3cbb995f0ecristy while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\'')) 32129188a8682a98d4b7882cca434b170517555fc7danthony p++; /* ignore "'" chars for convolve filter usage - Cristy */ 3225ef8e94ff55717be2387d537bd49025780a1a558anthony for (i=0; p < end; i++) 323602ab9b30b644a78a4057da93d838a77391ec0acanthony { 324602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 325602ab9b30b644a78a4057da93d838a77391ec0acanthony if (*token == ',') 326602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 327602ab9b30b644a78a4057da93d838a77391ec0acanthony } 328602ab9b30b644a78a4057da93d838a77391ec0acanthony /* set the size of the kernel - old sized square */ 329bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height= (size_t) sqrt((double) i+1.0); 330bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 331602ab9b30b644a78a4057da93d838a77391ec0acanthony p=(const char *) kernel_string; 33229188a8682a98d4b7882cca434b170517555fc7danthony while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\'')) 33329188a8682a98d4b7882cca434b170517555fc7danthony p++; /* ignore "'" chars for convolve filter usage - Cristy */ 334602ab9b30b644a78a4057da93d838a77391ec0acanthony } 335602ab9b30b644a78a4057da93d838a77391ec0acanthony 336602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Read in the kernel values from rest of input string argument */ 337e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory( 338e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->width,kernel->height*sizeof(*kernel->values))); 339d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 34083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 341c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->minimum = +MagickHuge; 342c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = -MagickHuge; 343c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 344bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++) 345602ab9b30b644a78a4057da93d838a77391ec0acanthony { 346602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 347602ab9b30b644a78a4057da93d838a77391ec0acanthony if (*token == ',') 348602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 34929188a8682a98d4b7882cca434b170517555fc7danthony if ( LocaleCompare("nan",token) == 0 350c84dce50867229e4872193e8eed5dbab58eb9f02anthony || LocaleCompare("-",token) == 0 ) { 351ea068a53d23d6dca08f1bce44c8937d54f83b983anthony kernel->values[i] = nan; /* this value is not part of neighbourhood */ 35229188a8682a98d4b7882cca434b170517555fc7danthony } 35329188a8682a98d4b7882cca434b170517555fc7danthony else { 3540ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony kernel->values[i] = StringToDouble(token,(char **) NULL); 35529188a8682a98d4b7882cca434b170517555fc7danthony ( kernel->values[i] < 0) 356c99304fe3c8d9c617da792b40b57c118bb1249afcristy ? ( kernel->negative_range += kernel->values[i] ) 357c99304fe3c8d9c617da792b40b57c118bb1249afcristy : ( kernel->positive_range += kernel->values[i] ); 358c99304fe3c8d9c617da792b40b57c118bb1249afcristy Minimize(kernel->minimum, kernel->values[i]); 359c99304fe3c8d9c617da792b40b57c118bb1249afcristy Maximize(kernel->maximum, kernel->values[i]); 36029188a8682a98d4b7882cca434b170517555fc7danthony } 36129188a8682a98d4b7882cca434b170517555fc7danthony } 36229188a8682a98d4b7882cca434b170517555fc7danthony 3635ef8e94ff55717be2387d537bd49025780a1a558anthony /* sanity check -- no more values in kernel definition */ 3645ef8e94ff55717be2387d537bd49025780a1a558anthony GetMagickToken(p,&p,token); 3655ef8e94ff55717be2387d537bd49025780a1a558anthony if ( *token != '\0' && *token != ';' && *token != '\'' ) 3665ef8e94ff55717be2387d537bd49025780a1a558anthony return(DestroyKernelInfo(kernel)); 3675ef8e94ff55717be2387d537bd49025780a1a558anthony 368c84dce50867229e4872193e8eed5dbab58eb9f02anthony#if 0 369c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* this was the old method of handling a incomplete kernel */ 370bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( i < (ssize_t) (kernel->width*kernel->height) ) { 371c99304fe3c8d9c617da792b40b57c118bb1249afcristy Minimize(kernel->minimum, kernel->values[i]); 372c99304fe3c8d9c617da792b40b57c118bb1249afcristy Maximize(kernel->maximum, kernel->values[i]); 373bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( ; i < (ssize_t) (kernel->width*kernel->height); i++) 37429188a8682a98d4b7882cca434b170517555fc7danthony kernel->values[i]=0.0; 375602ab9b30b644a78a4057da93d838a77391ec0acanthony } 376c84dce50867229e4872193e8eed5dbab58eb9f02anthony#else 377c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* Number of values for kernel was not enough - Report Error */ 378bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( i < (ssize_t) (kernel->width*kernel->height) ) 379c84dce50867229e4872193e8eed5dbab58eb9f02anthony return(DestroyKernelInfo(kernel)); 380c84dce50867229e4872193e8eed5dbab58eb9f02anthony#endif 381c84dce50867229e4872193e8eed5dbab58eb9f02anthony 382c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* check that we recieved at least one real (non-nan) value! */ 383c84dce50867229e4872193e8eed5dbab58eb9f02anthony if ( kernel->minimum == MagickHuge ) 384c84dce50867229e4872193e8eed5dbab58eb9f02anthony return(DestroyKernelInfo(kernel)); 385602ab9b30b644a78a4057da93d838a77391ec0acanthony 38643c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( (flags & AreaValue) != 0 ) /* '@' symbol in kernel size */ 387bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 45.0); /* cyclic rotate 3x3 kernels */ 388bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */ 389bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 90.0); /* 90 degree rotate of kernel */ 390bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & LessValue) != 0 ) /* '<' symbol in kernel args */ 391bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(kernel); /* 90 degree mirror rotate */ 39243c4925e5305a26e48d68f7893e94f55d0831c39anthony 393602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 394602ab9b30b644a78a4057da93d838a77391ec0acanthony} 395c84dce50867229e4872193e8eed5dbab58eb9f02anthony 39643c4925e5305a26e48d68f7893e94f55d0831c39anthonystatic KernelInfo *ParseKernelName(const char *kernel_string) 397c84dce50867229e4872193e8eed5dbab58eb9f02anthony{ 398c84dce50867229e4872193e8eed5dbab58eb9f02anthony char 399c84dce50867229e4872193e8eed5dbab58eb9f02anthony token[MaxTextExtent]; 400c84dce50867229e4872193e8eed5dbab58eb9f02anthony 401c84dce50867229e4872193e8eed5dbab58eb9f02anthony const char 4027a01dcf50ce12cb2a789bedff51e9345f022432eanthony *p, 4037a01dcf50ce12cb2a789bedff51e9345f022432eanthony *end; 404c84dce50867229e4872193e8eed5dbab58eb9f02anthony 4059d314ff2c17a77996c05413c2013880387e50f0ecristy GeometryInfo 4069d314ff2c17a77996c05413c2013880387e50f0ecristy args; 4079d314ff2c17a77996c05413c2013880387e50f0ecristy 4089d314ff2c17a77996c05413c2013880387e50f0ecristy KernelInfo 4099d314ff2c17a77996c05413c2013880387e50f0ecristy *kernel; 4109d314ff2c17a77996c05413c2013880387e50f0ecristy 411c84dce50867229e4872193e8eed5dbab58eb9f02anthony MagickStatusType 412c84dce50867229e4872193e8eed5dbab58eb9f02anthony flags; 413c84dce50867229e4872193e8eed5dbab58eb9f02anthony 4149d314ff2c17a77996c05413c2013880387e50f0ecristy ssize_t 4159d314ff2c17a77996c05413c2013880387e50f0ecristy type; 416c84dce50867229e4872193e8eed5dbab58eb9f02anthony 417c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* Parse special 'named' kernel */ 4185ef8e94ff55717be2387d537bd49025780a1a558anthony GetMagickToken(kernel_string,&p,token); 419042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy type=ParseCommandOption(MagickKernelOptions,MagickFalse,token); 420c84dce50867229e4872193e8eed5dbab58eb9f02anthony if ( type < 0 || type == UserDefinedKernel ) 4215ef8e94ff55717be2387d537bd49025780a1a558anthony return((KernelInfo *)NULL); /* not a valid named kernel */ 422c84dce50867229e4872193e8eed5dbab58eb9f02anthony 423c84dce50867229e4872193e8eed5dbab58eb9f02anthony while (((isspace((int) ((unsigned char) *p)) != 0) || 4245ef8e94ff55717be2387d537bd49025780a1a558anthony (*p == ',') || (*p == ':' )) && (*p != '\0') && (*p != ';')) 425c84dce50867229e4872193e8eed5dbab58eb9f02anthony p++; 4267a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4277a01dcf50ce12cb2a789bedff51e9345f022432eanthony end = strchr(p, ';'); /* end of this kernel defintion */ 4287a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( end == (char *) NULL ) 4297a01dcf50ce12cb2a789bedff51e9345f022432eanthony end = strchr(p, '\0'); 4307a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4317a01dcf50ce12cb2a789bedff51e9345f022432eanthony /* ParseGeometry() needs the geometry separated! -- Arrgghh */ 4327a01dcf50ce12cb2a789bedff51e9345f022432eanthony memcpy(token, p, (size_t) (end-p)); 4337a01dcf50ce12cb2a789bedff51e9345f022432eanthony token[end-p] = '\0'; 434c84dce50867229e4872193e8eed5dbab58eb9f02anthony SetGeometryInfo(&args); 4357a01dcf50ce12cb2a789bedff51e9345f022432eanthony flags = ParseGeometry(token, &args); 436c84dce50867229e4872193e8eed5dbab58eb9f02anthony 4373c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony#if 0 4383c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony /* For Debugging Geometry Input */ 4395acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", 4401e604812fad85bb96f757a2393015ae3d061c39acristy flags, args.rho, args.sigma, args.xi, args.psi ); 4413c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony#endif 4423c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony 443c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* special handling of missing values in input string */ 444c84dce50867229e4872193e8eed5dbab58eb9f02anthony switch( type ) { 445a9892d898acb81e1ec73106d892855fdc5a69427anthony /* Shape Kernel Defaults */ 446529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 447529482f4b494010a13338a74446c510712f670b3anthony if ( (flags & WidthValue) == 0 ) 448a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = 1.0; /* Default scale = 1.0, zero is valid */ 4495ef8e94ff55717be2387d537bd49025780a1a558anthony break; 4505ef8e94ff55717be2387d537bd49025780a1a558anthony case SquareKernel: 4515ef8e94ff55717be2387d537bd49025780a1a558anthony case DiamondKernel: 4521ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 4535ef8e94ff55717be2387d537bd49025780a1a558anthony case DiskKernel: 4545ef8e94ff55717be2387d537bd49025780a1a558anthony case PlusKernel: 4553dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case CrossKernel: 4565ef8e94ff55717be2387d537bd49025780a1a558anthony if ( (flags & HeightValue) == 0 ) 457a9892d898acb81e1ec73106d892855fdc5a69427anthony args.sigma = 1.0; /* Default scale = 1.0, zero is valid */ 4585ef8e94ff55717be2387d537bd49025780a1a558anthony break; 459c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RingKernel: 460c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( (flags & XValue) == 0 ) 461a9892d898acb81e1ec73106d892855fdc5a69427anthony args.xi = 1.0; /* Default scale = 1.0, zero is valid */ 462c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 463a9892d898acb81e1ec73106d892855fdc5a69427anthony case RectangleKernel: /* Rectangle - set size defaults */ 464a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & WidthValue) == 0 ) /* if no width then */ 465a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = args.sigma; /* then width = height */ 466a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( args.rho < 1.0 ) /* if width too small */ 467a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = 3; /* then width = 3 */ 468a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( args.sigma < 1.0 ) /* if height too small */ 469a9892d898acb81e1ec73106d892855fdc5a69427anthony args.sigma = args.rho; /* then height = width */ 470a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & XValue) == 0 ) /* center offset if not defined */ 471a9892d898acb81e1ec73106d892855fdc5a69427anthony args.xi = (double)(((ssize_t)args.rho-1)/2); 472a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & YValue) == 0 ) 473a9892d898acb81e1ec73106d892855fdc5a69427anthony args.psi = (double)(((ssize_t)args.sigma-1)/2); 474a9892d898acb81e1ec73106d892855fdc5a69427anthony break; 475a9892d898acb81e1ec73106d892855fdc5a69427anthony /* Distance Kernel Defaults */ 4765ef8e94ff55717be2387d537bd49025780a1a558anthony case ChebyshevKernel: 477bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 4781ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonalKernel: 4795ef8e94ff55717be2387d537bd49025780a1a558anthony case EuclideanKernel: 48043c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( (flags & HeightValue) == 0 ) /* no distance scale */ 48143c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma = 100.0; /* default distance scaling */ 48243c4925e5305a26e48d68f7893e94f55d0831c39anthony else if ( (flags & AspectValue ) != 0 ) /* '!' flag */ 48343c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma = QuantumRange/(args.sigma+1); /* maximum pixel distance */ 48443c4925e5305a26e48d68f7893e94f55d0831c39anthony else if ( (flags & PercentValue ) != 0 ) /* '%' flag */ 48543c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma *= QuantumRange/100.0; /* percentage of color range */ 4865ef8e94ff55717be2387d537bd49025780a1a558anthony break; 4875ef8e94ff55717be2387d537bd49025780a1a558anthony default: 4885ef8e94ff55717be2387d537bd49025780a1a558anthony break; 489c84dce50867229e4872193e8eed5dbab58eb9f02anthony } 490c84dce50867229e4872193e8eed5dbab58eb9f02anthony 491f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony kernel = AcquireKernelBuiltIn((KernelInfoType)type, &args); 492529482f4b494010a13338a74446c510712f670b3anthony if ( kernel == (KernelInfo *) NULL ) 493529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 494f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony 495f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony /* global expand to rotated kernel list - only for single kernels */ 496f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony if ( kernel->next == (KernelInfo *) NULL ) { 497f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony if ( (flags & AreaValue) != 0 ) /* '@' symbol in kernel args */ 498bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 45.0); 499bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */ 500bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 90.0); 501bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & LessValue) != 0 ) /* '<' symbol in kernel args */ 502bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(kernel); 503f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony } 504f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony 505f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony return(kernel); 506c84dce50867229e4872193e8eed5dbab58eb9f02anthony} 507c84dce50867229e4872193e8eed5dbab58eb9f02anthony 5085ef8e94ff55717be2387d537bd49025780a1a558anthonyMagickExport KernelInfo *AcquireKernelInfo(const char *kernel_string) 5095ef8e94ff55717be2387d537bd49025780a1a558anthony{ 5107a01dcf50ce12cb2a789bedff51e9345f022432eanthony 5117a01dcf50ce12cb2a789bedff51e9345f022432eanthony KernelInfo 512dbc8989a61339951c6434d9a43e7b6fefb5da374anthony *kernel, 51343c4925e5305a26e48d68f7893e94f55d0831c39anthony *new_kernel; 5147a01dcf50ce12cb2a789bedff51e9345f022432eanthony 5155ef8e94ff55717be2387d537bd49025780a1a558anthony char 5165ef8e94ff55717be2387d537bd49025780a1a558anthony token[MaxTextExtent]; 5175ef8e94ff55717be2387d537bd49025780a1a558anthony 5187a01dcf50ce12cb2a789bedff51e9345f022432eanthony const char 519dbc8989a61339951c6434d9a43e7b6fefb5da374anthony *p; 5207a01dcf50ce12cb2a789bedff51e9345f022432eanthony 521bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 522e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony kernel_number; 523e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony 5245e6be1e6a77c230e4a204fa9163d873104730c35cristy if (kernel_string == (const char *) NULL) 5255e6be1e6a77c230e4a204fa9163d873104730c35cristy return(ParseKernelArray(kernel_string)); 526dbc8989a61339951c6434d9a43e7b6fefb5da374anthony p = kernel_string; 52743c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel = NULL; 528e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony kernel_number = 0; 5297a01dcf50ce12cb2a789bedff51e9345f022432eanthony 530dbc8989a61339951c6434d9a43e7b6fefb5da374anthony while ( GetMagickToken(p,NULL,token), *token != '\0' ) { 5317a01dcf50ce12cb2a789bedff51e9345f022432eanthony 5321e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp /* ignore extra or multiple ';' kernel separators */ 533dbc8989a61339951c6434d9a43e7b6fefb5da374anthony if ( *token != ';' ) { 5347a01dcf50ce12cb2a789bedff51e9345f022432eanthony 535dbc8989a61339951c6434d9a43e7b6fefb5da374anthony /* tokens starting with alpha is a Named kernel */ 53643c4925e5305a26e48d68f7893e94f55d0831c39anthony if (isalpha((int) *token) != 0) 53743c4925e5305a26e48d68f7893e94f55d0831c39anthony new_kernel = ParseKernelName(p); 538dbc8989a61339951c6434d9a43e7b6fefb5da374anthony else /* otherwise a user defined kernel array */ 53943c4925e5305a26e48d68f7893e94f55d0831c39anthony new_kernel = ParseKernelArray(p); 540dbc8989a61339951c6434d9a43e7b6fefb5da374anthony 541e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony /* Error handling -- this is not proper error handling! */ 542e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony if ( new_kernel == (KernelInfo *) NULL ) { 5435acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Failed to parse kernel number #%.20g\n", 5441e604812fad85bb96f757a2393015ae3d061c39acristy (double) kernel_number); 545e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony if ( kernel != (KernelInfo *) NULL ) 546e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony kernel=DestroyKernelInfo(kernel); 547e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony return((KernelInfo *) NULL); 548dbc8989a61339951c6434d9a43e7b6fefb5da374anthony } 549e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony 550e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony /* initialise or append the kernel list */ 5513dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony if ( kernel == (KernelInfo *) NULL ) 5523dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony kernel = new_kernel; 5533dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony else 55443c4925e5305a26e48d68f7893e94f55d0831c39anthony LastKernelInfo(kernel)->next = new_kernel; 555dbc8989a61339951c6434d9a43e7b6fefb5da374anthony } 556dbc8989a61339951c6434d9a43e7b6fefb5da374anthony 557dbc8989a61339951c6434d9a43e7b6fefb5da374anthony /* look for the next kernel in list */ 558dbc8989a61339951c6434d9a43e7b6fefb5da374anthony p = strchr(p, ';'); 559dbc8989a61339951c6434d9a43e7b6fefb5da374anthony if ( p == (char *) NULL ) 560dbc8989a61339951c6434d9a43e7b6fefb5da374anthony break; 561dbc8989a61339951c6434d9a43e7b6fefb5da374anthony p++; 5625ef8e94ff55717be2387d537bd49025780a1a558anthony 563dbc8989a61339951c6434d9a43e7b6fefb5da374anthony } 5647a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(kernel); 5655ef8e94ff55717be2387d537bd49025780a1a558anthony} 5665ef8e94ff55717be2387d537bd49025780a1a558anthony 567602ab9b30b644a78a4057da93d838a77391ec0acanthony 568602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 569602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 570602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 571602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 572602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 573602ab9b30b644a78a4057da93d838a77391ec0acanthony% A c q u i r e K e r n e l B u i l t I n % 574602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 575602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 576602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 577602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 578602ab9b30b644a78a4057da93d838a77391ec0acanthony% 579602ab9b30b644a78a4057da93d838a77391ec0acanthony% AcquireKernelBuiltIn() returned one of the 'named' built-in types of 580602ab9b30b644a78a4057da93d838a77391ec0acanthony% kernels used for special purposes such as gaussian blurring, skeleton 581602ab9b30b644a78a4057da93d838a77391ec0acanthony% pruning, and edge distance determination. 582602ab9b30b644a78a4057da93d838a77391ec0acanthony% 583602ab9b30b644a78a4057da93d838a77391ec0acanthony% They take a KernelType, and a set of geometry style arguments, which were 584602ab9b30b644a78a4057da93d838a77391ec0acanthony% typically decoded from a user supplied string, or from a more complex 585602ab9b30b644a78a4057da93d838a77391ec0acanthony% Morphology Method that was requested. 586602ab9b30b644a78a4057da93d838a77391ec0acanthony% 587602ab9b30b644a78a4057da93d838a77391ec0acanthony% The format of the AcquireKernalBuiltIn method is: 588602ab9b30b644a78a4057da93d838a77391ec0acanthony% 5892be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type, 590602ab9b30b644a78a4057da93d838a77391ec0acanthony% const GeometryInfo args) 591602ab9b30b644a78a4057da93d838a77391ec0acanthony% 592602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 593602ab9b30b644a78a4057da93d838a77391ec0acanthony% 594602ab9b30b644a78a4057da93d838a77391ec0acanthony% o type: the pre-defined type of kernel wanted 595602ab9b30b644a78a4057da93d838a77391ec0acanthony% 596602ab9b30b644a78a4057da93d838a77391ec0acanthony% o args: arguments defining or modifying the kernel 597602ab9b30b644a78a4057da93d838a77391ec0acanthony% 598602ab9b30b644a78a4057da93d838a77391ec0acanthony% Convolution Kernels 599602ab9b30b644a78a4057da93d838a77391ec0acanthony% 60046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Unity 601529482f4b494010a13338a74446c510712f670b3anthony% The a No-Op or Scaling single element kernel. 60246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 6033c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Gaussian:{radius},{sigma} 6042489f53a1153c2b619b1c9a6744602e8840bd9a9glennrp% Generate a two-dimensional gaussian kernel, as used by -gaussian. 605c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The sigma for the curve is required. The resulting kernel is 606c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% normalized, 607c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 608c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% If 'sigma' is zero, you get a single pixel on a field of zeros. 609602ab9b30b644a78a4057da93d838a77391ec0acanthony% 610602ab9b30b644a78a4057da93d838a77391ec0acanthony% NOTE: that the 'radius' is optional, but if provided can limit (clip) 611602ab9b30b644a78a4057da93d838a77391ec0acanthony% the final size of the resulting kernel to a square 2*radius+1 in size. 612602ab9b30b644a78a4057da93d838a77391ec0acanthony% The radius should be at least 2 times that of the sigma value, or 613602ab9b30b644a78a4057da93d838a77391ec0acanthony% sever clipping and aliasing may result. If not given or set to 0 the 614602ab9b30b644a78a4057da93d838a77391ec0acanthony% radius will be determined so as to produce the best minimal error 615602ab9b30b644a78a4057da93d838a77391ec0acanthony% result, which is usally much larger than is normally needed. 616602ab9b30b644a78a4057da93d838a77391ec0acanthony% 617501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% LoG:{radius},{sigma} 618501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% "Laplacian of a Gaussian" or "Mexician Hat" Kernel. 619501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% The supposed ideal edge detection, zero-summing kernel. 620501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 621501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% An alturnative to this kernel is to use a "DoG" with a sigma ratio of 622501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% approx 1.6 (according to wikipedia). 623501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 624501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% DoG:{radius},{sigma1},{sigma2} 625c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% "Difference of Gaussians" Kernel. 626c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% As "Gaussian" but with a gaussian produced by 'sigma2' subtracted 627c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% from the gaussian produced by 'sigma1'. Typically sigma2 > sigma1. 628c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The result is a zero-summing kernel. 629c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 630c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Blur:{radius},{sigma}[,{angle}] 6314c08aed51c5899665ade97263692328eea4af106cristy% Generates a 1 dimensional or linear gaussian blur, at the angle given 632c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% (current restricted to orthogonal angles). If a 'radius' is given the 633c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% kernel is clipped to a width of 2*radius+1. Kernel can be rotated 634c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% by a 90 degree angle. 635c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 636c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% If 'sigma' is zero, you get a single pixel on a field of zeros. 637c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 638c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Note that two convolutions with two "Blur" kernels perpendicular to 639f0a92fd8deb68d411304359906b12679b675691fglennrp% each other, is equivalent to a far larger "Gaussian" kernel with the 640c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% same sigma value, However it is much faster to apply. This is how the 641c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% "-blur" operator actually works. 642c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 6433c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Comet:{width},{sigma},{angle} 6443c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Blur in one direction only, much like how a bright object leaves 645602ab9b30b644a78a4057da93d838a77391ec0acanthony% a comet like trail. The Kernel is actually half a gaussian curve, 6463c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Adding two such blurs in opposite directions produces a Blur Kernel. 6473c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Angle can be rotated in multiples of 90 degrees. 648602ab9b30b644a78a4057da93d838a77391ec0acanthony% 6493c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Note that the first argument is the width of the kernel and not the 650602ab9b30b644a78a4057da93d838a77391ec0acanthony% radius of the kernel. 651602ab9b30b644a78a4057da93d838a77391ec0acanthony% 65240ca0b982379d4ab2716435a46603d56b5b218b1anthony% Binomial:[{radius}] 65340ca0b982379d4ab2716435a46603d56b5b218b1anthony% Generate a discrete kernel using a 2 dimentional Pascel's Triangle 654eef684ff80c7d5aca1493f4755426c88b3d3accdanthony% of values. Used for special forma of image filters. 65540ca0b982379d4ab2716435a46603d56b5b218b1anthony% 656602ab9b30b644a78a4057da93d838a77391ec0acanthony% # Still to be implemented... 657602ab9b30b644a78a4057da93d838a77391ec0acanthony% # 6584fd27e21043be809d66c8202e779255e5b660d2danthony% # Filter2D 6594fd27e21043be809d66c8202e779255e5b660d2danthony% # Filter1D 6604fd27e21043be809d66c8202e779255e5b660d2danthony% # Set kernel values using a resize filter, and given scale (sigma) 661dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp% # Cylindrical or Linear. Is this possible with an image? 6624fd27e21043be809d66c8202e779255e5b660d2danthony% # 663602ab9b30b644a78a4057da93d838a77391ec0acanthony% 6643c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Named Constant Convolution Kernels 6653c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 666c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% All these are unscaled, zero-summing kernels by default. As such for 667c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% non-HDRI version of ImageMagick some form of normalization, user scaling, 668c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% and biasing the results is recommended, to prevent the resulting image 669c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% being 'clipped'. 670c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 671c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The 3x3 kernels (most of these) can be circularly rotated in multiples of 672c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 45 degrees to generate the 8 angled varients of each of the kernels. 6733c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 6743c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Laplacian:{type} 67543c4925e5305a26e48d68f7893e94f55d0831c39anthony% Discrete Lapacian Kernels, (without normalization) 676c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Type 0 : 3x3 with center:8 surounded by -1 (8 neighbourhood) 677c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Type 1 : 3x3 with center:4 edge:-1 corner:0 (4 neighbourhood) 6789eb4f74649b23c053b308ce1152dce51239450baanthony% Type 2 : 3x3 with center:4 edge:1 corner:-2 6799eb4f74649b23c053b308ce1152dce51239450baanthony% Type 3 : 3x3 with center:4 edge:-2 corner:1 6809eb4f74649b23c053b308ce1152dce51239450baanthony% Type 5 : 5x5 laplacian 6819eb4f74649b23c053b308ce1152dce51239450baanthony% Type 7 : 7x7 laplacian 682501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Type 15 : 5x5 LoG (sigma approx 1.4) 683501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Type 19 : 9x9 LoG (sigma approx 1.4) 684c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 685c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Sobel:{angle} 68646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Sobel 'Edge' convolution kernel (3x3) 687c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 688c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 0,-2 | 689c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 690c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 691c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Roberts:{angle} 69246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Roberts convolution kernel (3x3) 693c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | 694c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 0 | 695c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | 696c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 697c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Prewitt:{angle} 698c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Prewitt Edge convolution kernel (3x3) 699c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 700c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 701c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 702c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 7039eb4f74649b23c053b308ce1152dce51239450baanthony% Compass:{angle} 7049eb4f74649b23c053b308ce1152dce51239450baanthony% Prewitt's "Compass" convolution kernel (3x3) 705c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 1 | 706c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1,-2, 1 | 707c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 1 | 708c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 7099eb4f74649b23c053b308ce1152dce51239450baanthony% Kirsch:{angle} 7109eb4f74649b23c053b308ce1152dce51239450baanthony% Kirsch's "Compass" convolution kernel (3x3) 711c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3,-3, 5 | 712c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3, 0, 5 | 713c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3,-3, 5 | 7143c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 715c40ac1e79923a1516075ba1197ae4ed90244af9banthony% FreiChen:{angle} 7161d5e67090dc7232b35bfcc71b31266c20838defcanthony% Frei-Chen Edge Detector is based on a kernel that is similar to 7171d5e67090dc7232b35bfcc71b31266c20838defcanthony% the Sobel Kernel, but is designed to be isotropic. That is it takes 7181d5e67090dc7232b35bfcc71b31266c20838defcanthony% into account the distance of the diagonal in the kernel. 719c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 720c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 721c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | 722c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 723c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 724c40ac1e79923a1516075ba1197ae4ed90244af9banthony% FreiChen:{type},{angle} 725c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 726c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Frei-Chen Pre-weighted kernels... 727c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 728c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 0: default un-nomalized version shown above. 729c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 730c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 1: Orthogonal Kernel (same as type 11 below) 731c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 732c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 733c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 734c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 735c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 2: Diagonal form of Kernel... 736c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, sqrt(2), 0 | 737c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 738c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, -sqrt(2) -1 | 739c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 7401d5e67090dc7232b35bfcc71b31266c20838defcanthony% However this kernel is als at the heart of the FreiChen Edge Detection 7411d5e67090dc7232b35bfcc71b31266c20838defcanthony% Process which uses a set of 9 specially weighted kernel. These 9 7421d5e67090dc7232b35bfcc71b31266c20838defcanthony% kernels not be normalized, but directly applied to the image. The 7431d5e67090dc7232b35bfcc71b31266c20838defcanthony% results is then added together, to produce the intensity of an edge in 7441d5e67090dc7232b35bfcc71b31266c20838defcanthony% a specific direction. The square root of the pixel value can then be 7451d5e67090dc7232b35bfcc71b31266c20838defcanthony% taken as the cosine of the edge, and at least 2 such runs at 90 degrees 7461d5e67090dc7232b35bfcc71b31266c20838defcanthony% from each other, both the direction and the strength of the edge can be 7471d5e67090dc7232b35bfcc71b31266c20838defcanthony% determined. 7481d5e67090dc7232b35bfcc71b31266c20838defcanthony% 749c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 10: All 9 of the following pre-weighted kernels... 750c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 751c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 11: | 1, 0, -1 | 752c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 753c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 754e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 755c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 12: | 1, sqrt(2), 1 | 756c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | / 2*sqrt(2) 757c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, sqrt(2), 1 | 758e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 759c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 13: | sqrt(2), -1, 0 | 760c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | / 2*sqrt(2) 761c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 1, -sqrt(2) | 762e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 763c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 14: | 0, 1, -sqrt(2) | 764c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | / 2*sqrt(2) 765c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), -1, 0 | 766e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 767c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 15: | 0, -1, 0 | 768c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, 1 | / 2 769c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, -1, 0 | 770e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 771c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 16: | 1, 0, -1 | 772c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | / 2 773c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 774e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 775c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 17: | 1, -2, 1 | 776c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 4, -2 | / 6 777c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, -2, 1 | 778501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 779c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 18: | -2, 1, -2 | 780c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 4, 1 | / 6 781c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 1, -2 | 782e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 783c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 19: | 1, 1, 1 | 784c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 1, 1 | / 3 785c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 1, 1 | 786e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 787e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% The first 4 are for edge detection, the next 4 are for line detection 788e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% and the last is to add a average component to the results. 789e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 790c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% Using a special type of '-1' will return all 9 pre-weighted kernels 791c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% as a multi-kernel list, so that you can use them directly (without 792c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% normalization) with the special "-set option:morphology:compose Plus" 793c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% setting to apply the full FreiChen Edge Detection Technique. 794c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 7951dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% If 'type' is large it will be taken to be an actual rotation angle for 7961dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% the default FreiChen (type 0) kernel. As such FreiChen:45 will look 7971dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% like a Sobel:45 but with 'sqrt(2)' instead of '2' values. 7981dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% 799501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% WARNING: The above was layed out as per 800501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf 801501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% But rotated 90 degrees so direction is from left rather than the top. 802501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% I have yet to find any secondary confirmation of the above. The only 803501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% other source found was actual source code at 804501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf 805501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Neigher paper defineds the kernels in a way that looks locical or 806501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% correct when taken as a whole. 807e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 808602ab9b30b644a78a4057da93d838a77391ec0acanthony% Boolean Kernels 809602ab9b30b644a78a4057da93d838a77391ec0acanthony% 8103c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Diamond:[{radius}[,{scale}]] 8111b2bc0a7da432e6e1cc0480280402df213faa940anthony% Generate a diamond shaped kernel with given radius to the points. 812602ab9b30b644a78a4057da93d838a77391ec0acanthony% Kernel size will again be radius*2+1 square and defaults to radius 1, 813602ab9b30b644a78a4057da93d838a77391ec0acanthony% generating a 3x3 kernel that is slightly larger than a square. 814602ab9b30b644a78a4057da93d838a77391ec0acanthony% 8153c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Square:[{radius}[,{scale}]] 816602ab9b30b644a78a4057da93d838a77391ec0acanthony% Generate a square shaped kernel of size radius*2+1, and defaulting 817602ab9b30b644a78a4057da93d838a77391ec0acanthony% to a 3x3 (radius 1). 818602ab9b30b644a78a4057da93d838a77391ec0acanthony% 8191ef941fea2534a0d20ba7d71307d35040247decbanthony% Octagon:[{radius}[,{scale}]] 8201ef941fea2534a0d20ba7d71307d35040247decbanthony% Generate octagonal shaped kernel of given radius and constant scale. 8210bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% Default radius is 3 producing a 7x7 kernel. A radius of 1 will result 8221ef941fea2534a0d20ba7d71307d35040247decbanthony% in "Diamond" kernel. 8231ef941fea2534a0d20ba7d71307d35040247decbanthony% 8243c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Disk:[{radius}[,{scale}]] 8251ef941fea2534a0d20ba7d71307d35040247decbanthony% Generate a binary disk, thresholded at the radius given, the radius 8261ef941fea2534a0d20ba7d71307d35040247decbanthony% may be a float-point value. Final Kernel size is floor(radius)*2+1 8270bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% square. A radius of 5.3 is the default. 8281ef941fea2534a0d20ba7d71307d35040247decbanthony% 8291ef941fea2534a0d20ba7d71307d35040247decbanthony% NOTE: That a low radii Disk kernels produce the same results as 8301ef941fea2534a0d20ba7d71307d35040247decbanthony% many of the previously defined kernels, but differ greatly at larger 8311ef941fea2534a0d20ba7d71307d35040247decbanthony% radii. Here is a table of equivalences... 8321ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:1" => "Diamond", "Octagon:1", or "Cross:1" 8331ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:1.5" => "Square" 8341ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2" => "Diamond:2" 8351ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2.5" => "Octagon" 8361ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2.9" => "Square:2" 8370bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% "Disk:3.5" => "Octagon:3" 8381ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:4.5" => "Octagon:4" 8391ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:5.4" => "Octagon:5" 8401ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:6.4" => "Octagon:6" 8411ef941fea2534a0d20ba7d71307d35040247decbanthony% All other Disk shapes are unique to this kernel, but because a "Disk" 8421ef941fea2534a0d20ba7d71307d35040247decbanthony% is more circular when using a larger radius, using a larger radius is 8431ef941fea2534a0d20ba7d71307d35040247decbanthony% preferred over iterating the morphological operation. 844602ab9b30b644a78a4057da93d838a77391ec0acanthony% 845a9892d898acb81e1ec73106d892855fdc5a69427anthony% Rectangle:{geometry} 846a9892d898acb81e1ec73106d892855fdc5a69427anthony% Simply generate a rectangle of 1's with the size given. You can also 847a9892d898acb81e1ec73106d892855fdc5a69427anthony% specify the location of the 'control point', otherwise the closest 848a9892d898acb81e1ec73106d892855fdc5a69427anthony% pixel to the center of the rectangle is selected. 849a9892d898acb81e1ec73106d892855fdc5a69427anthony% 850a9892d898acb81e1ec73106d892855fdc5a69427anthony% Properly centered and odd sized rectangles work the best. 851a9892d898acb81e1ec73106d892855fdc5a69427anthony% 852c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Symbol Dilation Kernels 853c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 854c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% These kernel is not a good general morphological kernel, but is used 855c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% more for highlighting and marking any single pixels in an image using, 856c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a "Dilate" method as appropriate. 857c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 858c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% For the same reasons iterating these kernels does not produce the 859c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% same result as using a larger radius for the symbol. 860c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 8613c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Plus:[{radius}[,{scale}]] 8623dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Cross:[{radius}[,{scale}]] 863c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Generate a kernel in the shape of a 'plus' or a 'cross' with 864c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a each arm the length of the given radius (default 2). 8653dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% 866f0a92fd8deb68d411304359906b12679b675691fglennrp% NOTE: "plus:1" is equivalent to a "Diamond" kernel. 867602ab9b30b644a78a4057da93d838a77391ec0acanthony% 868c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Ring:{radius1},{radius2}[,{scale}] 869c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% A ring of the values given that falls between the two radii. 870c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Defaults to a ring of approximataly 3 radius in a 7x7 kernel. 871c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% This is the 'edge' pixels of the default "Disk" kernel, 872c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% More specifically, "Ring" -> "Ring:2.5,3.5,1.0" 8733dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% 8743dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Hit and Miss Kernels 875602ab9b30b644a78a4057da93d838a77391ec0acanthony% 8763dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Peak:radius1,radius2 877c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Find any peak larger than the pixels the fall between the two radii. 878c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The default ring of pixels is as per "Ring". 87943c4925e5305a26e48d68f7893e94f55d0831c39anthony% Edges 880694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find flat orthogonal edges of a binary shape 8813dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Corners 882694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find 90 degree corners of a binary shape 883529482f4b494010a13338a74446c510712f670b3anthony% Diagonals:type 884529482f4b494010a13338a74446c510712f670b3anthony% A special kernel to thin the 'outside' of diagonals 885694934fa79dd310f727588b1d0a7481fa6170f1danthony% LineEnds:type 8863dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Find end points of lines (for pruning a skeletion) 887694934fa79dd310f727588b1d0a7481fa6170f1danthony% Two types of lines ends (default to both) can be searched for 888694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 0: All line ends 889694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: single kernel for 4-conneected line ends 890694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: single kernel for simple line ends 8913dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% LineJunctions 89243c4925e5305a26e48d68f7893e94f55d0831c39anthony% Find three line junctions (within a skeletion) 893694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 0: all line junctions 894694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Y Junction kernel 895694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: Diagonal T Junction kernel 896694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 3: Orthogonal T Junction kernel 897694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 4: Diagonal X Junction kernel 898694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 5: Orthogonal + Junction kernel 899694934fa79dd310f727588b1d0a7481fa6170f1danthony% Ridges:type 900694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find single pixel ridges or thin lines 901694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Fine single pixel thick lines and ridges 902694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: Find two pixel thick lines and ridges 9033dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% ConvexHull 904a9892d898acb81e1ec73106d892855fdc5a69427anthony% Octagonal Thickening Kernel, to generate convex hulls of 45 degrees 905c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Skeleton:type 906c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Traditional skeleton generating kernels. 907694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Tradional Skeleton kernel (4 connected skeleton) 908694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: HIPR2 Skeleton kernel (8 connected skeleton) 909e816a586a13717bab2d6839ced6e5c3828a37f19anthony% Type 3: Thinning skeleton based on a ressearch paper by 9102b2290b46c246ce1f14cb78f1695394e4c4a3ddfanthony% Dan S. Bloomberg (Default Type) 911e816a586a13717bab2d6839ced6e5c3828a37f19anthony% ThinSE:type 912e816a586a13717bab2d6839ced6e5c3828a37f19anthony% A huge variety of Thinning Kernels designed to preserve conectivity. 913e816a586a13717bab2d6839ced6e5c3828a37f19anthony% many other kernel sets use these kernels as source definitions. 914e816a586a13717bab2d6839ced6e5c3828a37f19anthony% Type numbers are 41-49, 81-89, 481, and 482 which are based on 915e816a586a13717bab2d6839ced6e5c3828a37f19anthony% the super and sub notations used in the source research paper. 916602ab9b30b644a78a4057da93d838a77391ec0acanthony% 917602ab9b30b644a78a4057da93d838a77391ec0acanthony% Distance Measuring Kernels 918602ab9b30b644a78a4057da93d838a77391ec0acanthony% 919c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Different types of distance measuring methods, which are used with the 920c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a 'Distance' morphology method for generating a gradient based on 921c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% distance from an edge of a binary shape, though there is a technique 922c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% for handling a anti-aliased shape. 923602ab9b30b644a78a4057da93d838a77391ec0acanthony% 924c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% See the 'Distance' Morphological Method, for information of how it is 925c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% applied. 926602ab9b30b644a78a4057da93d838a77391ec0acanthony% 927c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Chebyshev:[{radius}][x{scale}[%!]] 9281ef941fea2534a0d20ba7d71307d35040247decbanthony% Chebyshev Distance (also known as Tchebychev or Chessboard distance) 9291ef941fea2534a0d20ba7d71307d35040247decbanthony% is a value of one to any neighbour, orthogonal or diagonal. One why 9301ef941fea2534a0d20ba7d71307d35040247decbanthony% of thinking of it is the number of squares a 'King' or 'Queen' in 9311ef941fea2534a0d20ba7d71307d35040247decbanthony% chess needs to traverse reach any other position on a chess board. 9321ef941fea2534a0d20ba7d71307d35040247decbanthony% It results in a 'square' like distance function, but one where 9331ef941fea2534a0d20ba7d71307d35040247decbanthony% diagonals are given a value that is closer than expected. 934c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 935bee715c4c0fd9efe6e21d8627ae8664434df7750anthony% Manhattan:[{radius}][x{scale}[%!]] 9361ef941fea2534a0d20ba7d71307d35040247decbanthony% Manhattan Distance (also known as Rectilinear, City Block, or the Taxi 9371ef941fea2534a0d20ba7d71307d35040247decbanthony% Cab distance metric), it is the distance needed when you can only 9381ef941fea2534a0d20ba7d71307d35040247decbanthony% travel in horizontal or vertical directions only. It is the 9391ef941fea2534a0d20ba7d71307d35040247decbanthony% distance a 'Rook' in chess would have to travel, and results in a 9401ef941fea2534a0d20ba7d71307d35040247decbanthony% diamond like distances, where diagonals are further than expected. 9411ef941fea2534a0d20ba7d71307d35040247decbanthony% 9421ef941fea2534a0d20ba7d71307d35040247decbanthony% Octagonal:[{radius}][x{scale}[%!]] 9431ef941fea2534a0d20ba7d71307d35040247decbanthony% An interleving of Manhatten and Chebyshev metrics producing an 9441ef941fea2534a0d20ba7d71307d35040247decbanthony% increasing octagonally shaped distance. Distances matches those of 9451ef941fea2534a0d20ba7d71307d35040247decbanthony% the "Octagon" shaped kernel of the same radius. The minimum radius 9461ef941fea2534a0d20ba7d71307d35040247decbanthony% and default is 2, producing a 5x5 kernel. 947c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 948c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Euclidean:[{radius}][x{scale}[%!]] 9491ef941fea2534a0d20ba7d71307d35040247decbanthony% Euclidean distance is the 'direct' or 'as the crow flys' distance. 950c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% However by default the kernel size only has a radius of 1, which 951c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% limits the distance to 'Knight' like moves, with only orthogonal and 952c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% diagonal measurements being correct. As such for the default kernel 9531ef941fea2534a0d20ba7d71307d35040247decbanthony% you will get octagonal like distance function. 9541ef941fea2534a0d20ba7d71307d35040247decbanthony% 9551ef941fea2534a0d20ba7d71307d35040247decbanthony% However using a larger radius such as "Euclidean:4" you will get a 9561ef941fea2534a0d20ba7d71307d35040247decbanthony% much smoother distance gradient from the edge of the shape. Especially 9571ef941fea2534a0d20ba7d71307d35040247decbanthony% if the image is pre-processed to include any anti-aliasing pixels. 9581ef941fea2534a0d20ba7d71307d35040247decbanthony% Of course a larger kernel is slower to use, and not always needed. 9591ef941fea2534a0d20ba7d71307d35040247decbanthony% 9601ef941fea2534a0d20ba7d71307d35040247decbanthony% The first three Distance Measuring Kernels will only generate distances 9611ef941fea2534a0d20ba7d71307d35040247decbanthony% of exact multiples of {scale} in binary images. As such you can use a 9621ef941fea2534a0d20ba7d71307d35040247decbanthony% scale of 1 without loosing any information. However you also need some 9631ef941fea2534a0d20ba7d71307d35040247decbanthony% scaling when handling non-binary anti-aliased shapes. 9641ef941fea2534a0d20ba7d71307d35040247decbanthony% 9651ef941fea2534a0d20ba7d71307d35040247decbanthony% The "Euclidean" Distance Kernel however does generate a non-integer 9661ef941fea2534a0d20ba7d71307d35040247decbanthony% fractional results, and as such scaling is vital even for binary shapes. 967c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 968602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 969602ab9b30b644a78a4057da93d838a77391ec0acanthony 9702be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristyMagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type, 971602ab9b30b644a78a4057da93d838a77391ec0acanthony const GeometryInfo *args) 972602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 9732be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy KernelInfo 974602ab9b30b644a78a4057da93d838a77391ec0acanthony *kernel; 975602ab9b30b644a78a4057da93d838a77391ec0acanthony 976bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 977602ab9b30b644a78a4057da93d838a77391ec0acanthony i; 978602ab9b30b644a78a4057da93d838a77391ec0acanthony 979bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 980602ab9b30b644a78a4057da93d838a77391ec0acanthony u, 981602ab9b30b644a78a4057da93d838a77391ec0acanthony v; 982602ab9b30b644a78a4057da93d838a77391ec0acanthony 983602ab9b30b644a78a4057da93d838a77391ec0acanthony double 984602ab9b30b644a78a4057da93d838a77391ec0acanthony nan = sqrt((double)-1.0); /* Special Value : Not A Number */ 985602ab9b30b644a78a4057da93d838a77391ec0acanthony 986c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Generate a new empty kernel if needed */ 987e96405a0f45f803fb9c26f75e7bdee252437febbcristy kernel=(KernelInfo *) NULL; 988c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony switch(type) { 9891dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case UndefinedKernel: /* These should not call this function */ 9909eb4f74649b23c053b308ce1152dce51239450baanthony case UserDefinedKernel: 991529482f4b494010a13338a74446c510712f670b3anthony assert("Should not call this function" != (char *)NULL); 9929eb4f74649b23c053b308ce1152dce51239450baanthony break; 993529482f4b494010a13338a74446c510712f670b3anthony case LaplacianKernel: /* Named Descrete Convolution Kernels */ 994529482f4b494010a13338a74446c510712f670b3anthony case SobelKernel: /* these are defined using other kernels */ 9959eb4f74649b23c053b308ce1152dce51239450baanthony case RobertsKernel: 9969eb4f74649b23c053b308ce1152dce51239450baanthony case PrewittKernel: 9979eb4f74649b23c053b308ce1152dce51239450baanthony case CompassKernel: 9989eb4f74649b23c053b308ce1152dce51239450baanthony case KirschKernel: 9991dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case FreiChenKernel: 1000694934fa79dd310f727588b1d0a7481fa6170f1danthony case EdgesKernel: /* Hit and Miss kernels */ 1001694934fa79dd310f727588b1d0a7481fa6170f1danthony case CornersKernel: 1002529482f4b494010a13338a74446c510712f670b3anthony case DiagonalsKernel: 10039eb4f74649b23c053b308ce1152dce51239450baanthony case LineEndsKernel: 10049eb4f74649b23c053b308ce1152dce51239450baanthony case LineJunctionsKernel: 10051dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case RidgesKernel: 10069eb4f74649b23c053b308ce1152dce51239450baanthony case ConvexHullKernel: 10079eb4f74649b23c053b308ce1152dce51239450baanthony case SkeletonKernel: 10089a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case ThinSEKernel: 1009c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; /* A pre-generated kernel is not needed */ 1010c40ac1e79923a1516075ba1197ae4ed90244af9banthony#if 0 1011c40ac1e79923a1516075ba1197ae4ed90244af9banthony /* set to 1 to do a compile-time check that we haven't missed anything */ 1012529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 1013c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case GaussianKernel: 1014501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 1015501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 1016c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case BlurKernel: 1017c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CometKernel: 101840ca0b982379d4ab2716435a46603d56b5b218b1anthony case BinomialKernel: 1019c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiamondKernel: 1020c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SquareKernel: 1021c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RectangleKernel: 10221ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 1023c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiskKernel: 1024c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PlusKernel: 1025c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CrossKernel: 1026c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RingKernel: 1027c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PeaksKernel: 1028c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case ChebyshevKernel: 1029bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 10301ef941fea2534a0d20ba7d71307d35040247decbanthony case OctangonalKernel: 1031c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case EuclideanKernel: 10321dd091ae3bc17edc26c16cc47f436a24bd48412aanthony#else 10339eb4f74649b23c053b308ce1152dce51239450baanthony default: 10341dd091ae3bc17edc26c16cc47f436a24bd48412aanthony#endif 10359eb4f74649b23c053b308ce1152dce51239450baanthony /* Generate the base Kernel Structure */ 1036c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel)); 1037c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1038c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1039c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony (void) ResetMagickMemory(kernel,0,sizeof(*kernel)); 104043c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->minimum = kernel->maximum = kernel->angle = 0.0; 1041c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->negative_range = kernel->positive_range = 0.0; 1042c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 1043c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->next = (KernelInfo *) NULL; 1044c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->signature = MagickSignature; 1045c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1046c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1047602ab9b30b644a78a4057da93d838a77391ec0acanthony 1048602ab9b30b644a78a4057da93d838a77391ec0acanthony switch(type) { 1049529482f4b494010a13338a74446c510712f670b3anthony /* 1050529482f4b494010a13338a74446c510712f670b3anthony Convolution Kernels 1051529482f4b494010a13338a74446c510712f670b3anthony */ 1052529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 1053529482f4b494010a13338a74446c510712f670b3anthony { 1054529482f4b494010a13338a74446c510712f670b3anthony kernel->height = kernel->width = (size_t) 1; 1055529482f4b494010a13338a74446c510712f670b3anthony kernel->x = kernel->y = (ssize_t) 0; 1056e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1057e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(1,sizeof(*kernel->values))); 1058d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 1059529482f4b494010a13338a74446c510712f670b3anthony return(DestroyKernelInfo(kernel)); 1060529482f4b494010a13338a74446c510712f670b3anthony kernel->maximum = kernel->values[0] = args->rho; 1061529482f4b494010a13338a74446c510712f670b3anthony break; 1062529482f4b494010a13338a74446c510712f670b3anthony } 1063529482f4b494010a13338a74446c510712f670b3anthony break; 1064602ab9b30b644a78a4057da93d838a77391ec0acanthony case GaussianKernel: 1065501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 1066501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 1067602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 1068c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma = fabs(args->sigma), 1069c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma2 = fabs(args->xi), 10709eb4f74649b23c053b308ce1152dce51239450baanthony A, B, R; 1071c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1072c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( args->rho >= 1.0 ) 1073bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho*2+1; 1074501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony else if ( (type != DoGKernel) || (sigma >= sigma2) ) 1075c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = GetOptimalKernelWidth2D(args->rho,sigma); 1076c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1077c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2); 1078c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->height = kernel->width; 1079bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 1080e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1081e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1082e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1083d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 108483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1085602ab9b30b644a78a4057da93d838a77391ec0acanthony 108646a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* WARNING: The following generates a 'sampled gaussian' kernel. 10879eb4f74649b23c053b308ce1152dce51239450baanthony * What we really want is a 'discrete gaussian' kernel. 108846a369d839971ab627bdb31a93d8bd63e81b65a3anthony * 1089529482f4b494010a13338a74446c510712f670b3anthony * How to do this is I don't know, but appears to be basied on the 1090529482f4b494010a13338a74446c510712f670b3anthony * Error Function 'erf()' (intergral of a gaussian) 10919eb4f74649b23c053b308ce1152dce51239450baanthony */ 10929eb4f74649b23c053b308ce1152dce51239450baanthony 1093501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == GaussianKernel || type == DoGKernel ) 1094501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony { /* Calculate a Gaussian, OR positive half of a DoG */ 10959eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 10969eb4f74649b23c053b308ce1152dce51239450baanthony { A = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 109755a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(Magick2PI*sigma*sigma)); 1098bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1099bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 11009eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] = exp(-((double)(u*u+v*v))*A)*B; 11019eb4f74649b23c053b308ce1152dce51239450baanthony } 11029eb4f74649b23c053b308ce1152dce51239450baanthony else /* limiting case - a unity (normalized Dirac) kernel */ 11039eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 11049eb4f74649b23c053b308ce1152dce51239450baanthony kernel->width*kernel->height*sizeof(double)); 11059eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 11069eb4f74649b23c053b308ce1152dce51239450baanthony } 1107c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 11089eb4f74649b23c053b308ce1152dce51239450baanthony 1109501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == DoGKernel ) 1110c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { /* Subtract a Negative Gaussian for "Difference of Gaussian" */ 1111c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma2 > MagickEpsilon ) 1112c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { sigma = sigma2; /* simplify loop expressions */ 11139eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); 111455a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(Magick2PI*sigma*sigma)); 1115bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1116bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 11179eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] -= exp(-((double)(u*u+v*v))*A)*B; 1118c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 11199eb4f74649b23c053b308ce1152dce51239450baanthony else /* limiting case - a unity (normalized Dirac) kernel */ 1120c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] -= 1.0; 1121c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 11229eb4f74649b23c053b308ce1152dce51239450baanthony 1123501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == LoGKernel ) 11249eb4f74649b23c053b308ce1152dce51239450baanthony { /* Calculate a Laplacian of a Gaussian - Or Mexician Hat */ 11259eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 11269eb4f74649b23c053b308ce1152dce51239450baanthony { A = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 112755a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(MagickPI*sigma*sigma*sigma*sigma)); 1128bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1129bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 11309eb4f74649b23c053b308ce1152dce51239450baanthony { R = ((double)(u*u+v*v))*A; 11319eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] = (1-R)*exp(-R)*B; 11329eb4f74649b23c053b308ce1152dce51239450baanthony } 11339eb4f74649b23c053b308ce1152dce51239450baanthony } 11349eb4f74649b23c053b308ce1152dce51239450baanthony else /* special case - generate a unity kernel */ 11359eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 11369eb4f74649b23c053b308ce1152dce51239450baanthony kernel->width*kernel->height*sizeof(double)); 11379eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 11389eb4f74649b23c053b308ce1152dce51239450baanthony } 11399eb4f74649b23c053b308ce1152dce51239450baanthony } 11409eb4f74649b23c053b308ce1152dce51239450baanthony 11419eb4f74649b23c053b308ce1152dce51239450baanthony /* Note the above kernels may have been 'clipped' by a user defined 1142c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** radius, producing a smaller (darker) kernel. Also for very small 1143c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** sigma's (> 0.1) the central value becomes larger than one, and thus 1144c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** producing a very bright kernel. 1145c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 1146c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** Normalization will still be needed. 1147c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony */ 1148602ab9b30b644a78a4057da93d838a77391ec0acanthony 11493dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* Normalize the 2D Gaussian Kernel 11503dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** 1151c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** NB: a CorrelateNormalize performs a normal Normalize if 1152c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there are no negative values. 11533dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony */ 115446a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* the other kernel meta-data */ 1155c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue); 1156602ab9b30b644a78a4057da93d838a77391ec0acanthony 1157602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1158602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1159602ab9b30b644a78a4057da93d838a77391ec0acanthony case BlurKernel: 1160602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 1161c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma = fabs(args->sigma), 1162501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony alpha, beta; 1163602ab9b30b644a78a4057da93d838a77391ec0acanthony 1164c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( args->rho >= 1.0 ) 1165bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho*2+1; 1166c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1167501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->width = GetOptimalKernelWidth1D(args->rho,sigma); 1168602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height = 1; 1169bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) (kernel->width-1)/2; 1170c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->y = 0; 1171c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 1172e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1173e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1174e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1175d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 117683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1177602ab9b30b644a78a4057da93d838a77391ec0acanthony 1178602ab9b30b644a78a4057da93d838a77391ec0acanthony#if 1 1179602ab9b30b644a78a4057da93d838a77391ec0acanthony#define KernelRank 3 1180602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Formula derived from GetBlurKernel() in "effect.c" (plus bug fix). 1181602ab9b30b644a78a4057da93d838a77391ec0acanthony ** It generates a gaussian 3 times the width, and compresses it into 1182602ab9b30b644a78a4057da93d838a77391ec0acanthony ** the expected range. This produces a closer normalization of the 1183602ab9b30b644a78a4057da93d838a77391ec0acanthony ** resulting kernel, especially for very low sigma values. 1184602ab9b30b644a78a4057da93d838a77391ec0acanthony ** As such while wierd it is prefered. 1185602ab9b30b644a78a4057da93d838a77391ec0acanthony ** 1186602ab9b30b644a78a4057da93d838a77391ec0acanthony ** I am told this method originally came from Photoshop. 11879eb4f74649b23c053b308ce1152dce51239450baanthony ** 11889eb4f74649b23c053b308ce1152dce51239450baanthony ** A properly normalized curve is generated (apart from edge clipping) 11899eb4f74649b23c053b308ce1152dce51239450baanthony ** even though we later normalize the result (for edge clipping) 11909eb4f74649b23c053b308ce1152dce51239450baanthony ** to allow the correct generation of a "Difference of Blurs". 1191602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 1192c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1193c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* initialize */ 1194bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy v = (ssize_t) (kernel->width*KernelRank-1)/2; /* start/end points to fit range */ 11959eb4f74649b23c053b308ce1152dce51239450baanthony (void) ResetMagickMemory(kernel->values,0, (size_t) 11969eb4f74649b23c053b308ce1152dce51239450baanthony kernel->width*kernel->height*sizeof(double)); 1197c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Calculate a Positive 1D Gaussian */ 1198c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma > MagickEpsilon ) 1199c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { sigma *= KernelRank; /* simplify loop expressions */ 1200501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony alpha = 1.0/(2.0*sigma*sigma); 120155a91cddcdea3aa002893186a773e1704884a9dfcristy beta= (double) (1.0/(MagickSQ2PI*sigma )); 1202c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony for ( u=-v; u <= v; u++) { 1203501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[(u+v)/KernelRank] += 1204501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony exp(-((double)(u*u))*alpha)*beta; 1205c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1206c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1207c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else /* special case - generate a unity kernel */ 1208c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 1209602ab9b30b644a78a4057da93d838a77391ec0acanthony#else 121053f576d128f0bb744a82e7f9c0d8f05b2923972canthony /* Direct calculation without curve averaging 121153f576d128f0bb744a82e7f9c0d8f05b2923972canthony This is equivelent to a KernelRank of 1 */ 1212c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1213c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Calculate a Positive Gaussian */ 1214c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma > MagickEpsilon ) 1215501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony { alpha = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 1216501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony beta = 1.0/(MagickSQ2PI*sigma); 1217bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 1218501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[i] = exp(-((double)(u*u))*alpha)*beta; 1219c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1220c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else /* special case - generate a unity kernel */ 1221c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 1222c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width*kernel->height*sizeof(double)); 1223c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 1224c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1225602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 1226c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Note the above kernel may have been 'clipped' by a user defined 1227cc6c836da2a53b6023b716e4973090a6714dc3b0anthony ** radius, producing a smaller (darker) kernel. Also for very small 122853f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** sigma's (> 0.1) the central value becomes larger than one, as a 122953f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** result of not generating a actual 'discrete' kernel, and thus 123053f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** producing a very bright 'impulse'. 1231c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 123253f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** Becuase of these two factors Normalization is required! 1233602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 1234cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 1235602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Normalize the 1D Gaussian Kernel 1236602ab9b30b644a78a4057da93d838a77391ec0acanthony ** 1237c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** NB: a CorrelateNormalize performs a normal Normalize if 1238c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there are no negative values. 1239602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 124046a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* the other kernel meta-data */ 124146a369d839971ab627bdb31a93d8bd63e81b65a3anthony ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue); 1242cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 1243c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* rotate the 1D kernel by given angle */ 1244501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony RotateKernelInfo(kernel, args->xi ); 1245602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1246602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1247602ab9b30b644a78a4057da93d838a77391ec0acanthony case CometKernel: 1248602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 12499eb4f74649b23c053b308ce1152dce51239450baanthony sigma = fabs(args->sigma), 12509eb4f74649b23c053b308ce1152dce51239450baanthony A; 1251602ab9b30b644a78a4057da93d838a77391ec0acanthony 1252602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->rho < 1.0 ) 1253e1cf9465864144e8b8043d522906c1e47bbf6192anthony kernel->width = (GetOptimalKernelWidth1D(args->rho,sigma)-1)/2+1; 1254602ab9b30b644a78a4057da93d838a77391ec0acanthony else 1255bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho; 1256c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->x = kernel->y = 0; 1257602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height = 1; 1258c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 1259e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1260e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1261e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1262d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 126383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1264602ab9b30b644a78a4057da93d838a77391ec0acanthony 1265c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* A comet blur is half a 1D gaussian curve, so that the object is 1266602ab9b30b644a78a4057da93d838a77391ec0acanthony ** blurred in one direction only. This may not be quite the right 12673dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** curve to use so may change in the future. The function must be 12683dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** normalised after generation, which also resolves any clipping. 1269c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 1270c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** As we are normalizing and not subtracting gaussians, 1271c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there is no need for a divisor in the gaussian formula 1272c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 127343c4925e5305a26e48d68f7893e94f55d0831c39anthony ** It is less comples 1274602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 12759eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 12769eb4f74649b23c053b308ce1152dce51239450baanthony { 1277602ab9b30b644a78a4057da93d838a77391ec0acanthony#if 1 1278602ab9b30b644a78a4057da93d838a77391ec0acanthony#define KernelRank 3 1279bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy v = (ssize_t) kernel->width*KernelRank; /* start/end points */ 12809eb4f74649b23c053b308ce1152dce51239450baanthony (void) ResetMagickMemory(kernel->values,0, (size_t) 12819eb4f74649b23c053b308ce1152dce51239450baanthony kernel->width*sizeof(double)); 12829eb4f74649b23c053b308ce1152dce51239450baanthony sigma *= KernelRank; /* simplify the loop expression */ 12839eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); 12849eb4f74649b23c053b308ce1152dce51239450baanthony /* B = 1.0/(MagickSQ2PI*sigma); */ 12859eb4f74649b23c053b308ce1152dce51239450baanthony for ( u=0; u < v; u++) { 12869eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[u/KernelRank] += 12879eb4f74649b23c053b308ce1152dce51239450baanthony exp(-((double)(u*u))*A); 12889eb4f74649b23c053b308ce1152dce51239450baanthony /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */ 12899eb4f74649b23c053b308ce1152dce51239450baanthony } 1290bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) kernel->width; i++) 12919eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range += kernel->values[i]; 1292602ab9b30b644a78a4057da93d838a77391ec0acanthony#else 12939eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); /* simplify the loop expression */ 12949eb4f74649b23c053b308ce1152dce51239450baanthony /* B = 1.0/(MagickSQ2PI*sigma); */ 1295bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0; i < (ssize_t) kernel->width; i++) 12969eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range += 129753f576d128f0bb744a82e7f9c0d8f05b2923972canthony kernel->values[i] = exp(-((double)(i*i))*A); 12989eb4f74649b23c053b308ce1152dce51239450baanthony /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */ 1299602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 13009eb4f74649b23c053b308ce1152dce51239450baanthony } 13019eb4f74649b23c053b308ce1152dce51239450baanthony else /* special case - generate a unity kernel */ 13029eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 13039eb4f74649b23c053b308ce1152dce51239450baanthony kernel->width*kernel->height*sizeof(double)); 13049eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 13059eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range = 1.0; 13069eb4f74649b23c053b308ce1152dce51239450baanthony } 130746a369d839971ab627bdb31a93d8bd63e81b65a3anthony 130846a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->minimum = 0.0; 1309c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 131046a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->negative_range = 0.0; 1311602ab9b30b644a78a4057da93d838a77391ec0acanthony 1312999bb2c20aa9d42875bb5adba44951988d4ae354anthony ScaleKernelInfo(kernel, 1.0, NormalizeValue); /* Normalize */ 1313999bb2c20aa9d42875bb5adba44951988d4ae354anthony RotateKernelInfo(kernel, args->xi); /* Rotate by angle */ 1314602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1315602ab9b30b644a78a4057da93d838a77391ec0acanthony } 131640ca0b982379d4ab2716435a46603d56b5b218b1anthony case BinomialKernel: 131740ca0b982379d4ab2716435a46603d56b5b218b1anthony { 131840ca0b982379d4ab2716435a46603d56b5b218b1anthony size_t 131940ca0b982379d4ab2716435a46603d56b5b218b1anthony order_f; 132040ca0b982379d4ab2716435a46603d56b5b218b1anthony 132140ca0b982379d4ab2716435a46603d56b5b218b1anthony if (args->rho < 1.0) 132240ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->width = kernel->height = 3; /* default radius = 1 */ 132340ca0b982379d4ab2716435a46603d56b5b218b1anthony else 132440ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 132540ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 132640ca0b982379d4ab2716435a46603d56b5b218b1anthony 132740ca0b982379d4ab2716435a46603d56b5b218b1anthony order_f = fact(kernel->width-1); 132840ca0b982379d4ab2716435a46603d56b5b218b1anthony 1329e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1330e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1331e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1332d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 133340ca0b982379d4ab2716435a46603d56b5b218b1anthony return(DestroyKernelInfo(kernel)); 133440ca0b982379d4ab2716435a46603d56b5b218b1anthony 133540ca0b982379d4ab2716435a46603d56b5b218b1anthony /* set all kernel values within diamond area to scale given */ 133640ca0b982379d4ab2716435a46603d56b5b218b1anthony for ( i=0, v=0; v < (ssize_t)kernel->height; v++) 133740ca0b982379d4ab2716435a46603d56b5b218b1anthony { size_t 1338f13c594b1d9509e479fd845c3b8a5bb1351c32eacristy alpha = order_f / ( fact((size_t) v) * fact(kernel->height-v-1) ); 133940ca0b982379d4ab2716435a46603d56b5b218b1anthony for ( u=0; u < (ssize_t)kernel->width; u++, i++) 134040ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->positive_range += kernel->values[i] = (double) 1341f13c594b1d9509e479fd845c3b8a5bb1351c32eacristy (alpha * order_f / ( fact((size_t) u) * fact(kernel->height-u-1) )); 134240ca0b982379d4ab2716435a46603d56b5b218b1anthony } 134340ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->minimum = 1.0; 134440ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->maximum = kernel->values[kernel->x+kernel->y*kernel->width]; 134540ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->negative_range = 0.0; 134640ca0b982379d4ab2716435a46603d56b5b218b1anthony break; 134740ca0b982379d4ab2716435a46603d56b5b218b1anthony } 1348c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1349529482f4b494010a13338a74446c510712f670b3anthony /* 1350529482f4b494010a13338a74446c510712f670b3anthony Convolution Kernels - Well Known Named Constant Kernels 1351529482f4b494010a13338a74446c510712f670b3anthony */ 13523c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony case LaplacianKernel: 1353e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony { switch ( (int) args->rho ) { 13543dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case 0: 13559eb4f74649b23c053b308ce1152dce51239450baanthony default: /* laplacian square filter -- default */ 1356c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: -1,-1,-1 -1,8,-1 -1,-1,-1"); 13573dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony break; 13589eb4f74649b23c053b308ce1152dce51239450baanthony case 1: /* laplacian diamond filter */ 1359c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: 0,-1,0 -1,4,-1 0,-1,0"); 13603c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13613c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony case 2: 13629eb4f74649b23c053b308ce1152dce51239450baanthony kernel=ParseKernelArray("3: -2,1,-2 1,4,1 -2,1,-2"); 13639eb4f74649b23c053b308ce1152dce51239450baanthony break; 13649eb4f74649b23c053b308ce1152dce51239450baanthony case 3: 1365c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: 1,-2,1 -2,4,-2 1,-2,1"); 13663c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13679eb4f74649b23c053b308ce1152dce51239450baanthony case 5: /* a 5x5 laplacian */ 13683c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel=ParseKernelArray( 13699eb4f74649b23c053b308ce1152dce51239450baanthony "5: -4,-1,0,-1,-4 -1,2,3,2,-1 0,3,4,3,0 -1,2,3,2,-1 -4,-1,0,-1,-4"); 13703c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13719eb4f74649b23c053b308ce1152dce51239450baanthony case 7: /* a 7x7 laplacian */ 13723c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel=ParseKernelArray( 1373c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony "7:-10,-5,-2,-1,-2,-5,-10 -5,0,3,4,3,0,-5 -2,3,6,7,6,3,-2 -1,4,7,8,7,4,-1 -2,3,6,7,6,3,-2 -5,0,3,4,3,0,-5 -10,-5,-2,-1,-2,-5,-10" ); 13743c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 1375501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case 15: /* a 5x5 LoG (sigma approx 1.4) */ 13769eb4f74649b23c053b308ce1152dce51239450baanthony kernel=ParseKernelArray( 13779eb4f74649b23c053b308ce1152dce51239450baanthony "5: 0,0,-1,0,0 0,-1,-2,-1,0 -1,-2,16,-2,-1 0,-1,-2,-1,0 0,0,-1,0,0"); 13789eb4f74649b23c053b308ce1152dce51239450baanthony break; 1379501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case 19: /* a 9x9 LoG (sigma approx 1.4) */ 138043c4925e5305a26e48d68f7893e94f55d0831c39anthony /* http://www.cscjournals.org/csc/manuscript/Journals/IJIP/volume3/Issue1/IJIP-15.pdf */ 138143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel=ParseKernelArray( 1382bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony "9: 0,-1,-1,-2,-2,-2,-1,-1,0 -1,-2,-4,-5,-5,-5,-4,-2,-1 -1,-4,-5,-3,-0,-3,-5,-4,-1 -2,-5,-3,12,24,12,-3,-5,-2 -2,-5,-0,24,40,24,-0,-5,-2 -2,-5,-3,12,24,12,-3,-5,-2 -1,-4,-5,-3,-0,-3,-5,-4,-1 -1,-2,-4,-5,-5,-5,-4,-2,-1 0,-1,-1,-2,-2,-2,-1,-1,0"); 138343c4925e5305a26e48d68f7893e94f55d0831c39anthony break; 13843c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 13853c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if (kernel == (KernelInfo *) NULL) 13863c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony return(kernel); 13873c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->type = type; 13883c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13893c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 1390c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SobelKernel: 1391cceb6f05c2016ea3854b29e7770ec5ff49034ecfanthony { /* Simple Sobel Kernel */ 1392dcc2a474c98415e565434fe52f630acba36fa0c1anthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1393dcc2a474c98415e565434fe52f630acba36fa0c1anthony if (kernel == (KernelInfo *) NULL) 1394dcc2a474c98415e565434fe52f630acba36fa0c1anthony return(kernel); 1395dcc2a474c98415e565434fe52f630acba36fa0c1anthony kernel->type = type; 1396dcc2a474c98415e565434fe52f630acba36fa0c1anthony RotateKernelInfo(kernel, args->rho); 1397dcc2a474c98415e565434fe52f630acba36fa0c1anthony break; 1398dcc2a474c98415e565434fe52f630acba36fa0c1anthony } 1399c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RobertsKernel: 1400c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1401501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 0,0,0 1,-1,0 0,0,0"); 1402c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1403c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1404c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 140546a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1406c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1407c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1408c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PrewittKernel: 1409c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1410501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 1,0,-1 1,0,-1"); 1411c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1412c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1413c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 141446a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1415c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1416c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1417c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CompassKernel: 1418c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1419501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,1,-1 1,-2,-1 1,1,-1"); 1420c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1421c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1422c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 142346a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1424c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1425c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 14269eb4f74649b23c053b308ce1152dce51239450baanthony case KirschKernel: 14279eb4f74649b23c053b308ce1152dce51239450baanthony { 1428501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 5,-3,-3 5,0,-3 5,-3,-3"); 14299eb4f74649b23c053b308ce1152dce51239450baanthony if (kernel == (KernelInfo *) NULL) 14309eb4f74649b23c053b308ce1152dce51239450baanthony return(kernel); 14319eb4f74649b23c053b308ce1152dce51239450baanthony kernel->type = type; 143246a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 14339eb4f74649b23c053b308ce1152dce51239450baanthony break; 14349eb4f74649b23c053b308ce1152dce51239450baanthony } 1435e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony case FreiChenKernel: 1436501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* Direction is set to be left to right positive */ 1437501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf -- RIGHT? */ 1438501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf -- WRONG? */ 14391dd091ae3bc17edc26c16cc47f436a24bd48412aanthony { switch ( (int) args->rho ) { 1440e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony default: 1441c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony case 0: 1442501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1443c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony if (kernel == (KernelInfo *) NULL) 1444c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony return(kernel); 1445ef33d9f66f955c1f6f5f7105e164cc2d5c5e2a41anthony kernel->type = type; 1446d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[3] = +(MagickRealType) MagickSQ2; 1447d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[5] = -(MagickRealType) MagickSQ2; 1448c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 1449c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony break; 1450c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 2: 1451c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel=ParseKernelArray("3: 1,2,0 2,0,-2 0,-2,-1"); 1452c40ac1e79923a1516075ba1197ae4ed90244af9banthony if (kernel == (KernelInfo *) NULL) 1453c40ac1e79923a1516075ba1197ae4ed90244af9banthony return(kernel); 1454c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel->type = type; 1455d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[1] = kernel->values[3]= +(MagickRealType) MagickSQ2; 1456d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[5] = kernel->values[7]= -(MagickRealType) MagickSQ2; 1457c40ac1e79923a1516075ba1197ae4ed90244af9banthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 1458d4e3ffa7f64077da0f32c2d8a599737ee8d115ddcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1459c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; 1460c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 10: 1461c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel=AcquireKernelInfo("FreiChen:11;FreiChen:12;FreiChen:13;FreiChen:14;FreiChen:15;FreiChen:16;FreiChen:17;FreiChen:18;FreiChen:19"); 1462c40ac1e79923a1516075ba1197ae4ed90244af9banthony if (kernel == (KernelInfo *) NULL) 1463c40ac1e79923a1516075ba1197ae4ed90244af9banthony return(kernel); 1464c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; 1465e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony case 1: 1466c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 11: 1467501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1468e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1469e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1470c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1471d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[3] = +(MagickRealType) MagickSQ2; 1472d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[5] = -(MagickRealType) MagickSQ2; 1473e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 147455a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1475e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1476c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 12: 1477501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,2,1 0,0,0 1,2,1"); 1478e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1479e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1480c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1481d9123437a79f9d56a3e8c32aa912ae3ae1d47337cristy kernel->values[1] = +(MagickRealType) MagickSQ2; 1482d9123437a79f9d56a3e8c32aa912ae3ae1d47337cristy kernel->values[7] = +(MagickRealType) MagickSQ2; 1483e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 148455a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1485e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1486c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 13: 1487501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 2,-1,0 -1,0,1 0,1,-2"); 1488e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1489e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1490c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1491d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[0] = +(MagickRealType) MagickSQ2; 1492d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[8] = -(MagickRealType) MagickSQ2; 1493e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 149455a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1495e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1496c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 14: 14971d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel=ParseKernelArray("3: 0,1,-2 -1,0,1 2,-1,0"); 1498e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1499e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1500c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1501d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[2] = -(MagickRealType) MagickSQ2; 1502d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[6] = +(MagickRealType) MagickSQ2; 1503e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 150455a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1505e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1506c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 15: 1507501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 0,-1,0 1,0,1 0,-1,0"); 1508e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1509e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1510c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1511e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/2.0, NoValue); 1512e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1513c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 16: 15141d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel=ParseKernelArray("3: 1,0,-1 0,0,0 -1,0,1"); 1515e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1516e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1517c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1518e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/2.0, NoValue); 1519e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1520c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 17: 1521501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,-2,1 -2,4,-2 -1,-2,1"); 1522e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1523e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1524c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1525e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/6.0, NoValue); 1526e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1527c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 18: 1528501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: -2,1,-2 1,4,1 -2,1,-2"); 1529e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1530e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1531c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1532e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/6.0, NoValue); 1533e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1534c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 19: 1535c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel=ParseKernelArray("3: 1,1,1 1,1,1 1,1,1"); 1536e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1537e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1538c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1539e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/3.0, NoValue); 1540e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1541e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony } 1542b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(args->sigma) >= MagickEpsilon ) 1543c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony /* Rotate by correctly supplied 'angle' */ 1544c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony RotateKernelInfo(kernel, args->sigma); 1545c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony else if ( args->rho > 30.0 || args->rho < -30.0 ) 1546c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony /* Rotate by out of bounds 'type' */ 1547c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony RotateKernelInfo(kernel, args->rho); 1548e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1549e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony } 1550e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony 1551529482f4b494010a13338a74446c510712f670b3anthony /* 1552529482f4b494010a13338a74446c510712f670b3anthony Boolean or Shaped Kernels 1553529482f4b494010a13338a74446c510712f670b3anthony */ 1554c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiamondKernel: 1555602ab9b30b644a78a4057da93d838a77391ec0acanthony { 1556c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (args->rho < 1.0) 1557c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = kernel->height = 3; /* default radius = 1 */ 1558c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1559bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = ((size_t)args->rho)*2+1; 1560bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 1561c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1562e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1563e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1564e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1565d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 1566c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(DestroyKernelInfo(kernel)); 1567c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1568c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* set all kernel values within diamond area to scale given */ 1569bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1570bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 15711d5e67090dc7232b35bfcc71b31266c20838defcanthony if ( (labs((long) u)+labs((long) v)) <= (long) kernel->x) 1572c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->positive_range += kernel->values[i] = args->sigma; 1573c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1574c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[i] = nan; 1575c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 1576c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1577c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1578c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SquareKernel: 1579c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RectangleKernel: 1580c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { double 1581c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony scale; 1582602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( type == SquareKernel ) 1583602ab9b30b644a78a4057da93d838a77391ec0acanthony { 1584602ab9b30b644a78a4057da93d838a77391ec0acanthony if (args->rho < 1.0) 1585c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 1586602ab9b30b644a78a4057da93d838a77391ec0acanthony else 1587bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = (size_t) (2*args->rho+1); 1588bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 15894fd27e21043be809d66c8202e779255e5b660d2danthony scale = args->sigma; 1590602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1591602ab9b30b644a78a4057da93d838a77391ec0acanthony else { 15922be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy /* NOTE: user defaults set in "AcquireKernelInfo()" */ 1593602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->rho < 1.0 || args->sigma < 1.0 ) 159483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); /* invalid args given */ 1595bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho; 1596bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t)args->sigma; 1597602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->xi < 0.0 || args->xi > (double)kernel->width || 1598602ab9b30b644a78a4057da93d838a77391ec0acanthony args->psi < 0.0 || args->psi > (double)kernel->height ) 159983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); /* invalid args given */ 1600bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) args->xi; 1601bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = (ssize_t) args->psi; 16024fd27e21043be809d66c8202e779255e5b660d2danthony scale = 1.0; 1603602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1604e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1605e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1606e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1607d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 160883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1609602ab9b30b644a78a4057da93d838a77391ec0acanthony 16103dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* set all kernel values to scale given */ 1611eaedf06777741da32408da72c1e512975c600c48cristy u=(ssize_t) (kernel->width*kernel->height); 1612150989ed67ef9da53141a65e5f3ebdb05dd025abcristy for ( i=0; i < u; i++) 16134fd27e21043be809d66c8202e779255e5b660d2danthony kernel->values[i] = scale; 16144fd27e21043be809d66c8202e779255e5b660d2danthony kernel->minimum = kernel->maximum = scale; /* a flat shape */ 16154fd27e21043be809d66c8202e779255e5b660d2danthony kernel->positive_range = scale*u; 1616cc6c836da2a53b6023b716e4973090a6714dc3b0anthony break; 1617602ab9b30b644a78a4057da93d838a77391ec0acanthony } 16181ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 16191ef941fea2534a0d20ba7d71307d35040247decbanthony { 16201ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 1621a9892d898acb81e1ec73106d892855fdc5a69427anthony kernel->width = kernel->height = 5; /* default radius = 2 */ 16221ef941fea2534a0d20ba7d71307d35040247decbanthony else 16231ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 16241ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16251ef941fea2534a0d20ba7d71307d35040247decbanthony 1626e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1627e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1628e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1629d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 16301ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16311ef941fea2534a0d20ba7d71307d35040247decbanthony 16321ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16331ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16341ef941fea2534a0d20ba7d71307d35040247decbanthony if ( (labs((long) u)+labs((long) v)) <= 16351ef941fea2534a0d20ba7d71307d35040247decbanthony ((long)kernel->x + (long)(kernel->x/2)) ) 16361ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = args->sigma; 16371ef941fea2534a0d20ba7d71307d35040247decbanthony else 16381ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = nan; 1639a9892d898acb81e1ec73106d892855fdc5a69427anthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16401ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16411ef941fea2534a0d20ba7d71307d35040247decbanthony } 16421ef941fea2534a0d20ba7d71307d35040247decbanthony case DiskKernel: 16431ef941fea2534a0d20ba7d71307d35040247decbanthony { 16441ef941fea2534a0d20ba7d71307d35040247decbanthony ssize_t 16450bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony limit = (ssize_t)(args->rho*args->rho); 16461ef941fea2534a0d20ba7d71307d35040247decbanthony 16479bf68d590429a72aa70894f6aea7fc3c94876e54anthony if (args->rho < 0.4) /* default radius approx 4.3 */ 16489bf68d590429a72aa70894f6aea7fc3c94876e54anthony kernel->width = kernel->height = 9L, limit = 18L; 16491ef941fea2534a0d20ba7d71307d35040247decbanthony else 16501ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = (size_t)fabs(args->rho)*2+1; 16511ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16521ef941fea2534a0d20ba7d71307d35040247decbanthony 1653e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1654e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1655e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1656d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 16571ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16581ef941fea2534a0d20ba7d71307d35040247decbanthony 16591ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16601ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16611ef941fea2534a0d20ba7d71307d35040247decbanthony if ((u*u+v*v) <= limit) 16621ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = args->sigma; 16633dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony else 16643dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony kernel->values[i] = nan; 16651ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16661ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16671ef941fea2534a0d20ba7d71307d35040247decbanthony } 16681ef941fea2534a0d20ba7d71307d35040247decbanthony case PlusKernel: 16691ef941fea2534a0d20ba7d71307d35040247decbanthony { 16701ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 16711ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default radius 2 */ 16721ef941fea2534a0d20ba7d71307d35040247decbanthony else 16731ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 16741ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16751ef941fea2534a0d20ba7d71307d35040247decbanthony 1676e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1677e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1678e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1679d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 16801ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16811ef941fea2534a0d20ba7d71307d35040247decbanthony 16821ef941fea2534a0d20ba7d71307d35040247decbanthony /* set all kernel values along axises to given scale */ 16831ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16841ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16851ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan; 16861ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16871ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0); 16881ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16891ef941fea2534a0d20ba7d71307d35040247decbanthony } 16901ef941fea2534a0d20ba7d71307d35040247decbanthony case CrossKernel: 16911ef941fea2534a0d20ba7d71307d35040247decbanthony { 16921ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 16931ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default radius 2 */ 16941ef941fea2534a0d20ba7d71307d35040247decbanthony else 16951ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 16961ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16971ef941fea2534a0d20ba7d71307d35040247decbanthony 1698e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1699e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1700e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1701d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 17021ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 17031ef941fea2534a0d20ba7d71307d35040247decbanthony 17041ef941fea2534a0d20ba7d71307d35040247decbanthony /* set all kernel values along axises to given scale */ 17051ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 17061ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 17071ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = (u == v || u == -v) ? args->sigma : nan; 17081ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 17091ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0); 17101ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17111ef941fea2534a0d20ba7d71307d35040247decbanthony } 1712529482f4b494010a13338a74446c510712f670b3anthony /* 1713529482f4b494010a13338a74446c510712f670b3anthony HitAndMiss Kernels 1714529482f4b494010a13338a74446c510712f670b3anthony */ 17151ef941fea2534a0d20ba7d71307d35040247decbanthony case RingKernel: 17161ef941fea2534a0d20ba7d71307d35040247decbanthony case PeaksKernel: 17171ef941fea2534a0d20ba7d71307d35040247decbanthony { 17181ef941fea2534a0d20ba7d71307d35040247decbanthony ssize_t 17191ef941fea2534a0d20ba7d71307d35040247decbanthony limit1, 17201ef941fea2534a0d20ba7d71307d35040247decbanthony limit2, 17211ef941fea2534a0d20ba7d71307d35040247decbanthony scale; 17221ef941fea2534a0d20ba7d71307d35040247decbanthony 17231ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < args->sigma) 17241ef941fea2534a0d20ba7d71307d35040247decbanthony { 17251ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = ((size_t)args->sigma)*2+1; 17261ef941fea2534a0d20ba7d71307d35040247decbanthony limit1 = (ssize_t)(args->rho*args->rho); 17271ef941fea2534a0d20ba7d71307d35040247decbanthony limit2 = (ssize_t)(args->sigma*args->sigma); 17283dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony } 17291ef941fea2534a0d20ba7d71307d35040247decbanthony else 17301ef941fea2534a0d20ba7d71307d35040247decbanthony { 17311ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = ((size_t)args->rho)*2+1; 17321ef941fea2534a0d20ba7d71307d35040247decbanthony limit1 = (ssize_t)(args->sigma*args->sigma); 17331ef941fea2534a0d20ba7d71307d35040247decbanthony limit2 = (ssize_t)(args->rho*args->rho); 17341ef941fea2534a0d20ba7d71307d35040247decbanthony } 17351ef941fea2534a0d20ba7d71307d35040247decbanthony if ( limit2 <= 0 ) 17361ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = 7L, limit1 = 7L, limit2 = 11L; 17371ef941fea2534a0d20ba7d71307d35040247decbanthony 17381ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height = kernel->width; 17391ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 1740e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1741e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1742e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1743d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 17441ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 17451ef941fea2534a0d20ba7d71307d35040247decbanthony 17461ef941fea2534a0d20ba7d71307d35040247decbanthony /* set a ring of points of 'scale' ( 0.0 for PeaksKernel ) */ 17471ef941fea2534a0d20ba7d71307d35040247decbanthony scale = (ssize_t) (( type == PeaksKernel) ? 0.0 : args->xi); 17481ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v= -kernel->y; v <= (ssize_t)kernel->y; v++) 17491ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 17501ef941fea2534a0d20ba7d71307d35040247decbanthony { ssize_t radius=u*u+v*v; 17511ef941fea2534a0d20ba7d71307d35040247decbanthony if (limit1 < radius && radius <= limit2) 17521ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = (double) scale; 17531ef941fea2534a0d20ba7d71307d35040247decbanthony else 17541ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = nan; 17551ef941fea2534a0d20ba7d71307d35040247decbanthony } 17561ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = (double) scale; 17571ef941fea2534a0d20ba7d71307d35040247decbanthony if ( type == PeaksKernel ) { 17581ef941fea2534a0d20ba7d71307d35040247decbanthony /* set the central point in the middle */ 17591ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 17601ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = 1.0; 17611ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = 1.0; 17621ef941fea2534a0d20ba7d71307d35040247decbanthony } 17631ef941fea2534a0d20ba7d71307d35040247decbanthony break; 1764c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 17651ef941fea2534a0d20ba7d71307d35040247decbanthony case EdgesKernel: 17661ef941fea2534a0d20ba7d71307d35040247decbanthony { 1767529482f4b494010a13338a74446c510712f670b3anthony kernel=AcquireKernelInfo("ThinSE:482"); 17681ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17691ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17701ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 1771529482f4b494010a13338a74446c510712f670b3anthony ExpandMirrorKernelInfo(kernel); /* mirror expansion of kernels */ 17721ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17731ef941fea2534a0d20ba7d71307d35040247decbanthony } 17741ef941fea2534a0d20ba7d71307d35040247decbanthony case CornersKernel: 17751ef941fea2534a0d20ba7d71307d35040247decbanthony { 1776529482f4b494010a13338a74446c510712f670b3anthony kernel=AcquireKernelInfo("ThinSE:87"); 17771ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17781ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17791ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 17801ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* Expand 90 degree rotations */ 17811ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17821ef941fea2534a0d20ba7d71307d35040247decbanthony } 1783529482f4b494010a13338a74446c510712f670b3anthony case DiagonalsKernel: 17841ef941fea2534a0d20ba7d71307d35040247decbanthony { 17851ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 17861ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 17871ef941fea2534a0d20ba7d71307d35040247decbanthony default: 17881ef941fea2534a0d20ba7d71307d35040247decbanthony { KernelInfo 17891ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 1790529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,0 0,-,1 1,1,-"); 17911ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17921ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17931ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 1794529482f4b494010a13338a74446c510712f670b3anthony new_kernel=ParseKernelArray("3: 0,0,1 0,-,1 0,1,-"); 17951ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 17961ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 17971ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 17981ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 17991ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandMirrorKernelInfo(kernel); 1800529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 18011ef941fea2534a0d20ba7d71307d35040247decbanthony } 18021ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 1803529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,0 0,-,1 1,1,-"); 18041ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18051ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 1806529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,1 0,-,1 0,1,-"); 18071ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18081ef941fea2534a0d20ba7d71307d35040247decbanthony } 1809529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1810529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1811529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1812529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 18131ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18141ef941fea2534a0d20ba7d71307d35040247decbanthony } 18151ef941fea2534a0d20ba7d71307d35040247decbanthony case LineEndsKernel: 18161ef941fea2534a0d20ba7d71307d35040247decbanthony { /* Kernels for finding the end of thin lines */ 18171ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 18181ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 18191ef941fea2534a0d20ba7d71307d35040247decbanthony default: 18201ef941fea2534a0d20ba7d71307d35040247decbanthony /* set of kernels to find all end of lines */ 1821529482f4b494010a13338a74446c510712f670b3anthony return(AcquireKernelInfo("LineEnds:1>;LineEnds:2>")); 18221ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 18231ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel for 4-connected line ends - no rotation */ 18241ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,- 0,1,1 0,0,-"); 18251ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18261ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 18271ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel to add for 8-connected lines - no rotation */ 18281ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,0 0,0,1"); 18291ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18301ef941fea2534a0d20ba7d71307d35040247decbanthony case 3: 18311ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel to add for orthogonal line ends - does not find corners */ 18321ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,1 0,0,0"); 18331ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18341ef941fea2534a0d20ba7d71307d35040247decbanthony case 4: 18351ef941fea2534a0d20ba7d71307d35040247decbanthony /* traditional line end - fails on last T end */ 18361ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,- 0,0,-"); 18371ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18381ef941fea2534a0d20ba7d71307d35040247decbanthony } 1839529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1840529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1841529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1842529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 18431ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18441ef941fea2534a0d20ba7d71307d35040247decbanthony } 18451ef941fea2534a0d20ba7d71307d35040247decbanthony case LineJunctionsKernel: 18461ef941fea2534a0d20ba7d71307d35040247decbanthony { /* kernels for finding the junctions of multiple lines */ 18471ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 18481ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 18491ef941fea2534a0d20ba7d71307d35040247decbanthony default: 18501ef941fea2534a0d20ba7d71307d35040247decbanthony /* set of kernels to find all line junctions */ 1851529482f4b494010a13338a74446c510712f670b3anthony return(AcquireKernelInfo("LineJunctions:1@;LineJunctions:2>")); 18521ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 18531ef941fea2534a0d20ba7d71307d35040247decbanthony /* Y Junction */ 18541ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,1 -,1,- -,1,-"); 18551ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18561ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 18571ef941fea2534a0d20ba7d71307d35040247decbanthony /* Diagonal T Junctions */ 18581ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,- -,1,- 1,-,1"); 18591ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18601ef941fea2534a0d20ba7d71307d35040247decbanthony case 3: 18611ef941fea2534a0d20ba7d71307d35040247decbanthony /* Orthogonal T Junctions */ 18621ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: -,-,- 1,1,1 -,1,-"); 18631ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18641ef941fea2534a0d20ba7d71307d35040247decbanthony case 4: 18651ef941fea2534a0d20ba7d71307d35040247decbanthony /* Diagonal X Junctions */ 18661ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,1 -,1,- 1,-,1"); 18671ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18681ef941fea2534a0d20ba7d71307d35040247decbanthony case 5: 18691ef941fea2534a0d20ba7d71307d35040247decbanthony /* Orthogonal X Junctions - minimal diamond kernel */ 18701ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: -,1,- 1,1,1 -,1,-"); 18711ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18721ef941fea2534a0d20ba7d71307d35040247decbanthony } 1873529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1874529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1875529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1876529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 18771ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18781ef941fea2534a0d20ba7d71307d35040247decbanthony } 18791ef941fea2534a0d20ba7d71307d35040247decbanthony case RidgesKernel: 18801ef941fea2534a0d20ba7d71307d35040247decbanthony { /* Ridges - Ridge finding kernels */ 18811ef941fea2534a0d20ba7d71307d35040247decbanthony KernelInfo 18821ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 18831ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 18841ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 18851ef941fea2534a0d20ba7d71307d35040247decbanthony default: 18861ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3x1:0,1,0"); 18871ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 18881ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 18891ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 18901ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* 2 rotated kernels (symmetrical) */ 18911ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18921ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 18931ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("4x1:0,1,1,0"); 18941ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 18951ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 18961ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 18971ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotated kernels */ 18981ef941fea2534a0d20ba7d71307d35040247decbanthony 18991ef941fea2534a0d20ba7d71307d35040247decbanthony /* Kernels to find a stepped 'thick' line, 4 rotates + mirrors */ 19001ef941fea2534a0d20ba7d71307d35040247decbanthony /* Unfortunatally we can not yet rotate a non-square kernel */ 19011ef941fea2534a0d20ba7d71307d35040247decbanthony /* But then we can't flip a non-symetrical kernel either */ 19021ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+1+1:0,1,1,- -,1,1,- -,1,1,0"); 19031ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19041ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19051ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19061ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19071ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+2+1:0,1,1,- -,1,1,- -,1,1,0"); 19081ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19091ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19101ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19111ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19121ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+1+1:-,1,1,0 -,1,1,- 0,1,1,-"); 19131ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19141ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19151ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19161ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19171ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+2+1:-,1,1,0 -,1,1,- 0,1,1,-"); 19181ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19191ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19201ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19211ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19221ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+1:0,-,- 1,1,1 1,1,1 -,-,0"); 19231ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19241ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19251ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19261ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19271ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+2:0,-,- 1,1,1 1,1,1 -,-,0"); 19281ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19291ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19301ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19311ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19321ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+1:-,-,0 1,1,1 1,1,1 0,-,-"); 19331ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19341ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19351ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19361ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19371ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+2:-,-,0 1,1,1 1,1,1 0,-,-"); 193868cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony if (new_kernel == (KernelInfo *) NULL) 193968cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony return(DestroyKernelInfo(kernel)); 194068cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony new_kernel->type = type; 194168cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony LastKernelInfo(kernel)->next = new_kernel; 194268cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony break; 19431ef941fea2534a0d20ba7d71307d35040247decbanthony } 19441ef941fea2534a0d20ba7d71307d35040247decbanthony break; 194568cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony } 19461ef941fea2534a0d20ba7d71307d35040247decbanthony case ConvexHullKernel: 19471ef941fea2534a0d20ba7d71307d35040247decbanthony { 19481ef941fea2534a0d20ba7d71307d35040247decbanthony KernelInfo 19491ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 19501ef941fea2534a0d20ba7d71307d35040247decbanthony /* first set of 8 kernels */ 19511ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,1,- 1,0,- 1,-,0"); 19521ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 19531ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 19541ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 19551ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); 19561ef941fea2534a0d20ba7d71307d35040247decbanthony /* append the mirror versions too - no flip function yet */ 19571ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3: 1,1,1 1,0,- -,-,0"); 19581ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19591ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19601ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19611ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(new_kernel, 90.0); 19621ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19631ef941fea2534a0d20ba7d71307d35040247decbanthony break; 1964694934fa79dd310f727588b1d0a7481fa6170f1danthony } 19659a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case SkeletonKernel: 19669a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony { 19679a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony switch ( (int) args->rho ) { 19689a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 1: 19699a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony default: 19709a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* Traditional Skeleton... 19719a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** A cyclically rotated single kernel 19729a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19739a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo("ThinSE:482"); 19749a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19759a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19769a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19779a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandRotateKernelInfo(kernel, 45.0); /* 8 rotations */ 19789a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19799a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 2: 19809a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* HIPR Variation of the cyclic skeleton 19819a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** Corners of the traditional method made more forgiving, 19829a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** but the retain the same cyclic order. 19839a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19849a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo("ThinSE:482; ThinSE:87x90;"); 19859a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19869a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19879a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel->next == (KernelInfo *) NULL) 19889a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(DestroyKernelInfo(kernel)); 19899a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19909a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->type = type; 19919a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotations of the 2 kernels */ 19929a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19939a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 3: 19949a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* Dan Bloomberg Skeleton, from his paper on 3x3 thinning SE's 19959a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** "Connectivity-Preserving Morphological Image Thransformations" 19969a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** by Dan S. Bloomberg, available on Leptonica, Selected Papers, 19979a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** http://www.leptonica.com/papers/conn.pdf 19989a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19999a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo( 20009a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony "ThinSE:41; ThinSE:42; ThinSE:43"); 20019a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 20029a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 20039a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 20049a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->type = type; 20059a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->next->type = type; 20069a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandMirrorKernelInfo(kernel); /* 12 kernels total */ 20079a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 20089a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony } 20099a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 20109a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony } 2011529482f4b494010a13338a74446c510712f670b3anthony case ThinSEKernel: 2012529482f4b494010a13338a74446c510712f670b3anthony { /* Special kernels for general thinning, while preserving connections 2013529482f4b494010a13338a74446c510712f670b3anthony ** "Connectivity-Preserving Morphological Image Thransformations" 2014529482f4b494010a13338a74446c510712f670b3anthony ** by Dan S. Bloomberg, available on Leptonica, Selected Papers, 2015529482f4b494010a13338a74446c510712f670b3anthony ** http://www.leptonica.com/papers/conn.pdf 2016529482f4b494010a13338a74446c510712f670b3anthony ** And 2017529482f4b494010a13338a74446c510712f670b3anthony ** http://tpgit.github.com/Leptonica/ccthin_8c_source.html 2018529482f4b494010a13338a74446c510712f670b3anthony ** 2019529482f4b494010a13338a74446c510712f670b3anthony ** Note kernels do not specify the origin pixel, allowing them 2020529482f4b494010a13338a74446c510712f670b3anthony ** to be used for both thickening and thinning operations. 2021529482f4b494010a13338a74446c510712f670b3anthony */ 2022529482f4b494010a13338a74446c510712f670b3anthony switch ( (int) args->rho ) { 2023529482f4b494010a13338a74446c510712f670b3anthony /* SE for 4-connected thinning */ 2024529482f4b494010a13338a74446c510712f670b3anthony case 41: /* SE_4_1 */ 2025529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 -,-,1"); 2026529482f4b494010a13338a74446c510712f670b3anthony break; 2027529482f4b494010a13338a74446c510712f670b3anthony case 42: /* SE_4_2 */ 2028529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 -,0,-"); 2029529482f4b494010a13338a74446c510712f670b3anthony break; 2030529482f4b494010a13338a74446c510712f670b3anthony case 43: /* SE_4_3 */ 2031529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,-,1"); 2032529482f4b494010a13338a74446c510712f670b3anthony break; 2033529482f4b494010a13338a74446c510712f670b3anthony case 44: /* SE_4_4 */ 2034529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,0,-"); 2035529482f4b494010a13338a74446c510712f670b3anthony break; 2036529482f4b494010a13338a74446c510712f670b3anthony case 45: /* SE_4_5 */ 2037529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,1 0,-,1 -,0,-"); 2038529482f4b494010a13338a74446c510712f670b3anthony break; 2039529482f4b494010a13338a74446c510712f670b3anthony case 46: /* SE_4_6 */ 2040529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,0,1"); 2041529482f4b494010a13338a74446c510712f670b3anthony break; 2042529482f4b494010a13338a74446c510712f670b3anthony case 47: /* SE_4_7 */ 2043529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,1 0,-,1 -,0,-"); 2044529482f4b494010a13338a74446c510712f670b3anthony break; 2045529482f4b494010a13338a74446c510712f670b3anthony case 48: /* SE_4_8 */ 2046529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 0,-,1"); 2047529482f4b494010a13338a74446c510712f670b3anthony break; 2048529482f4b494010a13338a74446c510712f670b3anthony case 49: /* SE_4_9 */ 2049529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 -,-,1"); 2050529482f4b494010a13338a74446c510712f670b3anthony break; 2051529482f4b494010a13338a74446c510712f670b3anthony /* SE for 8-connected thinning - negatives of the above */ 2052529482f4b494010a13338a74446c510712f670b3anthony case 81: /* SE_8_0 */ 2053529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 -,1,-"); 2054529482f4b494010a13338a74446c510712f670b3anthony break; 2055529482f4b494010a13338a74446c510712f670b3anthony case 82: /* SE_8_2 */ 2056529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,-,-"); 2057529482f4b494010a13338a74446c510712f670b3anthony break; 2058529482f4b494010a13338a74446c510712f670b3anthony case 83: /* SE_8_3 */ 2059529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 -,1,-"); 2060529482f4b494010a13338a74446c510712f670b3anthony break; 2061529482f4b494010a13338a74446c510712f670b3anthony case 84: /* SE_8_4 */ 2062529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 0,-,-"); 2063529482f4b494010a13338a74446c510712f670b3anthony break; 2064529482f4b494010a13338a74446c510712f670b3anthony case 85: /* SE_8_5 */ 2065529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 0,-,-"); 2066529482f4b494010a13338a74446c510712f670b3anthony break; 2067529482f4b494010a13338a74446c510712f670b3anthony case 86: /* SE_8_6 */ 2068529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 0,-,1"); 2069529482f4b494010a13338a74446c510712f670b3anthony break; 2070529482f4b494010a13338a74446c510712f670b3anthony case 87: /* SE_8_7 */ 2071529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,0,-"); 2072529482f4b494010a13338a74446c510712f670b3anthony break; 2073529482f4b494010a13338a74446c510712f670b3anthony case 88: /* SE_8_8 */ 2074529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,1,-"); 2075529482f4b494010a13338a74446c510712f670b3anthony break; 2076529482f4b494010a13338a74446c510712f670b3anthony case 89: /* SE_8_9 */ 2077529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,1,- 0,-,1 -,1,-"); 2078529482f4b494010a13338a74446c510712f670b3anthony break; 2079529482f4b494010a13338a74446c510712f670b3anthony /* Special combined SE kernels */ 20809a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 423: /* SE_4_2 , SE_4_3 Combined Kernel */ 20819a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=ParseKernelArray("3: -,-,1 0,-,- -,0,-"); 20829a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 20839a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 823: /* SE_8_2 , SE_8_3 Combined Kernel */ 20849a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=ParseKernelArray("3: -,1,- -,-,1 0,-,-"); 20859a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 2086529482f4b494010a13338a74446c510712f670b3anthony case 481: /* SE_48_1 - General Connected Corner Kernel */ 2087529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,1 0,-,1 0,0,-"); 2088529482f4b494010a13338a74446c510712f670b3anthony break; 2089529482f4b494010a13338a74446c510712f670b3anthony default: 2090529482f4b494010a13338a74446c510712f670b3anthony case 482: /* SE_48_2 - General Edge Kernel */ 2091529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 0,-,1"); 2092529482f4b494010a13338a74446c510712f670b3anthony break; 2093529482f4b494010a13338a74446c510712f670b3anthony } 2094529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 2095529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 2096529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 2097529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 2098529482f4b494010a13338a74446c510712f670b3anthony break; 2099529482f4b494010a13338a74446c510712f670b3anthony } 2100529482f4b494010a13338a74446c510712f670b3anthony /* 2101529482f4b494010a13338a74446c510712f670b3anthony Distance Measuring Kernels 2102529482f4b494010a13338a74446c510712f670b3anthony */ 21031ef941fea2534a0d20ba7d71307d35040247decbanthony case ChebyshevKernel: 21041ef941fea2534a0d20ba7d71307d35040247decbanthony { 21051ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 21061ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 21071ef941fea2534a0d20ba7d71307d35040247decbanthony else 21081ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 21091ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 21101ef941fea2534a0d20ba7d71307d35040247decbanthony 2111e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2112e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2113e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2114d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 21151ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 21161ef941fea2534a0d20ba7d71307d35040247decbanthony 21171ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 21181ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 21191ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += ( kernel->values[i] = 21201ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*MagickMax(fabs((double)u),fabs((double)v)) ); 21211ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = kernel->values[0]; 21221ef941fea2534a0d20ba7d71307d35040247decbanthony break; 2123c40ac1e79923a1516075ba1197ae4ed90244af9banthony } 21241ef941fea2534a0d20ba7d71307d35040247decbanthony case ManhattanKernel: 21251ef941fea2534a0d20ba7d71307d35040247decbanthony { 21261ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 21271ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 21281ef941fea2534a0d20ba7d71307d35040247decbanthony else 21291ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 21301ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 21311ef941fea2534a0d20ba7d71307d35040247decbanthony 2132e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2133e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2134e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2135d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 21361ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 21371ef941fea2534a0d20ba7d71307d35040247decbanthony 21381ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 21391ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 21401ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += ( kernel->values[i] = 21411ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*(labs((long) u)+labs((long) v)) ); 21421ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = kernel->values[0]; 21431ef941fea2534a0d20ba7d71307d35040247decbanthony break; 2144c40ac1e79923a1516075ba1197ae4ed90244af9banthony } 21451ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonalKernel: 2146602ab9b30b644a78a4057da93d838a77391ec0acanthony { 21471ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 2.0) 21481ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default/minimum radius = 2 */ 2149602ab9b30b644a78a4057da93d838a77391ec0acanthony else 2150bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = ((size_t)args->rho)*2+1; 2151bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 2152602ab9b30b644a78a4057da93d838a77391ec0acanthony 2153e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2154e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2155e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2156d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 215783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 2158602ab9b30b644a78a4057da93d838a77391ec0acanthony 2159bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 2160bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 21611ef941fea2534a0d20ba7d71307d35040247decbanthony { 21621ef941fea2534a0d20ba7d71307d35040247decbanthony double 21631ef941fea2534a0d20ba7d71307d35040247decbanthony r1 = MagickMax(fabs((double)u),fabs((double)v)), 21641ef941fea2534a0d20ba7d71307d35040247decbanthony r2 = floor((double)(labs((long)u)+labs((long)v)+1)/1.5); 21651ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = 21661ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*MagickMax(r1,r2); 21671ef941fea2534a0d20ba7d71307d35040247decbanthony } 2168c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 2169602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2170602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2171602ab9b30b644a78a4057da93d838a77391ec0acanthony case EuclideanKernel: 2172602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2173602ab9b30b644a78a4057da93d838a77391ec0acanthony if (args->rho < 1.0) 2174c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 2175602ab9b30b644a78a4057da93d838a77391ec0acanthony else 21761ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 2177bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 2178602ab9b30b644a78a4057da93d838a77391ec0acanthony 2179e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2180e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2181e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2182d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 218383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 2184602ab9b30b644a78a4057da93d838a77391ec0acanthony 2185bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 2186bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 2187c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->positive_range += ( kernel->values[i] = 21880ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony args->sigma*sqrt((double)(u*u+v*v)) ); 2189c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 2190602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2191602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2192602ab9b30b644a78a4057da93d838a77391ec0acanthony default: 2193c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 2194529482f4b494010a13338a74446c510712f670b3anthony /* No-Op Kernel - Basically just a single pixel on its own */ 21953ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony kernel=ParseKernelArray("1:1"); 2196c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 2197c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 2198529482f4b494010a13338a74446c510712f670b3anthony kernel->type = UndefinedKernel; 2199c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 2200c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 2201602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2202602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2203602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 2204602ab9b30b644a78a4057da93d838a77391ec0acanthony} 2205c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony 2206602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 2207602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2208602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2209602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2210602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 22116771f1e8987fa49f52d4176281a2e8524b8e31cbcristy% C l o n e K e r n e l I n f o % 22124fd27e21043be809d66c8202e779255e5b660d2danthony% % 22134fd27e21043be809d66c8202e779255e5b660d2danthony% % 22144fd27e21043be809d66c8202e779255e5b660d2danthony% % 22154fd27e21043be809d66c8202e779255e5b660d2danthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22164fd27e21043be809d66c8202e779255e5b660d2danthony% 22171b2bc0a7da432e6e1cc0480280402df213faa940anthony% CloneKernelInfo() creates a new clone of the given Kernel List so that its 22181b2bc0a7da432e6e1cc0480280402df213faa940anthony% can be modified without effecting the original. The cloned kernel should 22190ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony% be destroyed using DestoryKernelInfo() when no longer needed. 22207a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 2221e636559dfadfdb115cc93f223315052a1ee89238cristy% The format of the CloneKernelInfo method is: 22224fd27e21043be809d66c8202e779255e5b660d2danthony% 2223930be614b4595b97cd79ee864a394796740f76adanthony% KernelInfo *CloneKernelInfo(const KernelInfo *kernel) 22244fd27e21043be809d66c8202e779255e5b660d2danthony% 22254fd27e21043be809d66c8202e779255e5b660d2danthony% A description of each parameter follows: 22264fd27e21043be809d66c8202e779255e5b660d2danthony% 22274fd27e21043be809d66c8202e779255e5b660d2danthony% o kernel: the Morphology/Convolution kernel to be cloned 22284fd27e21043be809d66c8202e779255e5b660d2danthony% 22294fd27e21043be809d66c8202e779255e5b660d2danthony*/ 2230ef656913b0b30d713ae94c82c47693c9dc69c9f4cristyMagickExport KernelInfo *CloneKernelInfo(const KernelInfo *kernel) 22314fd27e21043be809d66c8202e779255e5b660d2danthony{ 2232bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 22334fd27e21043be809d66c8202e779255e5b660d2danthony i; 22344fd27e21043be809d66c8202e779255e5b660d2danthony 223519eb64195ef744f61293025952df1e5e6de66524cristy KernelInfo 22367a01dcf50ce12cb2a789bedff51e9345f022432eanthony *new_kernel; 22374fd27e21043be809d66c8202e779255e5b660d2danthony 22384fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel != (KernelInfo *) NULL); 22397a01dcf50ce12cb2a789bedff51e9345f022432eanthony new_kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel)); 22407a01dcf50ce12cb2a789bedff51e9345f022432eanthony if (new_kernel == (KernelInfo *) NULL) 22417a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(new_kernel); 22427a01dcf50ce12cb2a789bedff51e9345f022432eanthony *new_kernel=(*kernel); /* copy values in structure */ 22437a01dcf50ce12cb2a789bedff51e9345f022432eanthony 22447a01dcf50ce12cb2a789bedff51e9345f022432eanthony /* replace the values with a copy of the values */ 2245e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy new_kernel->values=(MagickRealType *) MagickAssumeAligned( 2246e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height*sizeof(*kernel->values))); 2247d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (new_kernel->values == (MagickRealType *) NULL) 22487a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(DestroyKernelInfo(new_kernel)); 2249bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++) 22507a01dcf50ce12cb2a789bedff51e9345f022432eanthony new_kernel->values[i]=kernel->values[i]; 22511b2bc0a7da432e6e1cc0480280402df213faa940anthony 22521b2bc0a7da432e6e1cc0480280402df213faa940anthony /* Also clone the next kernel in the kernel list */ 22531b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL ) { 22541b2bc0a7da432e6e1cc0480280402df213faa940anthony new_kernel->next = CloneKernelInfo(kernel->next); 22551b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( new_kernel->next == (KernelInfo *) NULL ) 22561b2bc0a7da432e6e1cc0480280402df213faa940anthony return(DestroyKernelInfo(new_kernel)); 22571b2bc0a7da432e6e1cc0480280402df213faa940anthony } 22581b2bc0a7da432e6e1cc0480280402df213faa940anthony 22597a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(new_kernel); 22604fd27e21043be809d66c8202e779255e5b660d2danthony} 22614fd27e21043be809d66c8202e779255e5b660d2danthony 22624fd27e21043be809d66c8202e779255e5b660d2danthony/* 22634fd27e21043be809d66c8202e779255e5b660d2danthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22644fd27e21043be809d66c8202e779255e5b660d2danthony% % 22654fd27e21043be809d66c8202e779255e5b660d2danthony% % 22664fd27e21043be809d66c8202e779255e5b660d2danthony% % 226783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% D e s t r o y K e r n e l I n f o % 2268602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2269602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2270602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2271602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2272602ab9b30b644a78a4057da93d838a77391ec0acanthony% 227383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% DestroyKernelInfo() frees the memory used by a Convolution/Morphology 227483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% kernel. 2275602ab9b30b644a78a4057da93d838a77391ec0acanthony% 227683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% The format of the DestroyKernelInfo method is: 2277602ab9b30b644a78a4057da93d838a77391ec0acanthony% 227883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% KernelInfo *DestroyKernelInfo(KernelInfo *kernel) 2279602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2280602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 2281602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2282602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel: the Morphology/Convolution kernel to be destroyed 2283602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2284602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 228583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthonyMagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel) 2286602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 22872be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy assert(kernel != (KernelInfo *) NULL); 22887a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( kernel->next != (KernelInfo *) NULL ) 22899f752c092332bf2c4e599ea49e9422c13f3fb11bcristy kernel->next=DestroyKernelInfo(kernel->next); 2290d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values=(MagickRealType *) RelinquishAlignedMemory(kernel->values); 22919f752c092332bf2c4e599ea49e9422c13f3fb11bcristy kernel=(KernelInfo *) RelinquishMagickMemory(kernel); 2292602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 2293602ab9b30b644a78a4057da93d838a77391ec0acanthony} 2294c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony 2295c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony/* 2296c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2297c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2298c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2299c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2300ce0fd95b65b90e1dc307600bb14b346b777e8137anthony+ E x p a n d M i r r o r K e r n e l I n f o % 23013c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 23023c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 23033c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 23043c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23053c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2306bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% ExpandMirrorKernelInfo() takes a single kernel, and expands it into a 2307bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% sequence of 90-degree rotated kernels but providing a reflected 180 2308bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% rotatation, before the -/+ 90-degree rotations. 2309bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2310bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% This special rotation order produces a better, more symetrical thinning of 2311bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% objects. 2312bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2313bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The format of the ExpandMirrorKernelInfo method is: 2314bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2315bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% void ExpandMirrorKernelInfo(KernelInfo *kernel) 2316bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2317bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% A description of each parameter follows: 2318bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2319bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% o kernel: the Morphology/Convolution kernel 2320bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2321bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% This function is only internel to this module, as it is not finalized, 2322bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% especially with regard to non-orthogonal angles, and rotation of larger 2323bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2D kernels. 2324bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony*/ 2325bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2326bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony#if 0 2327bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void FlopKernelInfo(KernelInfo *kernel) 2328bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony { /* Do a Flop by reversing each row. */ 2329bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony size_t 2330bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony y; 2331bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony register ssize_t 2332bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony x,r; 2333bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony register double 2334bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *k,t; 2335bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2336bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width) 2337bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--) 2338bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony t=k[x], k[x]=k[r], k[r]=t; 2339bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2340bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony kernel->x = kernel->width - kernel->x - 1; 2341bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony angle = fmod(angle+180.0, 360.0); 2342bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony } 2343bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony#endif 2344bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2345bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void ExpandMirrorKernelInfo(KernelInfo *kernel) 2346bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony{ 2347bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony KernelInfo 2348bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *clone, 2349bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *last; 2350bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2351bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = kernel; 2352bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2353bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2354bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 180); /* flip */ 2355bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2356bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = clone; 2357bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2358bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2359bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 90); /* transpose */ 2360bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2361bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = clone; 2362bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2363bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2364bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 180); /* flop */ 2365bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2366bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2367bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony return; 2368bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony} 2369bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2370bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony/* 2371bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2372bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2373bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2374bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2375ce0fd95b65b90e1dc307600bb14b346b777e8137anthony+ E x p a n d R o t a t e K e r n e l I n f o % 2376bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2377bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2378bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2379bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2380bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2381bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% ExpandRotateKernelInfo() takes a kernel list, and expands it by rotating 2382529482f4b494010a13338a74446c510712f670b3anthony% incrementally by the angle given, until the kernel repeats. 23833c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23843c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% WARNING: 45 degree rotations only works for 3x3 kernels. 23853c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% While 90 degree roatations only works for linear and square kernels 23863c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2387bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The format of the ExpandRotateKernelInfo method is: 23883c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2389bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% void ExpandRotateKernelInfo(KernelInfo *kernel, double angle) 23903c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23913c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% A description of each parameter follows: 23923c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23933c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% o kernel: the Morphology/Convolution kernel 23943c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23953c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% o angle: angle to rotate in degrees 23963c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23973c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% This function is only internel to this module, as it is not finalized, 23983c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% especially with regard to non-orthogonal angles, and rotation of larger 23993c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2D kernels. 24003c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony*/ 240147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 240247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony/* Internal Routine - Return true if two kernels are the same */ 240347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthonystatic MagickBooleanType SameKernelInfo(const KernelInfo *kernel1, 240447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony const KernelInfo *kernel2) 240547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony{ 2406bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 240747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony i; 24081d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 24091d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* check size and origin location */ 24101d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( kernel1->width != kernel2->width 24111d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->height != kernel2->height 24121d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->x != kernel2->x 24131d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->y != kernel2->y ) 241447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 24151d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 24161d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* check actual kernel values */ 241747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony for (i=0; i < (kernel1->width*kernel1->height); i++) { 2418f0a92fd8deb68d411304359906b12679b675691fglennrp /* Test for Nan equivalence */ 241947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( IsNan(kernel1->values[i]) && !IsNan(kernel2->values[i]) ) 242047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 242147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( IsNan(kernel2->values[i]) && !IsNan(kernel1->values[i]) ) 242247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 2423f0a92fd8deb68d411304359906b12679b675691fglennrp /* Test actual values are equivalent */ 2424b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(kernel1->values[i] - kernel2->values[i]) >= MagickEpsilon ) 242547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 242647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 24271d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 242847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickTrue; 242947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony} 243047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 2431bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void ExpandRotateKernelInfo(KernelInfo *kernel, const double angle) 24323c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony{ 24333c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony KernelInfo 243484d9b5596c0900609dea18795861e2b0936b21c6cristy *clone, 24353c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony *last; 2436a9a61ad96c5112acd968f97b689bd42ca392d70bcristy 24373c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony last = kernel; 243847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while(1) { 243984d9b5596c0900609dea18795861e2b0936b21c6cristy clone = CloneKernelInfo(last); 244084d9b5596c0900609dea18795861e2b0936b21c6cristy RotateKernelInfo(clone, angle); 244184d9b5596c0900609dea18795861e2b0936b21c6cristy if ( SameKernelInfo(kernel, clone) == MagickTrue ) 244247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 2443bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 244484d9b5596c0900609dea18795861e2b0936b21c6cristy last = clone; 24453c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 2446bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = DestroyKernelInfo(clone); /* kernel has repeated - junk the clone */ 244747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return; 24483c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony} 24493c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony 24503c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony/* 24513c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 24523c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 24533c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 24543c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 245546a369d839971ab627bdb31a93d8bd63e81b65a3anthony+ C a l c M e t a K e r n a l I n f o % 245646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 245746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 245846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 245946a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 246046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 246146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% CalcKernelMetaData() recalculate the KernelInfo meta-data of this kernel only, 2462dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp% using the kernel values. This should only ne used if it is not possible to 246346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% calculate that meta-data in some easier way. 246446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 246546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% It is important that the meta-data is correct before ScaleKernelInfo() is 246646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% used to perform kernel normalization. 246746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 246846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The format of the CalcKernelMetaData method is: 246946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 247046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% void CalcKernelMetaData(KernelInfo *kernel, const double scale ) 247146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 247246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% A description of each parameter follows: 247346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 247446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o kernel: the Morphology/Convolution kernel to modify 247546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 247646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% WARNING: Minimum and Maximum values are assumed to include zero, even if 247746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% zero is not part of the kernel (as in Gaussian Derived kernels). This 247846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% however is not true for flat-shaped morphological kernels. 247946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 248046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% WARNING: Only the specific kernel pointed to is modified, not a list of 248146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% multiple kernels. 248246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 248346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This is an internal function and not expected to be useful outside this 248446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% module. This could change however. 248546a369d839971ab627bdb31a93d8bd63e81b65a3anthony*/ 248646a369d839971ab627bdb31a93d8bd63e81b65a3anthonystatic void CalcKernelMetaData(KernelInfo *kernel) 248746a369d839971ab627bdb31a93d8bd63e81b65a3anthony{ 2488bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 248946a369d839971ab627bdb31a93d8bd63e81b65a3anthony i; 249046a369d839971ab627bdb31a93d8bd63e81b65a3anthony 249146a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->minimum = kernel->maximum = 0.0; 249246a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->negative_range = kernel->positive_range = 0.0; 249346a369d839971ab627bdb31a93d8bd63e81b65a3anthony for (i=0; i < (kernel->width*kernel->height); i++) 249446a369d839971ab627bdb31a93d8bd63e81b65a3anthony { 249546a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( fabs(kernel->values[i]) < MagickEpsilon ) 249646a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->values[i] = 0.0; 249746a369d839971ab627bdb31a93d8bd63e81b65a3anthony ( kernel->values[i] < 0) 249846a369d839971ab627bdb31a93d8bd63e81b65a3anthony ? ( kernel->negative_range += kernel->values[i] ) 249946a369d839971ab627bdb31a93d8bd63e81b65a3anthony : ( kernel->positive_range += kernel->values[i] ); 250046a369d839971ab627bdb31a93d8bd63e81b65a3anthony Minimize(kernel->minimum, kernel->values[i]); 250146a369d839971ab627bdb31a93d8bd63e81b65a3anthony Maximize(kernel->maximum, kernel->values[i]); 250246a369d839971ab627bdb31a93d8bd63e81b65a3anthony } 250346a369d839971ab627bdb31a93d8bd63e81b65a3anthony 250446a369d839971ab627bdb31a93d8bd63e81b65a3anthony return; 250546a369d839971ab627bdb31a93d8bd63e81b65a3anthony} 250646a369d839971ab627bdb31a93d8bd63e81b65a3anthony 250746a369d839971ab627bdb31a93d8bd63e81b65a3anthony/* 250846a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 250946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 251046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 251146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 25129eb4f74649b23c053b308ce1152dce51239450baanthony% M o r p h o l o g y A p p l y % 2513602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2514602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2515602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2516602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2517602ab9b30b644a78a4057da93d838a77391ec0acanthony% 25189eb4f74649b23c053b308ce1152dce51239450baanthony% MorphologyApply() applies a morphological method, multiple times using 251922de2722b682eb405b60ec6022a7546df994674eanthony% a list of multiple kernels. This is the method that should be called by 252022de2722b682eb405b60ec6022a7546df994674eanthony% other 'operators' that internally use morphology operations as part of 252122de2722b682eb405b60ec6022a7546df994674eanthony% their processing. 2522602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2523f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% It is basically equivalent to as MorphologyImage() (see below) but 2524e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% without any user controls. This allows internel programs to use this 2525dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp% function, to actually perform a specific task without possible interference 2526e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% by any API user supplied settings. 2527e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% 2528f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% It is MorphologyImage() task to extract any such user controls, and 2529e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% pass them to this function for processing. 25309eb4f74649b23c053b308ce1152dce51239450baanthony% 253122de2722b682eb405b60ec6022a7546df994674eanthony% More specifically all given kernels should already be scaled, normalised, 253222de2722b682eb405b60ec6022a7546df994674eanthony% and blended appropriatally before being parred to this routine. The 253322de2722b682eb405b60ec6022a7546df994674eanthony% appropriate bias, and compose (typically 'UndefinedComposeOp') given. 2534602ab9b30b644a78a4057da93d838a77391ec0acanthony% 253547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% The format of the MorphologyApply method is: 2536602ab9b30b644a78a4057da93d838a77391ec0acanthony% 25379eb4f74649b23c053b308ce1152dce51239450baanthony% Image *MorphologyApply(const Image *image,MorphologyMethod method, 2538f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% const ssize_t iterations,const KernelInfo *kernel, 2539f46d42620631d2581e0b6a56456e203e17c427c8anthony% const CompositeMethod compose,const double bias, 2540f46d42620631d2581e0b6a56456e203e17c427c8anthony% ExceptionInfo *exception) 2541602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2542602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 2543602ab9b30b644a78a4057da93d838a77391ec0acanthony% 25448d18850dee4bed193a64866a6d2353eeeb73e145anthony% o image: the source image 2545602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2546602ab9b30b644a78a4057da93d838a77391ec0acanthony% o method: the morphology method to be applied. 2547602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2548602ab9b30b644a78a4057da93d838a77391ec0acanthony% o iterations: apply the operation this many times (or no change). 2549602ab9b30b644a78a4057da93d838a77391ec0acanthony% A value of -1 means loop until no change found. 2550602ab9b30b644a78a4057da93d838a77391ec0acanthony% How this is applied may depend on the morphology method. 2551602ab9b30b644a78a4057da93d838a77391ec0acanthony% Typically this is a value of 1. 2552602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2553602ab9b30b644a78a4057da93d838a77391ec0acanthony% o channel: the channel type. 2554602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2555602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel: An array of double representing the morphology kernel. 2556602ab9b30b644a78a4057da93d838a77391ec0acanthony% 255747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% o compose: How to handle or merge multi-kernel results. 25588d18850dee4bed193a64866a6d2353eeeb73e145anthony% If 'UndefinedCompositeOp' use default for the Morphology method. 25598d18850dee4bed193a64866a6d2353eeeb73e145anthony% If 'NoCompositeOp' force image to be re-iterated by each kernel. 25608d18850dee4bed193a64866a6d2353eeeb73e145anthony% Otherwise merge the results using the compose method given. 256147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% 2562f46d42620631d2581e0b6a56456e203e17c427c8anthony% o bias: Convolution Output Bias. 2563f46d42620631d2581e0b6a56456e203e17c427c8anthony% 25649eb4f74649b23c053b308ce1152dce51239450baanthony% o exception: return any errors or warnings in this structure. 2565602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2566602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 2567602ab9b30b644a78a4057da93d838a77391ec0acanthony 25689eb4f74649b23c053b308ce1152dce51239450baanthony/* Apply a Morphology Primative to an image using the given kernel. 2569a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** Two pre-created images must be provided, and no image is created. 2570ea61f01656bb0f9074677452017cc559e54093faanthony** It returns the number of pixels that changed between the images 2571a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** for result convergence determination. 25729eb4f74649b23c053b308ce1152dce51239450baanthony*/ 2573f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristystatic ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image, 2574f46d42620631d2581e0b6a56456e203e17c427c8anthony const MorphologyMethod method,const KernelInfo *kernel,const double bias, 2575f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 2576602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 25772be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy#define MorphologyTag "Morphology/Image" 2578602ab9b30b644a78a4057da93d838a77391ec0acanthony 25795f959473f334e196c6bf39b740c12cb4963fceebcristy CacheView 25804c08aed51c5899665ade97263692328eea4af106cristy *image_view, 25814c08aed51c5899665ade97263692328eea4af106cristy *morphology_view; 25825f959473f334e196c6bf39b740c12cb4963fceebcristy 2583bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t 2584a8843c1f815ffad2568ec592d5b446cb1476aab5anthony y, offx, offy; 2585a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 2586a8843c1f815ffad2568ec592d5b446cb1476aab5anthony size_t 2587db60568e12574785101a4ae8d8da076227a0a889anthony virt_width, 2588602ab9b30b644a78a4057da93d838a77391ec0acanthony changed; 2589602ab9b30b644a78a4057da93d838a77391ec0acanthony 2590602ab9b30b644a78a4057da93d838a77391ec0acanthony MagickBooleanType 2591602ab9b30b644a78a4057da93d838a77391ec0acanthony status; 2592602ab9b30b644a78a4057da93d838a77391ec0acanthony 25935f959473f334e196c6bf39b740c12cb4963fceebcristy MagickOffsetType 25945f959473f334e196c6bf39b740c12cb4963fceebcristy progress; 2595602ab9b30b644a78a4057da93d838a77391ec0acanthony 2596e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(image != (Image *) NULL); 2597e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(image->signature == MagickSignature); 25984c08aed51c5899665ade97263692328eea4af106cristy assert(morphology_image != (Image *) NULL); 25994c08aed51c5899665ade97263692328eea4af106cristy assert(morphology_image->signature == MagickSignature); 2600e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(kernel != (KernelInfo *) NULL); 2601e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(kernel->signature == MagickSignature); 2602e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(exception != (ExceptionInfo *) NULL); 2603e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(exception->signature == MagickSignature); 2604e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony 2605602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickTrue; 2606602ab9b30b644a78a4057da93d838a77391ec0acanthony changed=0; 2607602ab9b30b644a78a4057da93d838a77391ec0acanthony progress=0; 2608602ab9b30b644a78a4057da93d838a77391ec0acanthony 260946ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy image_view=AcquireVirtualCacheView(image,exception); 261046ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy morphology_view=AcquireAuthenticCacheView(morphology_image,exception); 26116eac8d74fdd2c99429aba3b8404008909a44261fanthony virt_width=image->columns+kernel->width-1; 261229188a8682a98d4b7882cca434b170517555fc7danthony 2613cc6c836da2a53b6023b716e4973090a6714dc3b0anthony /* Some methods (including convolve) needs use a reflected kernel. 26149eb4f74649b23c053b308ce1152dce51239450baanthony * Adjust 'origin' offsets to loop though kernel as a reflection. 261529188a8682a98d4b7882cca434b170517555fc7danthony */ 2616c99304fe3c8d9c617da792b40b57c118bb1249afcristy offx = kernel->x; 2617c99304fe3c8d9c617da792b40b57c118bb1249afcristy offy = kernel->y; 261829188a8682a98d4b7882cca434b170517555fc7danthony switch(method) { 2619930be614b4595b97cd79ee864a394796740f76adanthony case ConvolveMorphology: 2620930be614b4595b97cd79ee864a394796740f76adanthony case DilateMorphology: 2621930be614b4595b97cd79ee864a394796740f76adanthony case DilateIntensityMorphology: 2622f34d9b2df49a407af764c79e07d587af0600983aanthony case IterativeDistanceMorphology: 26235ef8e94ff55717be2387d537bd49025780a1a558anthony /* kernel needs to used with reflection about origin */ 2624bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy offx = (ssize_t) kernel->width-offx-1; 2625bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy offy = (ssize_t) kernel->height-offy-1; 262629188a8682a98d4b7882cca434b170517555fc7danthony break; 26275ef8e94ff55717be2387d537bd49025780a1a558anthony case ErodeMorphology: 26285ef8e94ff55717be2387d537bd49025780a1a558anthony case ErodeIntensityMorphology: 26295ef8e94ff55717be2387d537bd49025780a1a558anthony case HitAndMissMorphology: 26305ef8e94ff55717be2387d537bd49025780a1a558anthony case ThinningMorphology: 26315ef8e94ff55717be2387d537bd49025780a1a558anthony case ThickenMorphology: 26323ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony /* kernel is used as is, without reflection */ 26335ef8e94ff55717be2387d537bd49025780a1a558anthony break; 2634930be614b4595b97cd79ee864a394796740f76adanthony default: 26359eb4f74649b23c053b308ce1152dce51239450baanthony assert("Not a Primitive Morphology Method" != (char *) NULL); 2636930be614b4595b97cd79ee864a394796740f76adanthony break; 263729188a8682a98d4b7882cca434b170517555fc7danthony } 263829188a8682a98d4b7882cca434b170517555fc7danthony 26398d18850dee4bed193a64866a6d2353eeeb73e145anthony if ( method == ConvolveMorphology && kernel->width == 1 ) 26408d18850dee4bed193a64866a6d2353eeeb73e145anthony { /* Special handling (for speed) of vertical (blur) kernels. 26418d18850dee4bed193a64866a6d2353eeeb73e145anthony ** This performs its handling in columns rather than in rows. 2642ea61f01656bb0f9074677452017cc559e54093faanthony ** This is only done for convolve as it is the only method that 26438d18850dee4bed193a64866a6d2353eeeb73e145anthony ** generates very large 1-D vertical kernels (such as a 'BlurKernel') 26448d18850dee4bed193a64866a6d2353eeeb73e145anthony ** 26458d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Timing tests (on single CPU laptop) 26468d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Using a vertical 1-d Blue with normal row-by-row (below) 26478d18850dee4bed193a64866a6d2353eeeb73e145anthony ** time convert logo: -morphology Convolve Blur:0x10+90 null: 26488d18850dee4bed193a64866a6d2353eeeb73e145anthony ** 0.807u 26498d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Using this column method 26508d18850dee4bed193a64866a6d2353eeeb73e145anthony ** time convert logo: -morphology Convolve Blur:0x10+90 null: 26518d18850dee4bed193a64866a6d2353eeeb73e145anthony ** 0.620u 26528d18850dee4bed193a64866a6d2353eeeb73e145anthony ** 26538d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Anthony Thyssen, 14 June 2010 26548d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 2655fd1175952254cf1ac848ddb441e483c5e33d517fcristy register ssize_t 2656fd1175952254cf1ac848ddb441e483c5e33d517fcristy x; 2657fd1175952254cf1ac848ddb441e483c5e33d517fcristy 26588d18850dee4bed193a64866a6d2353eeeb73e145anthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 2659ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp parallel for schedule(static,4) shared(progress,status) \ 26605e6b259130f9dbe0da4666f734937017babe573acristy magick_threads(image,morphology_image,image->columns,1) 26618d18850dee4bed193a64866a6d2353eeeb73e145anthony#endif 26628d18850dee4bed193a64866a6d2353eeeb73e145anthony for (x=0; x < (ssize_t) image->columns; x++) 26638d18850dee4bed193a64866a6d2353eeeb73e145anthony { 26644c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 26658d18850dee4bed193a64866a6d2353eeeb73e145anthony *restrict p; 26668d18850dee4bed193a64866a6d2353eeeb73e145anthony 26674c08aed51c5899665ade97263692328eea4af106cristy register Quantum 26688d18850dee4bed193a64866a6d2353eeeb73e145anthony *restrict q; 26698d18850dee4bed193a64866a6d2353eeeb73e145anthony 26708d18850dee4bed193a64866a6d2353eeeb73e145anthony register ssize_t 26718d18850dee4bed193a64866a6d2353eeeb73e145anthony y; 26728d18850dee4bed193a64866a6d2353eeeb73e145anthony 267355a91cddcdea3aa002893186a773e1704884a9dfcristy ssize_t 26748d18850dee4bed193a64866a6d2353eeeb73e145anthony r; 26758d18850dee4bed193a64866a6d2353eeeb73e145anthony 26768d18850dee4bed193a64866a6d2353eeeb73e145anthony if (status == MagickFalse) 26778d18850dee4bed193a64866a6d2353eeeb73e145anthony continue; 2678c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy p=GetCacheViewVirtualPixels(image_view,x,-offy,1,image->rows+ 2679c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy kernel->height-1,exception); 2680c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy q=GetCacheViewAuthenticPixels(morphology_view,x,0,1, 2681c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy morphology_image->rows,exception); 26824c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 26838d18850dee4bed193a64866a6d2353eeeb73e145anthony { 26848d18850dee4bed193a64866a6d2353eeeb73e145anthony status=MagickFalse; 26858d18850dee4bed193a64866a6d2353eeeb73e145anthony continue; 26868d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2687a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* offset to origin in 'p'. while 'q' points to it directly */ 2688a8843c1f815ffad2568ec592d5b446cb1476aab5anthony r = offy; 26898d18850dee4bed193a64866a6d2353eeeb73e145anthony 26908d18850dee4bed193a64866a6d2353eeeb73e145anthony for (y=0; y < (ssize_t) image->rows; y++) 26918d18850dee4bed193a64866a6d2353eeeb73e145anthony { 269270b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy PixelInfo 269370b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy result; 269470b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy 2695d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register const MagickRealType 26968d18850dee4bed193a64866a6d2353eeeb73e145anthony *restrict k; 26978d18850dee4bed193a64866a6d2353eeeb73e145anthony 26984c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 26998d18850dee4bed193a64866a6d2353eeeb73e145anthony *restrict k_pixels; 27008d18850dee4bed193a64866a6d2353eeeb73e145anthony 2701d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register ssize_t 2702d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy v; 2703d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 27048d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Copy input image to the output image for unused channels 27058d18850dee4bed193a64866a6d2353eeeb73e145anthony * This removes need for 'cloning' a new image every iteration 27068d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 27074c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image,GetPixelRed(image,p+r* 2708ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 27094c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image,GetPixelGreen(image,p+r* 2710ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 27114c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image,GetPixelBlue(image,p+r* 2712ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 27138d18850dee4bed193a64866a6d2353eeeb73e145anthony if (image->colorspace == CMYKColorspace) 27144c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image,GetPixelBlack(image,p+r* 2715ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 27168d18850dee4bed193a64866a6d2353eeeb73e145anthony 27178d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Set the bias of the weighted average output */ 271853f576d128f0bb744a82e7f9c0d8f05b2923972canthony result.red = 271953f576d128f0bb744a82e7f9c0d8f05b2923972canthony result.green = 272053f576d128f0bb744a82e7f9c0d8f05b2923972canthony result.blue = 27214c08aed51c5899665ade97263692328eea4af106cristy result.alpha = 272253f576d128f0bb744a82e7f9c0d8f05b2923972canthony result.black = bias; 27238d18850dee4bed193a64866a6d2353eeeb73e145anthony 27248d18850dee4bed193a64866a6d2353eeeb73e145anthony 27258d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Weighted Average of pixels using reflected kernel 27268d18850dee4bed193a64866a6d2353eeeb73e145anthony ** 27278d18850dee4bed193a64866a6d2353eeeb73e145anthony ** NOTE for correct working of this operation for asymetrical 27288d18850dee4bed193a64866a6d2353eeeb73e145anthony ** kernels, the kernel needs to be applied in its reflected form. 27298d18850dee4bed193a64866a6d2353eeeb73e145anthony ** That is its values needs to be reversed. 27308d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 27318d18850dee4bed193a64866a6d2353eeeb73e145anthony k = &kernel->values[ kernel->height-1 ]; 27328d18850dee4bed193a64866a6d2353eeeb73e145anthony k_pixels = p; 27330ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony if ( (image->channel_mask != DefaultChannels) || 27348a46d827a124555f0c48fb2368ec1bba8e079ab6cristy (image->alpha_trait != BlendPixelTrait) ) 27358d18850dee4bed193a64866a6d2353eeeb73e145anthony { /* No 'Sync' involved. 27360ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony ** Convolution is just a simple greyscale channel operation 27378d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 27388d18850dee4bed193a64866a6d2353eeeb73e145anthony for (v=0; v < (ssize_t) kernel->height; v++) { 27398d18850dee4bed193a64866a6d2353eeeb73e145anthony if ( IsNan(*k) ) continue; 27404c08aed51c5899665ade97263692328eea4af106cristy result.red += (*k)*GetPixelRed(image,k_pixels); 27414c08aed51c5899665ade97263692328eea4af106cristy result.green += (*k)*GetPixelGreen(image,k_pixels); 27424c08aed51c5899665ade97263692328eea4af106cristy result.blue += (*k)*GetPixelBlue(image,k_pixels); 27434c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 27444c08aed51c5899665ade97263692328eea4af106cristy result.black+=(*k)*GetPixelBlack(image,k_pixels); 27454c08aed51c5899665ade97263692328eea4af106cristy result.alpha += (*k)*GetPixelAlpha(image,k_pixels); 27468d18850dee4bed193a64866a6d2353eeeb73e145anthony k--; 2747ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+=GetPixelChannels(image); 27488d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2749ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 27504c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image,ClampToQuantum(result.red),q); 2751ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 27524c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image,ClampToQuantum(result.green),q); 2753ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 27544c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image,ClampToQuantum(result.blue),q); 2755ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 27564c08aed51c5899665ade97263692328eea4af106cristy (image->colorspace == CMYKColorspace)) 27574c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image,ClampToQuantum(result.black),q); 2758ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 27598a46d827a124555f0c48fb2368ec1bba8e079ab6cristy (image->alpha_trait == BlendPixelTrait)) 27604c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q); 27618d18850dee4bed193a64866a6d2353eeeb73e145anthony } 27628d18850dee4bed193a64866a6d2353eeeb73e145anthony else 27638d18850dee4bed193a64866a6d2353eeeb73e145anthony { /* Channel 'Sync' Flag, and Alpha Channel enabled. 27648d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Weight the color channels with Alpha Channel so that 27658d18850dee4bed193a64866a6d2353eeeb73e145anthony ** transparent pixels are not part of the results. 27668d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 2767a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy double 276842052799a46abaf2b4fc90fe390cdd856038b4f7anthony alpha, /* alpha weighting for colors : alpha */ 276942052799a46abaf2b4fc90fe390cdd856038b4f7anthony gamma; /* divisor, sum of color alpha weighting */ 277042052799a46abaf2b4fc90fe390cdd856038b4f7anthony size_t 277142052799a46abaf2b4fc90fe390cdd856038b4f7anthony count; /* alpha valus collected, number kernel values */ 27728d18850dee4bed193a64866a6d2353eeeb73e145anthony 277342052799a46abaf2b4fc90fe390cdd856038b4f7anthony count=0; 27748d18850dee4bed193a64866a6d2353eeeb73e145anthony gamma=0.0; 27758d18850dee4bed193a64866a6d2353eeeb73e145anthony for (v=0; v < (ssize_t) kernel->height; v++) { 27768d18850dee4bed193a64866a6d2353eeeb73e145anthony if ( IsNan(*k) ) continue; 27770ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony alpha=QuantumScale*GetPixelAlpha(image,k_pixels); 27780ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony gamma += alpha; /* normalize alpha weights only */ 277942052799a46abaf2b4fc90fe390cdd856038b4f7anthony count++; /* number of alpha values collected */ 27800ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony alpha*=(*k); /* include kernel weighting now */ 27814c08aed51c5899665ade97263692328eea4af106cristy result.red += alpha*GetPixelRed(image,k_pixels); 27824c08aed51c5899665ade97263692328eea4af106cristy result.green += alpha*GetPixelGreen(image,k_pixels); 27834c08aed51c5899665ade97263692328eea4af106cristy result.blue += alpha*GetPixelBlue(image,k_pixels); 27844c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 27854c08aed51c5899665ade97263692328eea4af106cristy result.black += alpha*GetPixelBlack(image,k_pixels); 278642052799a46abaf2b4fc90fe390cdd856038b4f7anthony result.alpha += (*k)*GetPixelAlpha(image,k_pixels); 27878d18850dee4bed193a64866a6d2353eeeb73e145anthony k--; 2788ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+=GetPixelChannels(image); 27898d18850dee4bed193a64866a6d2353eeeb73e145anthony } 27908d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Sync'ed channels, all channels are modified */ 27919b52834318bcfea7da9c8b4ec8eb4682f009234dcristy gamma=(double)count/(fabs((double) gamma) < MagickEpsilon ? MagickEpsilon : gamma); 27920ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony SetPixelRed(morphology_image,ClampToQuantum(gamma*result.red),q); 27930ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony SetPixelGreen(morphology_image,ClampToQuantum(gamma*result.green),q); 27940ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony SetPixelBlue(morphology_image,ClampToQuantum(gamma*result.blue),q); 27958d18850dee4bed193a64866a6d2353eeeb73e145anthony if (image->colorspace == CMYKColorspace) 27960ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony SetPixelBlack(morphology_image,ClampToQuantum(gamma*result.black),q); 27970ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q); 27988d18850dee4bed193a64866a6d2353eeeb73e145anthony } 27998d18850dee4bed193a64866a6d2353eeeb73e145anthony 28008d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Count up changed pixels */ 2801ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(morphology_image,q)) 2802ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(morphology_image,q)) 2803ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(morphology_image,q)) 2804ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(morphology_image,q)) 28054c08aed51c5899665ade97263692328eea4af106cristy || ((image->colorspace == CMYKColorspace) && 2806ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(morphology_image,q)))) 28078d18850dee4bed193a64866a6d2353eeeb73e145anthony changed++; /* The pixel was changed in some way! */ 2808ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p+=GetPixelChannels(image); 2809ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(morphology_image); 28108d18850dee4bed193a64866a6d2353eeeb73e145anthony } /* y */ 28114c08aed51c5899665ade97263692328eea4af106cristy if ( SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 28128d18850dee4bed193a64866a6d2353eeeb73e145anthony status=MagickFalse; 28138d18850dee4bed193a64866a6d2353eeeb73e145anthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 28148d18850dee4bed193a64866a6d2353eeeb73e145anthony { 28158d18850dee4bed193a64866a6d2353eeeb73e145anthony MagickBooleanType 28168d18850dee4bed193a64866a6d2353eeeb73e145anthony proceed; 28178d18850dee4bed193a64866a6d2353eeeb73e145anthony 28188d18850dee4bed193a64866a6d2353eeeb73e145anthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 2819ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp critical (MagickCore_MorphologyImage) 28208d18850dee4bed193a64866a6d2353eeeb73e145anthony#endif 28218d18850dee4bed193a64866a6d2353eeeb73e145anthony proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows); 28228d18850dee4bed193a64866a6d2353eeeb73e145anthony if (proceed == MagickFalse) 28238d18850dee4bed193a64866a6d2353eeeb73e145anthony status=MagickFalse; 28248d18850dee4bed193a64866a6d2353eeeb73e145anthony } 28258d18850dee4bed193a64866a6d2353eeeb73e145anthony } /* x */ 28264c08aed51c5899665ade97263692328eea4af106cristy morphology_image->type=image->type; 28274c08aed51c5899665ade97263692328eea4af106cristy morphology_view=DestroyCacheView(morphology_view); 28284c08aed51c5899665ade97263692328eea4af106cristy image_view=DestroyCacheView(image_view); 2829aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy return(status ? (ssize_t) changed : 0); 28308d18850dee4bed193a64866a6d2353eeeb73e145anthony } 28318d18850dee4bed193a64866a6d2353eeeb73e145anthony 28328d18850dee4bed193a64866a6d2353eeeb73e145anthony /* 28338d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Normal handling of horizontal or rectangular kernels (row by row) 28348d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 2835602ab9b30b644a78a4057da93d838a77391ec0acanthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 2836ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp parallel for schedule(static,4) shared(progress,status) \ 28375e6b259130f9dbe0da4666f734937017babe573acristy magick_threads(image,morphology_image,image->rows,1) 2838602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 2839bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (y=0; y < (ssize_t) image->rows; y++) 2840602ab9b30b644a78a4057da93d838a77391ec0acanthony { 28414c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 2842602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict p; 2843602ab9b30b644a78a4057da93d838a77391ec0acanthony 28444c08aed51c5899665ade97263692328eea4af106cristy register Quantum 2845602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict q; 2846602ab9b30b644a78a4057da93d838a77391ec0acanthony 2847bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 2848602ab9b30b644a78a4057da93d838a77391ec0acanthony x; 2849602ab9b30b644a78a4057da93d838a77391ec0acanthony 2850bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 2851602ab9b30b644a78a4057da93d838a77391ec0acanthony r; 2852602ab9b30b644a78a4057da93d838a77391ec0acanthony 2853602ab9b30b644a78a4057da93d838a77391ec0acanthony if (status == MagickFalse) 2854602ab9b30b644a78a4057da93d838a77391ec0acanthony continue; 28554c08aed51c5899665ade97263692328eea4af106cristy p=GetCacheViewVirtualPixels(image_view, -offx, y-offy, virt_width, 2856c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy kernel->height, exception); 2857c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy q=GetCacheViewAuthenticPixels(morphology_view,0,y, 2858c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy morphology_image->columns,1,exception); 28594c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 2860602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2861602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 2862602ab9b30b644a78a4057da93d838a77391ec0acanthony continue; 2863602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2864a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* offset to origin in 'p'. while 'q' points to it directly */ 2865db60568e12574785101a4ae8d8da076227a0a889anthony r = virt_width*offy + offx; 286629188a8682a98d4b7882cca434b170517555fc7danthony 2867bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (x=0; x < (ssize_t) image->columns; x++) 2868602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2869d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy PixelInfo 2870d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy result, 2871d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy min, 2872d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy max; 2873602ab9b30b644a78a4057da93d838a77391ec0acanthony 2874d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register const MagickRealType 2875602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict k; 2876602ab9b30b644a78a4057da93d838a77391ec0acanthony 28774c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 2878602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict k_pixels; 2879602ab9b30b644a78a4057da93d838a77391ec0acanthony 2880d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register ssize_t 2881d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy u; 2882d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 2883d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy ssize_t 2884d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy v; 2885602ab9b30b644a78a4057da93d838a77391ec0acanthony 2886c406ea496196b962e4bc865ed8f6a4491241c6edanthony /* Copy input image to the output image for unused channels 288783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony * This removes need for 'cloning' a new image every iteration 288829188a8682a98d4b7882cca434b170517555fc7danthony */ 28894c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image,GetPixelRed(image,p+r* 2890ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 28914c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image,GetPixelGreen(image,p+r* 2892ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 28934c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image,GetPixelBlue(image,p+r* 2894ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 2895602ab9b30b644a78a4057da93d838a77391ec0acanthony if (image->colorspace == CMYKColorspace) 28964c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image,GetPixelBlack(image,p+r* 2897ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 2898602ab9b30b644a78a4057da93d838a77391ec0acanthony 28995ef8e94ff55717be2387d537bd49025780a1a558anthony /* Defaults */ 29005ef8e94ff55717be2387d537bd49025780a1a558anthony min.red = 29015ef8e94ff55717be2387d537bd49025780a1a558anthony min.green = 29025ef8e94ff55717be2387d537bd49025780a1a558anthony min.blue = 29034c08aed51c5899665ade97263692328eea4af106cristy min.alpha = 2904a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy min.black = (double) QuantumRange; 29055ef8e94ff55717be2387d537bd49025780a1a558anthony max.red = 29065ef8e94ff55717be2387d537bd49025780a1a558anthony max.green = 29075ef8e94ff55717be2387d537bd49025780a1a558anthony max.blue = 29084c08aed51c5899665ade97263692328eea4af106cristy max.alpha = 2909a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy max.black = (double) 0; 29109eb4f74649b23c053b308ce1152dce51239450baanthony /* default result is the original pixel value */ 2911a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy result.red = (double) GetPixelRed(image,p+r*GetPixelChannels(image)); 2912a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy result.green = (double) GetPixelGreen(image,p+r*GetPixelChannels(image)); 2913a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy result.blue = (double) GetPixelBlue(image,p+r*GetPixelChannels(image)); 29144c08aed51c5899665ade97263692328eea4af106cristy result.black = 0.0; 29154c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 2916a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy result.black = (double) GetPixelBlack(image,p+r*GetPixelChannels(image)); 2917a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy result.alpha=(double) GetPixelAlpha(image,p+r*GetPixelChannels(image)); 29185ef8e94ff55717be2387d537bd49025780a1a558anthony 2919602ab9b30b644a78a4057da93d838a77391ec0acanthony switch (method) { 2920602ab9b30b644a78a4057da93d838a77391ec0acanthony case ConvolveMorphology: 29218d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Set the bias of the weighted average output */ 29229eb4f74649b23c053b308ce1152dce51239450baanthony result.red = 29239eb4f74649b23c053b308ce1152dce51239450baanthony result.green = 29249eb4f74649b23c053b308ce1152dce51239450baanthony result.blue = 29254c08aed51c5899665ade97263692328eea4af106cristy result.alpha = 2926f46d42620631d2581e0b6a56456e203e17c427c8anthony result.black = bias; 2927930be614b4595b97cd79ee864a394796740f76adanthony break; 29284fd27e21043be809d66c8202e779255e5b660d2danthony case DilateIntensityMorphology: 29294fd27e21043be809d66c8202e779255e5b660d2danthony case ErodeIntensityMorphology: 29309eb4f74649b23c053b308ce1152dce51239450baanthony /* use a boolean flag indicating when first match found */ 29319eb4f74649b23c053b308ce1152dce51239450baanthony result.red = 0.0; /* result is not used otherwise */ 29324fd27e21043be809d66c8202e779255e5b660d2danthony break; 2933602ab9b30b644a78a4057da93d838a77391ec0acanthony default: 2934602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2935602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2936602ab9b30b644a78a4057da93d838a77391ec0acanthony 2937602ab9b30b644a78a4057da93d838a77391ec0acanthony switch ( method ) { 2938602ab9b30b644a78a4057da93d838a77391ec0acanthony case ConvolveMorphology: 2939930be614b4595b97cd79ee864a394796740f76adanthony /* Weighted Average of pixels using reflected kernel 2940930be614b4595b97cd79ee864a394796740f76adanthony ** 2941930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE for correct working of this operation for asymetrical 2942930be614b4595b97cd79ee864a394796740f76adanthony ** kernels, the kernel needs to be applied in its reflected form. 2943930be614b4595b97cd79ee864a394796740f76adanthony ** That is its values needs to be reversed. 2944930be614b4595b97cd79ee864a394796740f76adanthony ** 2945930be614b4595b97cd79ee864a394796740f76adanthony ** Correlation is actually the same as this but without reflecting 2946930be614b4595b97cd79ee864a394796740f76adanthony ** the kernel, and thus 'lower-level' that Convolution. However 2947930be614b4595b97cd79ee864a394796740f76adanthony ** as Convolution is the more common method used, and it does not 2948930be614b4595b97cd79ee864a394796740f76adanthony ** really cost us much in terms of processing to use a reflected 29495ef8e94ff55717be2387d537bd49025780a1a558anthony ** kernel, so it is Convolution that is implemented. 2950930be614b4595b97cd79ee864a394796740f76adanthony ** 2951930be614b4595b97cd79ee864a394796740f76adanthony ** Correlation will have its kernel reflected before calling 2952930be614b4595b97cd79ee864a394796740f76adanthony ** this function to do a Convolve. 2953930be614b4595b97cd79ee864a394796740f76adanthony ** 2954930be614b4595b97cd79ee864a394796740f76adanthony ** For more details of Correlation vs Convolution see 2955930be614b4595b97cd79ee864a394796740f76adanthony ** http://www.cs.umd.edu/~djacobs/CMSC426/Convolution.pdf 2956930be614b4595b97cd79ee864a394796740f76adanthony */ 29578d18850dee4bed193a64866a6d2353eeeb73e145anthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 29588d18850dee4bed193a64866a6d2353eeeb73e145anthony k_pixels = p; 29595f95f4f77efc46ff53593d750491c8f60698c983cristy if ( (image->channel_mask != DefaultChannels) || 29608a46d827a124555f0c48fb2368ec1bba8e079ab6cristy (image->alpha_trait != BlendPixelTrait) ) 29618d18850dee4bed193a64866a6d2353eeeb73e145anthony { /* No 'Sync' involved. 29628d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Convolution is simple greyscale channel operation 29638d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 29648d18850dee4bed193a64866a6d2353eeeb73e145anthony for (v=0; v < (ssize_t) kernel->height; v++) { 29658d18850dee4bed193a64866a6d2353eeeb73e145anthony for (u=0; u < (ssize_t) kernel->width; u++, k--) { 29668d18850dee4bed193a64866a6d2353eeeb73e145anthony if ( IsNan(*k) ) continue; 29674c08aed51c5899665ade97263692328eea4af106cristy result.red += (*k)* 2968ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image)); 29694c08aed51c5899665ade97263692328eea4af106cristy result.green += (*k)* 2970ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)); 29714c08aed51c5899665ade97263692328eea4af106cristy result.blue += (*k)* 2972ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)); 29734c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 29744c08aed51c5899665ade97263692328eea4af106cristy result.black += (*k)* 2975ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)); 29764c08aed51c5899665ade97263692328eea4af106cristy result.alpha += (*k)* 2977ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)); 29788d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2979ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 29808d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2981ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 29822b9582a27910c7baaeb04b7e969638328fa70095cristy SetPixelRed(morphology_image,ClampToQuantum(result.red), 29832b9582a27910c7baaeb04b7e969638328fa70095cristy q); 2984ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 29852b9582a27910c7baaeb04b7e969638328fa70095cristy SetPixelGreen(morphology_image,ClampToQuantum(result.green), 29862b9582a27910c7baaeb04b7e969638328fa70095cristy q); 2987ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 29882b9582a27910c7baaeb04b7e969638328fa70095cristy SetPixelBlue(morphology_image,ClampToQuantum(result.blue), 29892b9582a27910c7baaeb04b7e969638328fa70095cristy q); 2990ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 29914c08aed51c5899665ade97263692328eea4af106cristy (image->colorspace == CMYKColorspace)) 29922b9582a27910c7baaeb04b7e969638328fa70095cristy SetPixelBlack(morphology_image,ClampToQuantum(result.black), 29932b9582a27910c7baaeb04b7e969638328fa70095cristy q); 2994ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 29958a46d827a124555f0c48fb2368ec1bba8e079ab6cristy (image->alpha_trait == BlendPixelTrait)) 29962b9582a27910c7baaeb04b7e969638328fa70095cristy SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha), 29972b9582a27910c7baaeb04b7e969638328fa70095cristy q); 29988d18850dee4bed193a64866a6d2353eeeb73e145anthony } 29998d18850dee4bed193a64866a6d2353eeeb73e145anthony else 30008d18850dee4bed193a64866a6d2353eeeb73e145anthony { /* Channel 'Sync' Flag, and Alpha Channel enabled. 30015ef8e94ff55717be2387d537bd49025780a1a558anthony ** Weight the color channels with Alpha Channel so that 30025ef8e94ff55717be2387d537bd49025780a1a558anthony ** transparent pixels are not part of the results. 30035ef8e94ff55717be2387d537bd49025780a1a558anthony */ 3004a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy double 300542052799a46abaf2b4fc90fe390cdd856038b4f7anthony alpha, /* alpha weighting for colors : alpha */ 300642052799a46abaf2b4fc90fe390cdd856038b4f7anthony gamma; /* divisor, sum of color alpha weighting */ 300742052799a46abaf2b4fc90fe390cdd856038b4f7anthony size_t 300842052799a46abaf2b4fc90fe390cdd856038b4f7anthony count; /* alpha valus collected, number kernel values */ 3009602ab9b30b644a78a4057da93d838a77391ec0acanthony 301042052799a46abaf2b4fc90fe390cdd856038b4f7anthony count=0; 3011602ab9b30b644a78a4057da93d838a77391ec0acanthony gamma=0.0; 3012bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3013bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3014602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( IsNan(*k) ) continue; 30150ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony alpha=QuantumScale*GetPixelAlpha(image, 30160ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony k_pixels+u*GetPixelChannels(image)); 301742052799a46abaf2b4fc90fe390cdd856038b4f7anthony gamma += alpha; /* normalize alpha weights only */ 301842052799a46abaf2b4fc90fe390cdd856038b4f7anthony count++; /* number of alpha values collected */ 301942052799a46abaf2b4fc90fe390cdd856038b4f7anthony alpha=alpha*(*k); /* include kernel weighting now */ 30204c08aed51c5899665ade97263692328eea4af106cristy result.red += alpha* 3021ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image)); 30224c08aed51c5899665ade97263692328eea4af106cristy result.green += alpha* 3023ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)); 30244c08aed51c5899665ade97263692328eea4af106cristy result.blue += alpha* 3025ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)); 30264c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 302742052799a46abaf2b4fc90fe390cdd856038b4f7anthony result.black += alpha* 3028ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)); 302942052799a46abaf2b4fc90fe390cdd856038b4f7anthony result.alpha += (*k)* 3030ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)); 3031602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3032ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3033602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3034c406ea496196b962e4bc865ed8f6a4491241c6edanthony /* Sync'ed channels, all channels are modified */ 30359b52834318bcfea7da9c8b4ec8eb4682f009234dcristy gamma=(double)count/(fabs((double) gamma) < MagickEpsilon ? MagickEpsilon : gamma); 30364c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image, 30374c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.red),q); 30384c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image, 30394c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.green),q); 30404c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image, 30414c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.blue),q); 3042c406ea496196b962e4bc865ed8f6a4491241c6edanthony if (image->colorspace == CMYKColorspace) 30434c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image, 30444c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.black),q); 30454c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q); 3046602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3047602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3048602ab9b30b644a78a4057da93d838a77391ec0acanthony 30494fd27e21043be809d66c8202e779255e5b660d2danthony case ErodeMorphology: 30505ef8e94ff55717be2387d537bd49025780a1a558anthony /* Minimum Value within kernel neighbourhood 3051930be614b4595b97cd79ee864a394796740f76adanthony ** 3052930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE that the kernel is not reflected for this operation! 3053930be614b4595b97cd79ee864a394796740f76adanthony ** 3054930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE: in normal Greyscale Morphology, the kernel value should 3055930be614b4595b97cd79ee864a394796740f76adanthony ** be added to the real value, this is currently not done, due to 3056930be614b4595b97cd79ee864a394796740f76adanthony ** the nature of the boolean kernels being used. 3057930be614b4595b97cd79ee864a394796740f76adanthony */ 30584fd27e21043be809d66c8202e779255e5b660d2danthony k = kernel->values; 3059602ab9b30b644a78a4057da93d838a77391ec0acanthony k_pixels = p; 3060bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3061bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k++) { 3062602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( IsNan(*k) || (*k) < 0.5 ) continue; 30634c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.red, (double) 3064ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 3065f34d9b2df49a407af764c79e07d587af0600983aanthony Minimize(min.green, (double) 3066ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 30674c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.blue, (double) 3068ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 3069f34d9b2df49a407af764c79e07d587af0600983aanthony Minimize(min.alpha, (double) 3070f34d9b2df49a407af764c79e07d587af0600983aanthony GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 30714c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 3072f34d9b2df49a407af764c79e07d587af0600983aanthony Minimize(min.black, (double) 3073ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 3074602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3075ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3076602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3077602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3078602ab9b30b644a78a4057da93d838a77391ec0acanthony 30794fd27e21043be809d66c8202e779255e5b660d2danthony case DilateMorphology: 30805ef8e94ff55717be2387d537bd49025780a1a558anthony /* Maximum Value within kernel neighbourhood 3081930be614b4595b97cd79ee864a394796740f76adanthony ** 3082930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE for correct working of this operation for asymetrical 3083930be614b4595b97cd79ee864a394796740f76adanthony ** kernels, the kernel needs to be applied in its reflected form. 3084930be614b4595b97cd79ee864a394796740f76adanthony ** That is its values needs to be reversed. 3085930be614b4595b97cd79ee864a394796740f76adanthony ** 3086930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE: in normal Greyscale Morphology, the kernel value should 3087930be614b4595b97cd79ee864a394796740f76adanthony ** be added to the real value, this is currently not done, due to 3088930be614b4595b97cd79ee864a394796740f76adanthony ** the nature of the boolean kernels being used. 3089930be614b4595b97cd79ee864a394796740f76adanthony ** 3090930be614b4595b97cd79ee864a394796740f76adanthony */ 30914fd27e21043be809d66c8202e779255e5b660d2danthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 3092602ab9b30b644a78a4057da93d838a77391ec0acanthony k_pixels = p; 3093bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3094bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3095602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( IsNan(*k) || (*k) < 0.5 ) continue; 30964c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.red, (double) 3097ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 3098f34d9b2df49a407af764c79e07d587af0600983aanthony Maximize(max.green, (double) 3099ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 3100f34d9b2df49a407af764c79e07d587af0600983aanthony Maximize(max.blue, (double) 3101ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 3102f34d9b2df49a407af764c79e07d587af0600983aanthony Maximize(max.alpha, (double) 3103f34d9b2df49a407af764c79e07d587af0600983aanthony GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 31044c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 31054c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.black, (double) 3106ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 3107602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3108ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3109602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3110602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3111602ab9b30b644a78a4057da93d838a77391ec0acanthony 31125ef8e94ff55717be2387d537bd49025780a1a558anthony case HitAndMissMorphology: 31135ef8e94ff55717be2387d537bd49025780a1a558anthony case ThinningMorphology: 31145ef8e94ff55717be2387d537bd49025780a1a558anthony case ThickenMorphology: 31155ef8e94ff55717be2387d537bd49025780a1a558anthony /* Minimum of Foreground Pixel minus Maxumum of Background Pixels 31165ef8e94ff55717be2387d537bd49025780a1a558anthony ** 31175ef8e94ff55717be2387d537bd49025780a1a558anthony ** NOTE that the kernel is not reflected for this operation, 31185ef8e94ff55717be2387d537bd49025780a1a558anthony ** and consists of both foreground and background pixel 31195ef8e94ff55717be2387d537bd49025780a1a558anthony ** neighbourhoods, 0.0 for background, and 1.0 for foreground 31205ef8e94ff55717be2387d537bd49025780a1a558anthony ** with either Nan or 0.5 values for don't care. 31215ef8e94ff55717be2387d537bd49025780a1a558anthony ** 31224c827ef1be3d42450ff45cedad271e6568be0ea9anthony ** Note that this will never produce a meaningless negative 31234c827ef1be3d42450ff45cedad271e6568be0ea9anthony ** result. Such results can cause Thinning/Thicken to not work 31244c827ef1be3d42450ff45cedad271e6568be0ea9anthony ** correctly when used against a greyscale image. 31255ef8e94ff55717be2387d537bd49025780a1a558anthony */ 31265ef8e94ff55717be2387d537bd49025780a1a558anthony k = kernel->values; 31275ef8e94ff55717be2387d537bd49025780a1a558anthony k_pixels = p; 3128bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3129bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k++) { 31305ef8e94ff55717be2387d537bd49025780a1a558anthony if ( IsNan(*k) ) continue; 31315ef8e94ff55717be2387d537bd49025780a1a558anthony if ( (*k) > 0.7 ) 31325ef8e94ff55717be2387d537bd49025780a1a558anthony { /* minimim of foreground pixels */ 31334c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.red, (double) 3134ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 31354c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.green, (double) 3136ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 31374c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.blue, (double) 3138ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 3139f34d9b2df49a407af764c79e07d587af0600983aanthony Minimize(min.alpha,(double) 3140f34d9b2df49a407af764c79e07d587af0600983aanthony GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 31415ef8e94ff55717be2387d537bd49025780a1a558anthony if ( image->colorspace == CMYKColorspace) 31424c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.black,(double) 3143ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 31445ef8e94ff55717be2387d537bd49025780a1a558anthony } 31455ef8e94ff55717be2387d537bd49025780a1a558anthony else if ( (*k) < 0.3 ) 31465ef8e94ff55717be2387d537bd49025780a1a558anthony { /* maximum of background pixels */ 31474c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.red, (double) 3148ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 31494c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.green, (double) 3150ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 31514c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.blue, (double) 3152ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 3153f34d9b2df49a407af764c79e07d587af0600983aanthony Maximize(max.alpha,(double) 3154f34d9b2df49a407af764c79e07d587af0600983aanthony GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 31554c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 31564c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.black, (double) 3157ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 31585ef8e94ff55717be2387d537bd49025780a1a558anthony } 31595ef8e94ff55717be2387d537bd49025780a1a558anthony } 3160ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 31615ef8e94ff55717be2387d537bd49025780a1a558anthony } 31624c827ef1be3d42450ff45cedad271e6568be0ea9anthony /* Pattern Match if difference is positive */ 31635ef8e94ff55717be2387d537bd49025780a1a558anthony min.red -= max.red; Maximize( min.red, 0.0 ); 31645ef8e94ff55717be2387d537bd49025780a1a558anthony min.green -= max.green; Maximize( min.green, 0.0 ); 31655ef8e94ff55717be2387d537bd49025780a1a558anthony min.blue -= max.blue; Maximize( min.blue, 0.0 ); 31664c08aed51c5899665ade97263692328eea4af106cristy min.black -= max.black; Maximize( min.black, 0.0 ); 316770b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy min.alpha -= max.alpha; Maximize( min.alpha, 0.0 ); 31685ef8e94ff55717be2387d537bd49025780a1a558anthony break; 31695ef8e94ff55717be2387d537bd49025780a1a558anthony 31704fd27e21043be809d66c8202e779255e5b660d2danthony case ErodeIntensityMorphology: 3171930be614b4595b97cd79ee864a394796740f76adanthony /* Select Pixel with Minimum Intensity within kernel neighbourhood 3172930be614b4595b97cd79ee864a394796740f76adanthony ** 3173930be614b4595b97cd79ee864a394796740f76adanthony ** WARNING: the intensity test fails for CMYK and does not 3174c406ea496196b962e4bc865ed8f6a4491241c6edanthony ** take into account the moderating effect of the alpha channel 3175930be614b4595b97cd79ee864a394796740f76adanthony ** on the intensity. 3176930be614b4595b97cd79ee864a394796740f76adanthony ** 3177930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE that the kernel is not reflected for this operation! 3178930be614b4595b97cd79ee864a394796740f76adanthony */ 31794fd27e21043be809d66c8202e779255e5b660d2danthony k = kernel->values; 3180602ab9b30b644a78a4057da93d838a77391ec0acanthony k_pixels = p; 3181bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3182bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k++) { 31834fd27e21043be809d66c8202e779255e5b660d2danthony if ( IsNan(*k) || (*k) < 0.5 ) continue; 318429188a8682a98d4b7882cca434b170517555fc7danthony if ( result.red == 0.0 || 3185ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelIntensity(image,k_pixels+u*GetPixelChannels(image)) < GetPixelIntensity(morphology_image,q) ) { 318629188a8682a98d4b7882cca434b170517555fc7danthony /* copy the whole pixel - no channel selection */ 3187c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelRed(morphology_image,GetPixelRed(image, 3188ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3189c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelGreen(morphology_image,GetPixelGreen(image, 3190ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3191c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelBlue(morphology_image,GetPixelBlue(image, 3192ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3193c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelAlpha(morphology_image,GetPixelAlpha(image, 3194ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 319529188a8682a98d4b7882cca434b170517555fc7danthony if ( result.red > 0.0 ) changed++; 319629188a8682a98d4b7882cca434b170517555fc7danthony result.red = 1.0; 319729188a8682a98d4b7882cca434b170517555fc7danthony } 3198602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3199ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3200602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3201602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3202602ab9b30b644a78a4057da93d838a77391ec0acanthony 32034fd27e21043be809d66c8202e779255e5b660d2danthony case DilateIntensityMorphology: 3204930be614b4595b97cd79ee864a394796740f76adanthony /* Select Pixel with Maximum Intensity within kernel neighbourhood 3205930be614b4595b97cd79ee864a394796740f76adanthony ** 3206930be614b4595b97cd79ee864a394796740f76adanthony ** WARNING: the intensity test fails for CMYK and does not 32079eb4f74649b23c053b308ce1152dce51239450baanthony ** take into account the moderating effect of the alpha channel 32089eb4f74649b23c053b308ce1152dce51239450baanthony ** on the intensity (yet). 3209930be614b4595b97cd79ee864a394796740f76adanthony ** 3210930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE for correct working of this operation for asymetrical 3211930be614b4595b97cd79ee864a394796740f76adanthony ** kernels, the kernel needs to be applied in its reflected form. 3212930be614b4595b97cd79ee864a394796740f76adanthony ** That is its values needs to be reversed. 3213930be614b4595b97cd79ee864a394796740f76adanthony */ 32144fd27e21043be809d66c8202e779255e5b660d2danthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 3215602ab9b30b644a78a4057da93d838a77391ec0acanthony k_pixels = p; 3216bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3217bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k--) { 32184fd27e21043be809d66c8202e779255e5b660d2danthony if ( IsNan(*k) || (*k) < 0.5 ) continue; /* boolean kernel */ 321929188a8682a98d4b7882cca434b170517555fc7danthony if ( result.red == 0.0 || 3220ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelIntensity(image,k_pixels+u*GetPixelChannels(image)) > GetPixelIntensity(morphology_image,q) ) { 322129188a8682a98d4b7882cca434b170517555fc7danthony /* copy the whole pixel - no channel selection */ 3222c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelRed(morphology_image,GetPixelRed(image, 3223ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3224c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelGreen(morphology_image,GetPixelGreen(image, 3225ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3226c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelBlue(morphology_image,GetPixelBlue(image, 3227ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3228c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelAlpha(morphology_image,GetPixelAlpha(image, 3229ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 323029188a8682a98d4b7882cca434b170517555fc7danthony if ( result.red > 0.0 ) changed++; 323129188a8682a98d4b7882cca434b170517555fc7danthony result.red = 1.0; 323229188a8682a98d4b7882cca434b170517555fc7danthony } 3233602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3234ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3235602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3236602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3237db60568e12574785101a4ae8d8da076227a0a889anthony 3238f34d9b2df49a407af764c79e07d587af0600983aanthony case IterativeDistanceMorphology: 3239f34d9b2df49a407af764c79e07d587af0600983aanthony /* Work out an iterative distance from black edge of a white image 3240f34d9b2df49a407af764c79e07d587af0600983aanthony ** shape. Essentually white values are decreased to the smallest 3241f34d9b2df49a407af764c79e07d587af0600983aanthony ** 'distance from edge' it can find. 3242f34d9b2df49a407af764c79e07d587af0600983aanthony ** 3243f34d9b2df49a407af764c79e07d587af0600983aanthony ** It works by adding kernel values to the neighbourhood, and and 3244f34d9b2df49a407af764c79e07d587af0600983aanthony ** select the minimum value found. The kernel is rotated before 3245f34d9b2df49a407af764c79e07d587af0600983aanthony ** use, so kernel distances match resulting distances, when a user 3246f34d9b2df49a407af764c79e07d587af0600983aanthony ** provided asymmetric kernel is applied. 3247f34d9b2df49a407af764c79e07d587af0600983aanthony ** 3248f34d9b2df49a407af764c79e07d587af0600983aanthony ** 3249f34d9b2df49a407af764c79e07d587af0600983aanthony ** This code is almost identical to True GrayScale Morphology But 3250f34d9b2df49a407af764c79e07d587af0600983aanthony ** not quite. 3251930be614b4595b97cd79ee864a394796740f76adanthony ** 3252f34d9b2df49a407af764c79e07d587af0600983aanthony ** GreyDilate Kernel values added, maximum value found Kernel is 3253f34d9b2df49a407af764c79e07d587af0600983aanthony ** rotated before use. 3254f34d9b2df49a407af764c79e07d587af0600983aanthony ** 3255f34d9b2df49a407af764c79e07d587af0600983aanthony ** GrayErode: Kernel values subtracted and minimum value found No 3256f34d9b2df49a407af764c79e07d587af0600983aanthony ** kernel rotation used. 3257f34d9b2df49a407af764c79e07d587af0600983aanthony ** 3258f34d9b2df49a407af764c79e07d587af0600983aanthony ** Note the the Iterative Distance method is essentially a 3259f34d9b2df49a407af764c79e07d587af0600983aanthony ** GrayErode, but with negative kernel values, and kernel 3260f34d9b2df49a407af764c79e07d587af0600983aanthony ** rotation applied. 3261930be614b4595b97cd79ee864a394796740f76adanthony */ 326229188a8682a98d4b7882cca434b170517555fc7danthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 3263602ab9b30b644a78a4057da93d838a77391ec0acanthony k_pixels = p; 3264bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3265bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3266602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( IsNan(*k) ) continue; 3267f34d9b2df49a407af764c79e07d587af0600983aanthony Minimize(result.red, (*k)+(double) 3268f34d9b2df49a407af764c79e07d587af0600983aanthony GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 3269f34d9b2df49a407af764c79e07d587af0600983aanthony Minimize(result.green, (*k)+(double) 3270f34d9b2df49a407af764c79e07d587af0600983aanthony GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 3271f34d9b2df49a407af764c79e07d587af0600983aanthony Minimize(result.blue, (*k)+(double) 3272f34d9b2df49a407af764c79e07d587af0600983aanthony GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 3273f34d9b2df49a407af764c79e07d587af0600983aanthony Minimize(result.alpha, (*k)+(double) 3274f34d9b2df49a407af764c79e07d587af0600983aanthony GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 3275602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( image->colorspace == CMYKColorspace) 3276f34d9b2df49a407af764c79e07d587af0600983aanthony Maximize(result.black, (*k)+(double) 3277f34d9b2df49a407af764c79e07d587af0600983aanthony GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 3278602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3279ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3280602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3281602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3282f34d9b2df49a407af764c79e07d587af0600983aanthony 3283602ab9b30b644a78a4057da93d838a77391ec0acanthony case UndefinedMorphology: 3284602ab9b30b644a78a4057da93d838a77391ec0acanthony default: 3285602ab9b30b644a78a4057da93d838a77391ec0acanthony break; /* Do nothing */ 328683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 32875ef8e94ff55717be2387d537bd49025780a1a558anthony /* Final mathematics of results (combine with original image?) 32885ef8e94ff55717be2387d537bd49025780a1a558anthony ** 32895ef8e94ff55717be2387d537bd49025780a1a558anthony ** NOTE: Difference Morphology operators Edge* and *Hat could also 32905ef8e94ff55717be2387d537bd49025780a1a558anthony ** be done here but works better with iteration as a image difference 32915ef8e94ff55717be2387d537bd49025780a1a558anthony ** in the controling function (below). Thicken and Thinning however 32925ef8e94ff55717be2387d537bd49025780a1a558anthony ** should be done here so thay can be iterated correctly. 32935ef8e94ff55717be2387d537bd49025780a1a558anthony */ 32945ef8e94ff55717be2387d537bd49025780a1a558anthony switch ( method ) { 32955ef8e94ff55717be2387d537bd49025780a1a558anthony case HitAndMissMorphology: 32965ef8e94ff55717be2387d537bd49025780a1a558anthony case ErodeMorphology: 32975ef8e94ff55717be2387d537bd49025780a1a558anthony result = min; /* minimum of neighbourhood */ 32985ef8e94ff55717be2387d537bd49025780a1a558anthony break; 32995ef8e94ff55717be2387d537bd49025780a1a558anthony case DilateMorphology: 33005ef8e94ff55717be2387d537bd49025780a1a558anthony result = max; /* maximum of neighbourhood */ 33015ef8e94ff55717be2387d537bd49025780a1a558anthony break; 33025ef8e94ff55717be2387d537bd49025780a1a558anthony case ThinningMorphology: 33035ef8e94ff55717be2387d537bd49025780a1a558anthony /* subtract pattern match from original */ 33045ef8e94ff55717be2387d537bd49025780a1a558anthony result.red -= min.red; 33055ef8e94ff55717be2387d537bd49025780a1a558anthony result.green -= min.green; 33065ef8e94ff55717be2387d537bd49025780a1a558anthony result.blue -= min.blue; 33074c08aed51c5899665ade97263692328eea4af106cristy result.black -= min.black; 3308f34d9b2df49a407af764c79e07d587af0600983aanthony result.alpha -= min.alpha; 33095ef8e94ff55717be2387d537bd49025780a1a558anthony break; 33105ef8e94ff55717be2387d537bd49025780a1a558anthony case ThickenMorphology: 33114c827ef1be3d42450ff45cedad271e6568be0ea9anthony /* Add the pattern matchs to the original */ 33124c827ef1be3d42450ff45cedad271e6568be0ea9anthony result.red += min.red; 33134c827ef1be3d42450ff45cedad271e6568be0ea9anthony result.green += min.green; 33144c827ef1be3d42450ff45cedad271e6568be0ea9anthony result.blue += min.blue; 33154c08aed51c5899665ade97263692328eea4af106cristy result.black += min.black; 3316f34d9b2df49a407af764c79e07d587af0600983aanthony result.alpha += min.alpha; 33175ef8e94ff55717be2387d537bd49025780a1a558anthony break; 33185ef8e94ff55717be2387d537bd49025780a1a558anthony default: 33195ef8e94ff55717be2387d537bd49025780a1a558anthony /* result directly calculated or assigned */ 33205ef8e94ff55717be2387d537bd49025780a1a558anthony break; 33215ef8e94ff55717be2387d537bd49025780a1a558anthony } 33225ef8e94ff55717be2387d537bd49025780a1a558anthony /* Assign the resulting pixel values - Clamping Result */ 332383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony switch ( method ) { 332483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case UndefinedMorphology: 3325c406ea496196b962e4bc865ed8f6a4491241c6edanthony case ConvolveMorphology: 332683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case DilateIntensityMorphology: 332783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case ErodeIntensityMorphology: 3328930be614b4595b97cd79ee864a394796740f76adanthony break; /* full pixel was directly assigned - not a channel method */ 332983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony default: 3330ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 33314c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image,ClampToQuantum(result.red),q); 3332ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 33334c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image,ClampToQuantum(result.green),q); 3334ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 33354c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image,ClampToQuantum(result.blue),q); 3336ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 33374c08aed51c5899665ade97263692328eea4af106cristy (image->colorspace == CMYKColorspace)) 33384c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image,ClampToQuantum(result.black),q); 3339ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 33408a46d827a124555f0c48fb2368ec1bba8e079ab6cristy (image->alpha_trait == BlendPixelTrait)) 33414c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q); 334283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony break; 334383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 33445ef8e94ff55717be2387d537bd49025780a1a558anthony /* Count up changed pixels */ 3345ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(morphology_image,q)) || 3346ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(morphology_image,q)) || 3347ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(morphology_image,q)) || 3348ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(morphology_image,q)) || 33494c08aed51c5899665ade97263692328eea4af106cristy ((image->colorspace == CMYKColorspace) && 3350ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(morphology_image,q)))) 3351c406ea496196b962e4bc865ed8f6a4491241c6edanthony changed++; /* The pixel was changed in some way! */ 3352ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p+=GetPixelChannels(image); 3353ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(morphology_image); 335483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } /* x */ 33554c08aed51c5899665ade97263692328eea4af106cristy if ( SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 3356602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 3357602ab9b30b644a78a4057da93d838a77391ec0acanthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 3358602ab9b30b644a78a4057da93d838a77391ec0acanthony { 3359602ab9b30b644a78a4057da93d838a77391ec0acanthony MagickBooleanType 3360602ab9b30b644a78a4057da93d838a77391ec0acanthony proceed; 3361602ab9b30b644a78a4057da93d838a77391ec0acanthony 3362602ab9b30b644a78a4057da93d838a77391ec0acanthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 3363ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp critical (MagickCore_MorphologyImage) 3364602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 3365602ab9b30b644a78a4057da93d838a77391ec0acanthony proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows); 3366602ab9b30b644a78a4057da93d838a77391ec0acanthony if (proceed == MagickFalse) 3367602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 3368602ab9b30b644a78a4057da93d838a77391ec0acanthony } 336983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } /* y */ 33704c08aed51c5899665ade97263692328eea4af106cristy morphology_view=DestroyCacheView(morphology_view); 33714c08aed51c5899665ade97263692328eea4af106cristy image_view=DestroyCacheView(image_view); 3372a8843c1f815ffad2568ec592d5b446cb1476aab5anthony return(status ? (ssize_t)changed : -1); 3373602ab9b30b644a78a4057da93d838a77391ec0acanthony} 3374602ab9b30b644a78a4057da93d838a77391ec0acanthony 3375a8843c1f815ffad2568ec592d5b446cb1476aab5anthony/* This is almost identical to the MorphologyPrimative() function above, 3376f34d9b2df49a407af764c79e07d587af0600983aanthony** but will apply the primitive directly to the actual image using two 3377f34d9b2df49a407af764c79e07d587af0600983aanthony** passes, once in each direction, with the results of the previous (and 3378f34d9b2df49a407af764c79e07d587af0600983aanthony** current) row being re-used. 3379a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** 3380a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** That is after each row is 'Sync'ed' into the image, the next row will 3381a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** make use of those values as part of the calculation of the next row. 3382a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** It then repeats, but going in the oppisite (bottom-up) direction. 3383a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** 3384f34d9b2df49a407af764c79e07d587af0600983aanthony** Because of this 're-use of results' this function can not make use 3385a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** of multi-threaded, parellel processing. 3386a8843c1f815ffad2568ec592d5b446cb1476aab5anthony*/ 3387e698a255629ba03cd125572de7b35b5e21c4ee5danthonystatic ssize_t MorphologyPrimitiveDirect(Image *image, 3388f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method,const KernelInfo *kernel, 3389f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 3390a8843c1f815ffad2568ec592d5b446cb1476aab5anthony{ 3391a8843c1f815ffad2568ec592d5b446cb1476aab5anthony CacheView 3392a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *auth_view, 3393a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *virt_view; 3394a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3395a8843c1f815ffad2568ec592d5b446cb1476aab5anthony MagickBooleanType 3396a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status; 3397a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3398a8843c1f815ffad2568ec592d5b446cb1476aab5anthony MagickOffsetType 3399a8843c1f815ffad2568ec592d5b446cb1476aab5anthony progress; 3400a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3401a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3402a8843c1f815ffad2568ec592d5b446cb1476aab5anthony y, offx, offy; 3403a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3404a8843c1f815ffad2568ec592d5b446cb1476aab5anthony size_t 3405db60568e12574785101a4ae8d8da076227a0a889anthony virt_width, 3406a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed; 3407a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3408a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickTrue; 3409a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed=0; 3410a8843c1f815ffad2568ec592d5b446cb1476aab5anthony progress=0; 3411a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3412a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(image != (Image *) NULL); 3413a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(image->signature == MagickSignature); 3414a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(kernel != (KernelInfo *) NULL); 3415a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(kernel->signature == MagickSignature); 3416a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(exception != (ExceptionInfo *) NULL); 3417a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(exception->signature == MagickSignature); 3418a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3419a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Some methods (including convolve) needs use a reflected kernel. 3420a8843c1f815ffad2568ec592d5b446cb1476aab5anthony * Adjust 'origin' offsets to loop though kernel as a reflection. 3421a8843c1f815ffad2568ec592d5b446cb1476aab5anthony */ 3422a8843c1f815ffad2568ec592d5b446cb1476aab5anthony offx = kernel->x; 3423a8843c1f815ffad2568ec592d5b446cb1476aab5anthony offy = kernel->y; 3424a8843c1f815ffad2568ec592d5b446cb1476aab5anthony switch(method) { 3425a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3426e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3427a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* kernel needs to used with reflection about origin */ 3428a8843c1f815ffad2568ec592d5b446cb1476aab5anthony offx = (ssize_t) kernel->width-offx-1; 3429a8843c1f815ffad2568ec592d5b446cb1476aab5anthony offy = (ssize_t) kernel->height-offy-1; 3430a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3431a8843c1f815ffad2568ec592d5b446cb1476aab5anthony#if 0 3432a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case ?????Morphology: 3433a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* kernel is used as is, without reflection */ 3434a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3435a8843c1f815ffad2568ec592d5b446cb1476aab5anthony#endif 3436a8843c1f815ffad2568ec592d5b446cb1476aab5anthony default: 3437a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert("Not a PrimativeDirect Morphology Method" != (char *) NULL); 3438a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3439a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3440a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3441a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* DO NOT THREAD THIS CODE! */ 3442a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* two views into same image (virtual, and actual) */ 344346ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy virt_view=AcquireVirtualCacheView(image,exception); 344446ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy auth_view=AcquireAuthenticCacheView(image,exception); 3445db60568e12574785101a4ae8d8da076227a0a889anthony virt_width=image->columns+kernel->width-1; 3446a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3447a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (y=0; y < (ssize_t) image->rows; y++) 3448a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 34494c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3450a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict p; 3451a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 34524c08aed51c5899665ade97263692328eea4af106cristy register Quantum 3453a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict q; 3454a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3455a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register ssize_t 3456a8843c1f815ffad2568ec592d5b446cb1476aab5anthony x; 3457a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3458a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3459a8843c1f815ffad2568ec592d5b446cb1476aab5anthony r; 3460a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3461a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* NOTE read virtual pixels, and authentic pixels, from the same image! 3462a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** we read using virtual to get virtual pixel handling, but write back 3463a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** into the same image. 3464a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** 3465a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** Only top half of kernel is processed as we do a single pass downward 3466a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** through the image iterating the distance function as we go. 3467a8843c1f815ffad2568ec592d5b446cb1476aab5anthony */ 3468a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (status == MagickFalse) 3469a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 34704c08aed51c5899665ade97263692328eea4af106cristy p=GetCacheViewVirtualPixels(virt_view,-offx,y-offy,virt_width,(size_t) 34714c08aed51c5899665ade97263692328eea4af106cristy offy+1,exception); 3472db60568e12574785101a4ae8d8da076227a0a889anthony q=GetCacheViewAuthenticPixels(auth_view, 0, y, image->columns, 1, 34734c08aed51c5899665ade97263692328eea4af106cristy exception); 34744c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 3475a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3476a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (status == MagickFalse) 3477a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3478a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3479a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* offset to origin in 'p'. while 'q' points to it directly */ 3480aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy r = (ssize_t) virt_width*offy + offx; 3481a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3482a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (x=0; x < (ssize_t) image->columns; x++) 3483a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 3484d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy PixelInfo 3485d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy result; 3486a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3487d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register const MagickRealType 3488a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict k; 3489a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 34904c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3491a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict k_pixels; 3492a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3493d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register ssize_t 3494d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy u; 3495d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 3496d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy ssize_t 3497d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy v; 3498a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3499e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Starting Defaults */ 35004c08aed51c5899665ade97263692328eea4af106cristy GetPixelInfo(image,&result); 3501803640d20a6a664315eddfff6f8531d0c5e0871dcristy GetPixelInfoPixel(image,q,&result); 3502e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( method != VoronoiMorphology ) 35034c08aed51c5899665ade97263692328eea4af106cristy result.alpha = QuantumRange - result.alpha; 3504a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3505a8843c1f815ffad2568ec592d5b446cb1476aab5anthony switch ( method ) { 3506a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3507a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Add kernel Value and select the minimum value found. */ 3508a8843c1f815ffad2568ec592d5b446cb1476aab5anthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 3509a8843c1f815ffad2568ec592d5b446cb1476aab5anthony k_pixels = p; 3510a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (v=0; v <= (ssize_t) offy; v++) { 3511a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3512a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( IsNan(*k) ) continue; 35134c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.red, (*k)+ 3514ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 35154c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.green, (*k)+ 3516ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 35174c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.blue, (*k)+ 3518ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 35194c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 35204c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.black,(*k)+ 3521ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 35224c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.alpha, (*k)+ 3523ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 3524a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3525ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3526a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3527a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* repeat with the just processed pixels of this row */ 3528db60568e12574785101a4ae8d8da076227a0a889anthony k = &kernel->values[ kernel->width*(kernel->y+1)-1 ]; 3529ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels = q-offx*GetPixelChannels(image); 3530a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (u=0; u < (ssize_t) offx; u++, k--) { 3531a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( x+u-offx < 0 ) continue; /* off the edge! */ 3532a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( IsNan(*k) ) continue; 35334c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.red, (*k)+ 3534ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 35354c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.green, (*k)+ 3536ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 35374c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.blue, (*k)+ 3538ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 35394c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 35404c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.black,(*k)+ 3541ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 35424c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.alpha,(*k)+ 3543ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 3544a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3545a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3546e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3547ea068a53d23d6dca08f1bce44c8937d54f83b983anthony /* Apply Distance to 'Matte' channel, while coping the color 3548ea068a53d23d6dca08f1bce44c8937d54f83b983anthony ** values of the closest pixel. 3549e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** 3550e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** This is experimental, and realy the 'alpha' component should 3551f34d9b2df49a407af764c79e07d587af0600983aanthony ** be completely separate 'masking' channel so that alpha can 3552f34d9b2df49a407af764c79e07d587af0600983aanthony ** also be used as part of the results. 3553e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 3554e698a255629ba03cd125572de7b35b5e21c4ee5danthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 3555e698a255629ba03cd125572de7b35b5e21c4ee5danthony k_pixels = p; 3556e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (v=0; v <= (ssize_t) offy; v++) { 3557e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3558e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( IsNan(*k) ) continue; 3559ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) ) 3560e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3561803640d20a6a664315eddfff6f8531d0c5e0871dcristy GetPixelInfoPixel(image,k_pixels+u*GetPixelChannels(image), 35624a06a14c06f675b6a2052a3c814e7da54877a733cristy &result); 35634c08aed51c5899665ade97263692328eea4af106cristy result.alpha += *k; 3564e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3565e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3566ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3567e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3568e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* repeat with the just processed pixels of this row */ 3569e698a255629ba03cd125572de7b35b5e21c4ee5danthony k = &kernel->values[ kernel->width*(kernel->y+1)-1 ]; 3570ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels = q-offx*GetPixelChannels(image); 3571e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (u=0; u < (ssize_t) offx; u++, k--) { 3572e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( x+u-offx < 0 ) continue; /* off the edge! */ 3573e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( IsNan(*k) ) continue; 3574ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) ) 3575e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3576803640d20a6a664315eddfff6f8531d0c5e0871dcristy GetPixelInfoPixel(image,k_pixels+u*GetPixelChannels(image), 35774a06a14c06f675b6a2052a3c814e7da54877a733cristy &result); 35784c08aed51c5899665ade97263692328eea4af106cristy result.alpha += *k; 3579e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3580e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3581e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3582a8843c1f815ffad2568ec592d5b446cb1476aab5anthony default: 3583a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* result directly calculated or assigned */ 3584a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3585a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3586a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Assign the resulting pixel values - Clamping Result */ 3587e698a255629ba03cd125572de7b35b5e21c4ee5danthony switch ( method ) { 3588e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3589803640d20a6a664315eddfff6f8531d0c5e0871dcristy SetPixelInfoPixel(image,&result,q); 3590e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3591e698a255629ba03cd125572de7b35b5e21c4ee5danthony default: 3592ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 35934c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(image,ClampToQuantum(result.red),q); 3594ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 35954c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(image,ClampToQuantum(result.green),q); 3596ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 35974c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(image,ClampToQuantum(result.blue),q); 3598ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 35994c08aed51c5899665ade97263692328eea4af106cristy (image->colorspace == CMYKColorspace)) 36004c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(image,ClampToQuantum(result.black),q); 3601ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0 && 36028a46d827a124555f0c48fb2368ec1bba8e079ab6cristy (image->alpha_trait == BlendPixelTrait)) 36034c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(image,ClampToQuantum(result.alpha),q); 3604e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3605e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3606a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Count up changed pixels */ 3607ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(image,q)) || 3608ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(image,q)) || 3609ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(image,q)) || 3610ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(image,q)) || 36114c08aed51c5899665ade97263692328eea4af106cristy ((image->colorspace == CMYKColorspace) && 3612ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(image,q)))) 3613a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed++; /* The pixel was changed in some way! */ 3614a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3615ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p+=GetPixelChannels(image); /* increment pixel buffers */ 3616ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(image); 3617a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* x */ 36184fd27e21043be809d66c8202e779255e5b660d2danthony 3619a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( SyncCacheViewAuthenticPixels(auth_view,exception) == MagickFalse) 3620a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3621a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 3622a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( SetImageProgress(image,MorphologyTag,progress++,image->rows) 3623a8843c1f815ffad2568ec592d5b446cb1476aab5anthony == MagickFalse ) 3624a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3625a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3626a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* y */ 3627a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3628a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Do the reversed pass through the image */ 3629a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (y=(ssize_t)image->rows-1; y >= 0; y--) 3630a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 36314c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3632a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict p; 3633a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 36344c08aed51c5899665ade97263692328eea4af106cristy register Quantum 3635a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict q; 3636a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3637a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register ssize_t 3638a8843c1f815ffad2568ec592d5b446cb1476aab5anthony x; 3639a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3640a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3641a8843c1f815ffad2568ec592d5b446cb1476aab5anthony r; 3642a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3643db60568e12574785101a4ae8d8da076227a0a889anthony if (status == MagickFalse) 3644db60568e12574785101a4ae8d8da076227a0a889anthony break; 3645a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* NOTE read virtual pixels, and authentic pixels, from the same image! 3646a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** we read using virtual to get virtual pixel handling, but write back 3647a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** into the same image. 3648a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** 3649a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** Only the bottom half of the kernel will be processes as we 3650a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** up the image. 3651a8843c1f815ffad2568ec592d5b446cb1476aab5anthony */ 36524c08aed51c5899665ade97263692328eea4af106cristy p=GetCacheViewVirtualPixels(virt_view,-offx,y,virt_width,(size_t) 36534c08aed51c5899665ade97263692328eea4af106cristy kernel->y+1,exception); 3654db60568e12574785101a4ae8d8da076227a0a889anthony q=GetCacheViewAuthenticPixels(auth_view, 0, y, image->columns, 1, 36554c08aed51c5899665ade97263692328eea4af106cristy exception); 36564c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 3657a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3658a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (status == MagickFalse) 3659a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3660a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3661a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* adjust positions to end of row */ 3662ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p += (image->columns-1)*GetPixelChannels(image); 3663ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q += (image->columns-1)*GetPixelChannels(image); 3664a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3665a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* offset to origin in 'p'. while 'q' points to it directly */ 3666a8843c1f815ffad2568ec592d5b446cb1476aab5anthony r = offx; 3667a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3668a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (x=(ssize_t)image->columns-1; x >= 0; x--) 3669a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 3670d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy PixelInfo 3671d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy result; 3672a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3673d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register const MagickRealType 3674a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict k; 3675a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 36764c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3677a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict k_pixels; 3678a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3679d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register ssize_t 3680d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy u; 3681d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 3682d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy ssize_t 3683d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy v; 3684a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3685e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Default - previously modified pixel */ 36864c08aed51c5899665ade97263692328eea4af106cristy GetPixelInfo(image,&result); 3687803640d20a6a664315eddfff6f8531d0c5e0871dcristy GetPixelInfoPixel(image,q,&result); 3688e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( method != VoronoiMorphology ) 36894c08aed51c5899665ade97263692328eea4af106cristy result.alpha = QuantumRange - result.alpha; 3690a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3691a8843c1f815ffad2568ec592d5b446cb1476aab5anthony switch ( method ) { 3692a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3693a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Add kernel Value and select the minimum value found. */ 3694db60568e12574785101a4ae8d8da076227a0a889anthony k = &kernel->values[ kernel->width*(kernel->y+1)-1 ]; 3695a8843c1f815ffad2568ec592d5b446cb1476aab5anthony k_pixels = p; 3696a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (v=offy; v < (ssize_t) kernel->height; v++) { 3697a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3698a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( IsNan(*k) ) continue; 36994c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.red, (*k)+ 3700ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 37014c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.green, (*k)+ 3702ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 37034c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.blue, (*k)+ 3704ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 3705a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( image->colorspace == CMYKColorspace) 37064c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.black,(*k)+ 3707ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 37084c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.alpha, (*k)+ 3709ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 3710a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3711ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3712a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3713a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* repeat with the just processed pixels of this row */ 3714db60568e12574785101a4ae8d8da076227a0a889anthony k = &kernel->values[ kernel->width*(kernel->y)+kernel->x-1 ]; 3715ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels = q-offx*GetPixelChannels(image); 3716a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (u=offx+1; u < (ssize_t) kernel->width; u++, k--) { 3717e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( (x+u-offx) >= (ssize_t)image->columns ) continue; 3718a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( IsNan(*k) ) continue; 37194c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.red, (*k)+ 3720ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 37214c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.green, (*k)+ 3722ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 37234c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.blue, (*k)+ 3724ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 3725a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( image->colorspace == CMYKColorspace) 37264c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.black, (*k)+ 3727ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 37284c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.alpha, (*k)+ 3729ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 3730a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3731a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3732e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3733e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Apply Distance to 'Matte' channel, coping the closest color. 3734e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** 3735e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** This is experimental, and realy the 'alpha' component should 3736e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** be completely separate 'masking' channel. 3737e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 3738e698a255629ba03cd125572de7b35b5e21c4ee5danthony k = &kernel->values[ kernel->width*(kernel->y+1)-1 ]; 3739e698a255629ba03cd125572de7b35b5e21c4ee5danthony k_pixels = p; 3740e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (v=offy; v < (ssize_t) kernel->height; v++) { 3741e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3742e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( IsNan(*k) ) continue; 3743ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) ) 3744e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3745803640d20a6a664315eddfff6f8531d0c5e0871dcristy GetPixelInfoPixel(image,k_pixels+u*GetPixelChannels(image), 37464a06a14c06f675b6a2052a3c814e7da54877a733cristy &result); 37474c08aed51c5899665ade97263692328eea4af106cristy result.alpha += *k; 3748e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3749e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3750ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3751e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3752e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* repeat with the just processed pixels of this row */ 3753e698a255629ba03cd125572de7b35b5e21c4ee5danthony k = &kernel->values[ kernel->width*(kernel->y)+kernel->x-1 ]; 3754ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels = q-offx*GetPixelChannels(image); 3755e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (u=offx+1; u < (ssize_t) kernel->width; u++, k--) { 3756e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( (x+u-offx) >= (ssize_t)image->columns ) continue; 3757e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( IsNan(*k) ) continue; 3758ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) ) 3759e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3760803640d20a6a664315eddfff6f8531d0c5e0871dcristy GetPixelInfoPixel(image,k_pixels+u*GetPixelChannels(image), 37614a06a14c06f675b6a2052a3c814e7da54877a733cristy &result); 37624c08aed51c5899665ade97263692328eea4af106cristy result.alpha += *k; 3763e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3764e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3765e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3766a8843c1f815ffad2568ec592d5b446cb1476aab5anthony default: 3767a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* result directly calculated or assigned */ 3768a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3769a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3770a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Assign the resulting pixel values - Clamping Result */ 3771e698a255629ba03cd125572de7b35b5e21c4ee5danthony switch ( method ) { 3772e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3773803640d20a6a664315eddfff6f8531d0c5e0871dcristy SetPixelInfoPixel(image,&result,q); 3774e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3775e698a255629ba03cd125572de7b35b5e21c4ee5danthony default: 3776ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 37774c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(image,ClampToQuantum(result.red),q); 3778ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 37794c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(image,ClampToQuantum(result.green),q); 3780ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 37814c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(image,ClampToQuantum(result.blue),q); 3782ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 37834c08aed51c5899665ade97263692328eea4af106cristy (image->colorspace == CMYKColorspace)) 37844c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(image,ClampToQuantum(result.black),q); 3785ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0 && 37868a46d827a124555f0c48fb2368ec1bba8e079ab6cristy (image->alpha_trait == BlendPixelTrait)) 37874c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(image,ClampToQuantum(result.alpha),q); 3788e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3789e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3790a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Count up changed pixels */ 3791ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ( (GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(image,q)) 3792ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(image,q)) 3793ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(image,q)) 3794ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(image,q)) 37954c08aed51c5899665ade97263692328eea4af106cristy || ((image->colorspace == CMYKColorspace) && 3796ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(image,q)))) 3797a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed++; /* The pixel was changed in some way! */ 3798a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3799ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p-=GetPixelChannels(image); /* go backward through pixel buffers */ 3800ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q-=GetPixelChannels(image); 3801a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* x */ 3802a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( SyncCacheViewAuthenticPixels(auth_view,exception) == MagickFalse) 3803a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3804a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 3805a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( SetImageProgress(image,MorphologyTag,progress++,image->rows) 3806a8843c1f815ffad2568ec592d5b446cb1476aab5anthony == MagickFalse ) 3807a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3808a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3809a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* y */ 3810e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3811a8843c1f815ffad2568ec592d5b446cb1476aab5anthony auth_view=DestroyCacheView(auth_view); 3812a8843c1f815ffad2568ec592d5b446cb1476aab5anthony virt_view=DestroyCacheView(virt_view); 3813aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy return(status ? (ssize_t) changed : -1); 3814a8843c1f815ffad2568ec592d5b446cb1476aab5anthony} 3815a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3816f34d9b2df49a407af764c79e07d587af0600983aanthony/* Apply a Morphology by calling one of the above low level primitive 3817f34d9b2df49a407af764c79e07d587af0600983aanthony** application functions. This function handles any iteration loops, 3818f34d9b2df49a407af764c79e07d587af0600983aanthony** composition or re-iteration of results, and compound morphology methods 3819f34d9b2df49a407af764c79e07d587af0600983aanthony** that is based on multiple low-level (staged) morphology methods. 3820a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** 382122de2722b682eb405b60ec6022a7546df994674eanthony** Basically this provides the complex glue between the requested morphology 3822a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** method and raw low-level implementation (above). 3823a8843c1f815ffad2568ec592d5b446cb1476aab5anthony*/ 3824cf592636b16d028b14c5fa9dffdc3a94eae7c2f3cristyMagickPrivate Image *MorphologyApply(const Image *image, 3825f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method, const ssize_t iterations, 3826f46d42620631d2581e0b6a56456e203e17c427c8anthony const KernelInfo *kernel, const CompositeOperator compose,const double bias, 3827f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 3828602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 38291cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy CompositeOperator 38301cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy curr_compose; 38311cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy 3832602ab9b30b644a78a4057da93d838a77391ec0acanthony Image 383347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *curr_image, /* Image we are working with or iterating */ 3834a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *work_image, /* secondary image for primitive iteration */ 383547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *save_image, /* saved image - for 'edge' method only */ 383647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *rslt_image; /* resultant image - after multi-kernel handling */ 3837602ab9b30b644a78a4057da93d838a77391ec0acanthony 38384fd27e21043be809d66c8202e779255e5b660d2danthony KernelInfo 383947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *reflected_kernel, /* A reflected copy of the kernel (if needed) */ 384047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *norm_kernel, /* the current normal un-reflected kernel */ 384147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *rflt_kernel, /* the current reflected kernel (if needed) */ 384247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *this_kernel; /* the kernel being applied */ 38434fd27e21043be809d66c8202e779255e5b660d2danthony 38444fd27e21043be809d66c8202e779255e5b660d2danthony MorphologyMethod 3845a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive; /* the current morphology primitive being applied */ 38469eb4f74649b23c053b308ce1152dce51239450baanthony 38479eb4f74649b23c053b308ce1152dce51239450baanthony CompositeOperator 384847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose; /* multi-kernel compose method for results to use */ 384947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 385047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony MagickBooleanType 3851e698a255629ba03cd125572de7b35b5e21c4ee5danthony special, /* do we use a direct modify function? */ 385247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony verbose; /* verbose output of results */ 38534fd27e21043be809d66c8202e779255e5b660d2danthony 3854bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 3855a8843c1f815ffad2568ec592d5b446cb1476aab5anthony method_loop, /* Loop 1: number of compound method iterations (norm 1) */ 385647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_limit, /* maximum number of compound method iterations */ 385747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number, /* Loop 2: the kernel number being applied */ 3858a8843c1f815ffad2568ec592d5b446cb1476aab5anthony stage_loop, /* Loop 3: primitive loop for compound morphology */ 3859a8843c1f815ffad2568ec592d5b446cb1476aab5anthony stage_limit, /* how many primitives are in this compound */ 3860a8843c1f815ffad2568ec592d5b446cb1476aab5anthony kernel_loop, /* Loop 4: iterate the kernel over image */ 386147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_limit, /* number of times to iterate kernel */ 3862a8843c1f815ffad2568ec592d5b446cb1476aab5anthony count, /* total count of primitive steps applied */ 386347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_changed, /* total count of changed using iterated kernel */ 386447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed; /* total count of changed over method iteration */ 386547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 3866a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3867a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed; /* number pixels changed by last primitive operation */ 3868a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 386947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony char 387047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony v_info[80]; 38711b2bc0a7da432e6e1cc0480280402df213faa940anthony 3872602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(image != (Image *) NULL); 3873602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(image->signature == MagickSignature); 38744fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel != (KernelInfo *) NULL); 38754fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel->signature == MagickSignature); 3876602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(exception != (ExceptionInfo *) NULL); 3877602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(exception->signature == MagickSignature); 3878602ab9b30b644a78a4057da93d838a77391ec0acanthony 3879a8843c1f815ffad2568ec592d5b446cb1476aab5anthony count = 0; /* number of low-level morphology primitives performed */ 3880602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( iterations == 0 ) 388147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return((Image *)NULL); /* null operation - nothing to do! */ 3882602ab9b30b644a78a4057da93d838a77391ec0acanthony 3883bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel_limit = (size_t) iterations; 388447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( iterations < 0 ) /* negative interations = infinite (well alomst) */ 3885e698a255629ba03cd125572de7b35b5e21c4ee5danthony kernel_limit = image->columns>image->rows ? image->columns : image->rows; 388628ad1d779b6ca95852e860514185a7a97e06af77anthony 38876f2013165d72f7d8ef5f66bb9453126d88113809anthony verbose = IsStringTrue(GetImageArtifact(image,"verbose")); 38884f1dcb76c95ef6410f2957ca9e7e1d391cee0d02anthony 38899eb4f74649b23c053b308ce1152dce51239450baanthony /* initialise for cleanup */ 389047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; 38911cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy curr_compose = image->compose; 3892aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy (void) curr_compose; 389347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = save_image = rslt_image = (Image *) NULL; 389447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = (KernelInfo *) NULL; 38954fd27e21043be809d66c8202e779255e5b660d2danthony 389647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Initialize specific methods 389747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony * + which loop should use the given iteratations 3898a8843c1f815ffad2568ec592d5b446cb1476aab5anthony * + how many primitives make up the compound morphology 389947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony * + multi-kernel compose method to use (by default) 390047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 390147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_limit = 1; /* just do method once, unless otherwise set */ 3902ea61f01656bb0f9074677452017cc559e54093faanthony stage_limit = 1; /* assume method is not a compound */ 39034ee950098ad0166bbbc85c3a59bc079cd321384aglennrp special = MagickFalse; /* assume it is NOT a direct modify primitive */ 390447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = compose; /* and we are composing multi-kernels as given */ 39059eb4f74649b23c053b308ce1152dce51239450baanthony switch( method ) { 3906a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case SmoothMorphology: /* 4 primitive compound morphology */ 390747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_limit = 4; 3908602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3909a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case OpenMorphology: /* 2 primitive compound morphology */ 3910930be614b4595b97cd79ee864a394796740f76adanthony case OpenIntensityMorphology: 391147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: 391247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: 39134fd27e21043be809d66c8202e779255e5b660d2danthony case CloseIntensityMorphology: 391447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 391547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: 391647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_limit = 2; 3917602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 39189eb4f74649b23c053b308ce1152dce51239450baanthony case HitAndMissMorphology: 391947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = LightenCompositeOp; /* Union of multi-kernel results */ 39203ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony /* FALL THUR */ 3921c3e48258f3253188894e783dcdfd03562f7ab2c5anthony case ThinningMorphology: 39229eb4f74649b23c053b308ce1152dce51239450baanthony case ThickenMorphology: 39233ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony method_limit = kernel_limit; /* iterate the whole method */ 3924c3e48258f3253188894e783dcdfd03562f7ab2c5anthony kernel_limit = 1; /* do not do kernel iteration */ 392547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 3926a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3927e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3928f34d9b2df49a407af764c79e07d587af0600983aanthony special = MagickTrue; /* use special direct primative */ 3929a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 393047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 39319eb4f74649b23c053b308ce1152dce51239450baanthony break; 39329eb4f74649b23c053b308ce1152dce51239450baanthony } 3933602ab9b30b644a78a4057da93d838a77391ec0acanthony 3934e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Apply special methods with special requirments 3935e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** For example, single run only, or post-processing requirements 3936e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 3937e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( special == MagickTrue ) 3938e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3939e698a255629ba03cd125572de7b35b5e21c4ee5danthony rslt_image=CloneImage(image,0,0,MagickTrue,exception); 3940e698a255629ba03cd125572de7b35b5e21c4ee5danthony if (rslt_image == (Image *) NULL) 3941e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto error_cleanup; 3942574cc26500992189f637cd1cdf93d0654e7df7aecristy if (SetImageStorageClass(rslt_image,DirectClass,exception) == MagickFalse) 3943574cc26500992189f637cd1cdf93d0654e7df7aecristy goto error_cleanup; 3944e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3945e698a255629ba03cd125572de7b35b5e21c4ee5danthony changed = MorphologyPrimitiveDirect(rslt_image, method, 3946f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy kernel, exception); 3947e698a255629ba03cd125572de7b35b5e21c4ee5danthony 39487bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 39495acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) (void) FormatLocaleFile(stderr, 39501e604812fad85bb96f757a2393015ae3d061c39acristy "%s:%.20g.%.20g #%.20g => Changed %.20g\n", 39511e604812fad85bb96f757a2393015ae3d061c39acristy CommandOptionToMnemonic(MagickMorphologyOptions, method), 39521e604812fad85bb96f757a2393015ae3d061c39acristy 1.0,0.0,1.0, (double) changed); 3953e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3954e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( changed < 0 ) 3955e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto error_cleanup; 3956e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3957e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( method == VoronoiMorphology ) { 3958e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Preserve the alpha channel of input image - but turned off */ 395963240888c3975789a09c2494a4654b523931df96cristy (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel, 396063240888c3975789a09c2494a4654b523931df96cristy exception); 3961feb3e9695150978a5d2372d3fe2f60466a7c8066cristy (void) CompositeImage(rslt_image,image,CopyAlphaCompositeOp, 396239172408bad7ef2ef00a815fa9abf9979e7857cbcristy MagickTrue,0,0,exception); 396363240888c3975789a09c2494a4654b523931df96cristy (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel, 396463240888c3975789a09c2494a4654b523931df96cristy exception); 3965e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3966e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto exit_cleanup; 3967e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3968e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3969c3e48258f3253188894e783dcdfd03562f7ab2c5anthony /* Handle user (caller) specified multi-kernel composition method */ 397047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( compose != UndefinedCompositeOp ) 397147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = compose; /* override default composition for method */ 397247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rslt_compose == UndefinedCompositeOp ) 397347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = NoCompositeOp; /* still not defined! Then re-iterate */ 39744fd27e21043be809d66c8202e779255e5b660d2danthony 3975a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Some methods require a reflected kernel to use with primitives. 3976c3e48258f3253188894e783dcdfd03562f7ab2c5anthony * Create the reflected kernel for those methods. */ 397747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch ( method ) { 397847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CorrelateMorphology: 397947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: 398047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseIntensityMorphology: 398147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 398247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case SmoothMorphology: 398347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = CloneKernelInfo(kernel); 398447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if (reflected_kernel == (KernelInfo *) NULL) 398547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony goto error_cleanup; 398647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony RotateKernelInfo(reflected_kernel,180); 398747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 398847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 398947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 399047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 3991602ab9b30b644a78a4057da93d838a77391ec0acanthony 3992e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Loops around more primitive morpholgy methods 3993e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** erose, dilate, open, close, smooth, edge, etc... 3994e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 399547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 1: iterate the compound method */ 399647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_loop = 0; 399747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed = 1; 399847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( method_loop < method_limit && method_changed > 0 ) { 399947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_loop++; 400047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed = 0; 400147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 400247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 2: iterate over each kernel in a multi-kernel list */ 400347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony norm_kernel = (KernelInfo *) kernel; 4004f2faecf9facdbbb14fcba373365f9f691a9658e0cristy this_kernel = (KernelInfo *) kernel; 400547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rflt_kernel = reflected_kernel; 4006e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony 400747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number = 0; 400847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( norm_kernel != NULL ) { 400947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 401047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 3: Compound Morphology Staging - Select Primative to apply */ 401147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_loop = 0; /* the compound morphology stage number */ 401247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( stage_loop < stage_limit ) { 401347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_loop++; /* The stage of the compound morphology */ 401447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 4015a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Select primitive morphology for this stage of compound method */ 401647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = norm_kernel; /* default use unreflected kernel */ 4017a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = method; /* Assume method is a primitive */ 401847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch( method ) { 401947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case ErodeMorphology: /* just erode */ 402047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeInMorphology: /* erode and image difference */ 4021a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 402247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 402347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case DilateMorphology: /* just dilate */ 402447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeOutMorphology: /* dilate and image difference */ 4025a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 402647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 402747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case OpenMorphology: /* erode then dialate */ 402847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: /* open and image difference */ 4029a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 403047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 4031a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 403247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 403347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case OpenIntensityMorphology: 4034a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeIntensityMorphology; 403547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 4036a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateIntensityMorphology; 4037e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony break; 403847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: /* dilate, then erode */ 403947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: /* close and image difference */ 404047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 4041a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 404247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 4043a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 404447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 404547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseIntensityMorphology: 404647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 4047a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateIntensityMorphology; 404847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 4049a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeIntensityMorphology; 405047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 405147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case SmoothMorphology: /* open, close */ 405247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch ( stage_loop ) { 405347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 1: /* start an open method, which starts with Erode */ 4054a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 405547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 405647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 2: /* now Dilate the Erode */ 4057a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 405847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 405947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 3: /* Reflect kernel a close */ 406047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 4061a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 406247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 406347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 4: /* Finish the Close */ 406447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 4065a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 406647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 406747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 406847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 406947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: /* dilate and erode difference */ 4070a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 407147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) { 407247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = curr_image; /* save the image difference */ 407347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; 4074a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 407547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 407647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 407747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CorrelateMorphology: 407847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* A Correlation is a Convolution with a reflected kernel. 407947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** However a Convolution is a weighted sum using a reflected 408047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** kernel. It may seem stange to convert a Correlation into a 408147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Convolution as the Correlation is the simplier method, but 408247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Convolution is much more commonly used, and it makes sense to 408347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** implement it directly so as to avoid the need to duplicate the 408447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** kernel when it is not required (which is typically the 408547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** default). 408647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 408747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 4088a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ConvolveMorphology; 408947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 409047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 409147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 409247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 4093e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert( this_kernel != (KernelInfo *) NULL ); 40947a01dcf50ce12cb2a789bedff51e9345f022432eanthony 409547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Extra information for debugging compound operations */ 40967bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) { 409747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_limit > 1 ) 4098b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy (void) FormatLocaleString(v_info,MaxTextExtent,"%s:%.20g.%.20g -> ", 4099042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickMorphologyOptions,method),(double) 4100e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy method_loop,(double) stage_loop); 4101a8843c1f815ffad2568ec592d5b446cb1476aab5anthony else if ( primitive != method ) 4102b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy (void) FormatLocaleString(v_info, MaxTextExtent, "%s:%.20g -> ", 4103042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickMorphologyOptions, method),(double) 4104e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy method_loop); 410547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else 410647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony v_info[0] = '\0'; 410747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 41089eb4f74649b23c053b308ce1152dce51239450baanthony 4109a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Loop 4: Iterate the kernel with primitive */ 411047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_loop = 0; 411147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_changed = 0; 411247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony changed = 1; 411347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( kernel_loop < kernel_limit && changed > 0 ) { 411447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_loop++; /* the iteration of this kernel */ 41159eb4f74649b23c053b308ce1152dce51239450baanthony 4116a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Create a clone as the destination image, if not yet defined */ 41179eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image == (Image *) NULL ) 41189eb4f74649b23c053b308ce1152dce51239450baanthony { 41199eb4f74649b23c053b308ce1152dce51239450baanthony work_image=CloneImage(image,0,0,MagickTrue,exception); 41209eb4f74649b23c053b308ce1152dce51239450baanthony if (work_image == (Image *) NULL) 41219eb4f74649b23c053b308ce1152dce51239450baanthony goto error_cleanup; 4122574cc26500992189f637cd1cdf93d0654e7df7aecristy if (SetImageStorageClass(work_image,DirectClass,exception) == MagickFalse) 4123574cc26500992189f637cd1cdf93d0654e7df7aecristy goto error_cleanup; 4124db60568e12574785101a4ae8d8da076227a0a889anthony /* work_image->type=image->type; ??? */ 41259eb4f74649b23c053b308ce1152dce51239450baanthony } 41269eb4f74649b23c053b308ce1152dce51239450baanthony 4127501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* APPLY THE MORPHOLOGICAL PRIMITIVE (curr -> work) */ 41289eb4f74649b23c053b308ce1152dce51239450baanthony count++; 4129e698a255629ba03cd125572de7b35b5e21c4ee5danthony changed = MorphologyPrimitive(curr_image, work_image, primitive, 4130f46d42620631d2581e0b6a56456e203e17c427c8anthony this_kernel, bias, exception); 413147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 41327bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) { 413347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( kernel_loop > 1 ) 41345acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line from previous */ 41355acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) (void) FormatLocaleFile(stderr, 41361e604812fad85bb96f757a2393015ae3d061c39acristy "%s%s%s:%.20g.%.20g #%.20g => Changed %.20g", 4137042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy v_info,CommandOptionToMnemonic(MagickMorphologyOptions, 4138a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive),(this_kernel == rflt_kernel ) ? "*" : "", 4139e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy (double) (method_loop+kernel_loop-1),(double) kernel_number, 4140e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy (double) count,(double) changed); 414147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 4142a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( changed < 0 ) 4143a8843c1f815ffad2568ec592d5b446cb1476aab5anthony goto error_cleanup; 4144a8843c1f815ffad2568ec592d5b446cb1476aab5anthony kernel_changed += changed; 4145a8843c1f815ffad2568ec592d5b446cb1476aab5anthony method_changed += changed; 4146a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 41479eb4f74649b23c053b308ce1152dce51239450baanthony /* prepare next loop */ 41489eb4f74649b23c053b308ce1152dce51239450baanthony { Image *tmp = work_image; /* swap images for iteration */ 41499eb4f74649b23c053b308ce1152dce51239450baanthony work_image = curr_image; 41509eb4f74649b23c053b308ce1152dce51239450baanthony curr_image = tmp; 41519eb4f74649b23c053b308ce1152dce51239450baanthony } 41529eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image == image ) 415347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = (Image *) NULL; /* replace input 'image' */ 41549eb4f74649b23c053b308ce1152dce51239450baanthony 4155a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* End Loop 4: Iterate the kernel with primitive */ 41567a01dcf50ce12cb2a789bedff51e9345f022432eanthony 41577bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) && kernel_changed != (size_t)changed ) 41585acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " Total %.20g",(double) kernel_changed); 41597bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) && stage_loop < stage_limit ) 41605acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line before looping */ 41619eb4f74649b23c053b308ce1152dce51239450baanthony 416247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony#if 0 41635acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "--E-- image=0x%lx\n", (unsigned long)image); 41645acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " curr =0x%lx\n", (unsigned long)curr_image); 41655acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " work =0x%lx\n", (unsigned long)work_image); 41665acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " save =0x%lx\n", (unsigned long)save_image); 41675acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " union=0x%lx\n", (unsigned long)rslt_image); 416847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony#endif 41691b2bc0a7da432e6e1cc0480280402df213faa940anthony 417047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 3: Primative (staging) Loop for Coumpound Methods */ 41711b2bc0a7da432e6e1cc0480280402df213faa940anthony 417247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Final Post-processing for some Compound Methods 417347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** 417447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** The removal of any 'Sync' channel flag in the Image Compositon 417547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** below ensures the methematical compose method is applied in a 417647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** purely mathematical way, and only to the selected channels. 417747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Turn off SVG composition 'alpha blending'. 417847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 417947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch( method ) { 418047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeOutMorphology: 418147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeInMorphology: 418247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: 418347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 41847bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 4185e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy (void) FormatLocaleFile(stderr, 4186e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy "\n%s: Difference with original image",CommandOptionToMnemonic( 4187e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy MagickMorphologyOptions, method) ); 4188feb3e9695150978a5d2372d3fe2f60466a7c8066cristy (void) CompositeImage(curr_image,image,DifferenceCompositeOp, 418939172408bad7ef2ef00a815fa9abf9979e7857cbcristy MagickTrue,0,0,exception); 419047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 419147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: 41927bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 4193e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy (void) FormatLocaleFile(stderr, 4194e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy "\n%s: Difference of Dilate and Erode",CommandOptionToMnemonic( 4195e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy MagickMorphologyOptions, method) ); 4196feb3e9695150978a5d2372d3fe2f60466a7c8066cristy (void) CompositeImage(curr_image,save_image,DifferenceCompositeOp, 419739172408bad7ef2ef00a815fa9abf9979e7857cbcristy MagickTrue,0,0,exception); 419847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = DestroyImage(save_image); /* finished with save image */ 419947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 420047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 420147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 4202602ab9b30b644a78a4057da93d838a77391ec0acanthony } 42039eb4f74649b23c053b308ce1152dce51239450baanthony 420447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* multi-kernel handling: re-iterate, or compose results */ 420547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( kernel->next == (KernelInfo *) NULL ) 4206c3e48258f3253188894e783dcdfd03562f7ab2c5anthony rslt_image = curr_image; /* just return the resulting image */ 420747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else if ( rslt_compose == NoCompositeOp ) 42087bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony { if ( IfMagickTrue(verbose) ) { 4209c3e48258f3253188894e783dcdfd03562f7ab2c5anthony if ( this_kernel->next != (KernelInfo *) NULL ) 42105acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (re-iterate)"); 4211c3e48258f3253188894e783dcdfd03562f7ab2c5anthony else 42125acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (done)"); 4213c3e48258f3253188894e783dcdfd03562f7ab2c5anthony } 4214c3e48258f3253188894e783dcdfd03562f7ab2c5anthony rslt_image = curr_image; /* return result, and re-iterate */ 42159eb4f74649b23c053b308ce1152dce51239450baanthony } 421647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else if ( rslt_image == (Image *) NULL) 42177bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony { if ( IfMagickTrue(verbose) ) 42185acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (save for compose)"); 421947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_image = curr_image; 422047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; /* continue with original image */ 42219eb4f74649b23c053b308ce1152dce51239450baanthony } 422247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else 4223ea61f01656bb0f9074677452017cc559e54093faanthony { /* Add the new 'current' result to the composition 422447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** 422547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** The removal of any 'Sync' channel flag in the Image Compositon 422647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** below ensures the methematical compose method is applied in a 422747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** purely mathematical way, and only to the selected channels. 4228ea61f01656bb0f9074677452017cc559e54093faanthony ** IE: Turn off SVG composition 'alpha blending'. 422947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 42307bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 42315acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (compose \"%s\")", 4232feb3e9695150978a5d2372d3fe2f60466a7c8066cristy CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) ); 423339172408bad7ef2ef00a815fa9abf9979e7857cbcristy (void) CompositeImage(rslt_image,curr_image,rslt_compose,MagickTrue, 4234feb3e9695150978a5d2372d3fe2f60466a7c8066cristy 0,0,exception); 42350bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony curr_image = DestroyImage(curr_image); 423647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; /* continue with original image */ 423747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 42387bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 42395acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); 42404fd27e21043be809d66c8202e779255e5b660d2danthony 424147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* loop to the next kernel in a multi-kernel list */ 424247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony norm_kernel = norm_kernel->next; 424347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rflt_kernel != (KernelInfo *) NULL ) 424447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rflt_kernel = rflt_kernel->next; 424547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number++; 424647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 2: Loop over each kernel */ 42479eb4f74649b23c053b308ce1152dce51239450baanthony 424847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 1: compound method interation */ 4249602ab9b30b644a78a4057da93d838a77391ec0acanthony 42509eb4f74649b23c053b308ce1152dce51239450baanthony goto exit_cleanup; 42511b2bc0a7da432e6e1cc0480280402df213faa940anthony 425247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Yes goto's are bad, but it makes cleanup lot more efficient */ 42531b2bc0a7da432e6e1cc0480280402df213faa940anthonyerror_cleanup: 4254ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image == rslt_image ) 4255ea61f01656bb0f9074677452017cc559e54093faanthony curr_image = (Image *) NULL; 425647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rslt_image != (Image *) NULL ) 425747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_image = DestroyImage(rslt_image); 42581b2bc0a7da432e6e1cc0480280402df213faa940anthonyexit_cleanup: 4259ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image == rslt_image || curr_image == image ) 4260ea61f01656bb0f9074677452017cc559e54093faanthony curr_image = (Image *) NULL; 4261ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image != (Image *) NULL ) 426247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = DestroyImage(curr_image); 42639eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image != (Image *) NULL ) 426447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = DestroyImage(work_image); 42659eb4f74649b23c053b308ce1152dce51239450baanthony if ( save_image != (Image *) NULL ) 426647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = DestroyImage(save_image); 426747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( reflected_kernel != (KernelInfo *) NULL ) 426847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = DestroyKernelInfo(reflected_kernel); 426947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return(rslt_image); 42709eb4f74649b23c053b308ce1152dce51239450baanthony} 4271a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 42729eb4f74649b23c053b308ce1152dce51239450baanthony 42739eb4f74649b23c053b308ce1152dce51239450baanthony/* 42749eb4f74649b23c053b308ce1152dce51239450baanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 42759eb4f74649b23c053b308ce1152dce51239450baanthony% % 42769eb4f74649b23c053b308ce1152dce51239450baanthony% % 42779eb4f74649b23c053b308ce1152dce51239450baanthony% % 4278f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% M o r p h o l o g y I m a g e % 42799eb4f74649b23c053b308ce1152dce51239450baanthony% % 42809eb4f74649b23c053b308ce1152dce51239450baanthony% % 42819eb4f74649b23c053b308ce1152dce51239450baanthony% % 42829eb4f74649b23c053b308ce1152dce51239450baanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 42839eb4f74649b23c053b308ce1152dce51239450baanthony% 4284f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% MorphologyImage() applies a user supplied kernel to the image 42859eb4f74649b23c053b308ce1152dce51239450baanthony% according to the given mophology method. 42869eb4f74649b23c053b308ce1152dce51239450baanthony% 42879eb4f74649b23c053b308ce1152dce51239450baanthony% This function applies any and all user defined settings before calling 42889eb4f74649b23c053b308ce1152dce51239450baanthony% the above internal function MorphologyApply(). 42899eb4f74649b23c053b308ce1152dce51239450baanthony% 42909eb4f74649b23c053b308ce1152dce51239450baanthony% User defined settings include... 429122de2722b682eb405b60ec6022a7546df994674eanthony% * Output Bias for Convolution and correlation ("-define convolve:bias=??") 429222de2722b682eb405b60ec6022a7546df994674eanthony% * Kernel Scale/normalize settings ("-define convolve:scale=??") 429346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This can also includes the addition of a scaled unity kernel. 429422de2722b682eb405b60ec6022a7546df994674eanthony% * Show Kernel being applied ("-define showkernel=1") 429522de2722b682eb405b60ec6022a7546df994674eanthony% 429622de2722b682eb405b60ec6022a7546df994674eanthony% Other operators that do not want user supplied options interfering, 429722de2722b682eb405b60ec6022a7546df994674eanthony% especially "convolve:bias" and "showkernel" should use MorphologyApply() 429822de2722b682eb405b60ec6022a7546df994674eanthony% directly. 42999eb4f74649b23c053b308ce1152dce51239450baanthony% 43009eb4f74649b23c053b308ce1152dce51239450baanthony% The format of the MorphologyImage method is: 43019eb4f74649b23c053b308ce1152dce51239450baanthony% 43029eb4f74649b23c053b308ce1152dce51239450baanthony% Image *MorphologyImage(const Image *image,MorphologyMethod method, 4303bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% const ssize_t iterations,KernelInfo *kernel,ExceptionInfo *exception) 43049eb4f74649b23c053b308ce1152dce51239450baanthony% 43059eb4f74649b23c053b308ce1152dce51239450baanthony% A description of each parameter follows: 43069eb4f74649b23c053b308ce1152dce51239450baanthony% 43079eb4f74649b23c053b308ce1152dce51239450baanthony% o image: the image. 43089eb4f74649b23c053b308ce1152dce51239450baanthony% 43099eb4f74649b23c053b308ce1152dce51239450baanthony% o method: the morphology method to be applied. 43109eb4f74649b23c053b308ce1152dce51239450baanthony% 43119eb4f74649b23c053b308ce1152dce51239450baanthony% o iterations: apply the operation this many times (or no change). 43129eb4f74649b23c053b308ce1152dce51239450baanthony% A value of -1 means loop until no change found. 43139eb4f74649b23c053b308ce1152dce51239450baanthony% How this is applied may depend on the morphology method. 43149eb4f74649b23c053b308ce1152dce51239450baanthony% Typically this is a value of 1. 43159eb4f74649b23c053b308ce1152dce51239450baanthony% 43169eb4f74649b23c053b308ce1152dce51239450baanthony% o kernel: An array of double representing the morphology kernel. 43179eb4f74649b23c053b308ce1152dce51239450baanthony% Warning: kernel may be normalized for the Convolve method. 43189eb4f74649b23c053b308ce1152dce51239450baanthony% 43199eb4f74649b23c053b308ce1152dce51239450baanthony% o exception: return any errors or warnings in this structure. 43209eb4f74649b23c053b308ce1152dce51239450baanthony% 43219eb4f74649b23c053b308ce1152dce51239450baanthony*/ 4322f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristyMagickExport Image *MorphologyImage(const Image *image, 4323f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method,const ssize_t iterations, 4324f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const KernelInfo *kernel,ExceptionInfo *exception) 43259eb4f74649b23c053b308ce1152dce51239450baanthony{ 43269eb4f74649b23c053b308ce1152dce51239450baanthony KernelInfo 43279eb4f74649b23c053b308ce1152dce51239450baanthony *curr_kernel; 43289eb4f74649b23c053b308ce1152dce51239450baanthony 432947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony CompositeOperator 433047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony compose; 433147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 43329eb4f74649b23c053b308ce1152dce51239450baanthony Image 43339eb4f74649b23c053b308ce1152dce51239450baanthony *morphology_image; 43349eb4f74649b23c053b308ce1152dce51239450baanthony 4335f46d42620631d2581e0b6a56456e203e17c427c8anthony double 4336f46d42620631d2581e0b6a56456e203e17c427c8anthony bias; 43379eb4f74649b23c053b308ce1152dce51239450baanthony 433822de2722b682eb405b60ec6022a7546df994674eanthony curr_kernel = (KernelInfo *) kernel; 433922de2722b682eb405b60ec6022a7546df994674eanthony bias=0.0; 4340d228c03fa334bae897eee6c2d8721fa48e1577bacristy compose = UndefinedCompositeOp; /* use default for method */ 434122de2722b682eb405b60ec6022a7546df994674eanthony 434246a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Apply Convolve/Correlate Normalization and Scaling Factors. 434346a369d839971ab627bdb31a93d8bd63e81b65a3anthony * This is done BEFORE the ShowKernelInfo() function is called so that 434446a369d839971ab627bdb31a93d8bd63e81b65a3anthony * users can see the results of the 'option:convolve:scale' option. 43459eb4f74649b23c053b308ce1152dce51239450baanthony */ 434622de2722b682eb405b60ec6022a7546df994674eanthony if ( method == ConvolveMorphology || method == CorrelateMorphology ) { 434728ad1d779b6ca95852e860514185a7a97e06af77anthony const char 434828ad1d779b6ca95852e860514185a7a97e06af77anthony *artifact; 4349f46d42620631d2581e0b6a56456e203e17c427c8anthony 435022de2722b682eb405b60ec6022a7546df994674eanthony /* Get the bias value as it will be needed */ 435122de2722b682eb405b60ec6022a7546df994674eanthony artifact = GetImageArtifact(image,"convolve:bias"); 435222de2722b682eb405b60ec6022a7546df994674eanthony if ( artifact != (const char *) NULL) { 435322de2722b682eb405b60ec6022a7546df994674eanthony if (IfMagickFalse(IsGeometry(artifact))) 435422de2722b682eb405b60ec6022a7546df994674eanthony (void) ThrowMagickException(exception,GetMagickModule(), 435522de2722b682eb405b60ec6022a7546df994674eanthony OptionWarning,"InvalidSetting","'%s' '%s'", 435622de2722b682eb405b60ec6022a7546df994674eanthony "convolve:bias",artifact); 435722de2722b682eb405b60ec6022a7546df994674eanthony else 435822de2722b682eb405b60ec6022a7546df994674eanthony bias=StringToDoubleInterval(artifact,(double) QuantumRange+1.0); 435922de2722b682eb405b60ec6022a7546df994674eanthony } 436022de2722b682eb405b60ec6022a7546df994674eanthony 436122de2722b682eb405b60ec6022a7546df994674eanthony /* Scale kernel according to user wishes */ 43629eb4f74649b23c053b308ce1152dce51239450baanthony artifact = GetImageArtifact(image,"convolve:scale"); 4363e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony if ( artifact != (const char *)NULL ) { 436422de2722b682eb405b60ec6022a7546df994674eanthony if (IfMagickFalse(IsGeometry(artifact))) 436522de2722b682eb405b60ec6022a7546df994674eanthony (void) ThrowMagickException(exception,GetMagickModule(), 436622de2722b682eb405b60ec6022a7546df994674eanthony OptionWarning,"InvalidSetting","'%s' '%s'", 436722de2722b682eb405b60ec6022a7546df994674eanthony "convolve:scale",artifact); 436822de2722b682eb405b60ec6022a7546df994674eanthony else { 436922de2722b682eb405b60ec6022a7546df994674eanthony if ( curr_kernel == kernel ) 437022de2722b682eb405b60ec6022a7546df994674eanthony curr_kernel = CloneKernelInfo(kernel); 437122de2722b682eb405b60ec6022a7546df994674eanthony if (curr_kernel == (KernelInfo *) NULL) 437222de2722b682eb405b60ec6022a7546df994674eanthony return((Image *) NULL); 437322de2722b682eb405b60ec6022a7546df994674eanthony ScaleGeometryKernelInfo(curr_kernel, artifact); 43749eb4f74649b23c053b308ce1152dce51239450baanthony } 43759eb4f74649b23c053b308ce1152dce51239450baanthony } 43769eb4f74649b23c053b308ce1152dce51239450baanthony } 43779eb4f74649b23c053b308ce1152dce51239450baanthony 43789eb4f74649b23c053b308ce1152dce51239450baanthony /* display the (normalized) kernel via stderr */ 437948656f2d1ca9ac9979eac32052e4cdc4958c9010cristy if ( IfStringTrue(GetImageArtifact(image,"showkernel")) 438048656f2d1ca9ac9979eac32052e4cdc4958c9010cristy || IfStringTrue(GetImageArtifact(image,"convolve:showkernel")) 438148656f2d1ca9ac9979eac32052e4cdc4958c9010cristy || IfStringTrue(GetImageArtifact(image,"morphology:showkernel")) ) 43829eb4f74649b23c053b308ce1152dce51239450baanthony ShowKernelInfo(curr_kernel); 43839eb4f74649b23c053b308ce1152dce51239450baanthony 43843206678d008425bc56dd2dbad002f2bb26299dc2anthony /* Override the default handling of multi-kernel morphology results 43853206678d008425bc56dd2dbad002f2bb26299dc2anthony * If 'Undefined' use the default method 43863206678d008425bc56dd2dbad002f2bb26299dc2anthony * If 'None' (default for 'Convolve') re-iterate previous result 43873206678d008425bc56dd2dbad002f2bb26299dc2anthony * Otherwise merge resulting images using compose method given. 43883206678d008425bc56dd2dbad002f2bb26299dc2anthony * Default for 'HitAndMiss' is 'Lighten'. 438947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 439028ad1d779b6ca95852e860514185a7a97e06af77anthony { const char 439128ad1d779b6ca95852e860514185a7a97e06af77anthony *artifact; 439222de2722b682eb405b60ec6022a7546df994674eanthony ssize_t 439322de2722b682eb405b60ec6022a7546df994674eanthony parse; 439422de2722b682eb405b60ec6022a7546df994674eanthony 4395f46d42620631d2581e0b6a56456e203e17c427c8anthony artifact = GetImageArtifact(image,"morphology:compose"); 439622de2722b682eb405b60ec6022a7546df994674eanthony if ( artifact != (const char *) NULL) { 439722de2722b682eb405b60ec6022a7546df994674eanthony parse=ParseCommandOption(MagickComposeOptions, 439870b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy MagickFalse,artifact); 439922de2722b682eb405b60ec6022a7546df994674eanthony if ( parse < 0 ) 440022de2722b682eb405b60ec6022a7546df994674eanthony (void) ThrowMagickException(exception,GetMagickModule(), 440122de2722b682eb405b60ec6022a7546df994674eanthony OptionWarning,"UnrecognizedComposeOperator","'%s' '%s'", 440222de2722b682eb405b60ec6022a7546df994674eanthony "morphology:compose",artifact); 440322de2722b682eb405b60ec6022a7546df994674eanthony else 440422de2722b682eb405b60ec6022a7546df994674eanthony compose=(CompositeOperator)parse; 440522de2722b682eb405b60ec6022a7546df994674eanthony } 440628ad1d779b6ca95852e860514185a7a97e06af77anthony } 44079eb4f74649b23c053b308ce1152dce51239450baanthony /* Apply the Morphology */ 4408f46d42620631d2581e0b6a56456e203e17c427c8anthony morphology_image = MorphologyApply(image,method,iterations, 4409f46d42620631d2581e0b6a56456e203e17c427c8anthony curr_kernel,compose,bias,exception); 44109eb4f74649b23c053b308ce1152dce51239450baanthony 44119eb4f74649b23c053b308ce1152dce51239450baanthony /* Cleanup and Exit */ 44129eb4f74649b23c053b308ce1152dce51239450baanthony if ( curr_kernel != kernel ) 44131b2bc0a7da432e6e1cc0480280402df213faa940anthony curr_kernel=DestroyKernelInfo(curr_kernel); 44149eb4f74649b23c053b308ce1152dce51239450baanthony return(morphology_image); 44159eb4f74649b23c053b308ce1152dce51239450baanthony} 441683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 441783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony/* 441883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 441983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 442083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 442183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 44224fd27e21043be809d66c8202e779255e5b660d2danthony+ R o t a t e K e r n e l I n f o % 442383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 442483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 442583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 442683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 442783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 442846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% RotateKernelInfo() rotates the kernel by the angle given. 442946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 443046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Currently it is restricted to 90 degree angles, of either 1D kernels 443146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% or square kernels. And 'circular' rotations of 45 degrees for 3x3 kernels. 443246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% It will ignore usless rotations for specific 'named' built-in kernels. 443383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 44344fd27e21043be809d66c8202e779255e5b660d2danthony% The format of the RotateKernelInfo method is: 443583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 44364fd27e21043be809d66c8202e779255e5b660d2danthony% void RotateKernelInfo(KernelInfo *kernel, double angle) 443783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 443883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A description of each parameter follows: 443983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 444083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o kernel: the Morphology/Convolution kernel 444183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 444283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o angle: angle to rotate in degrees 444383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 444446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This function is currently internal to this module only, but can be exported 444546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% to other modules if needed. 444683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony*/ 44474fd27e21043be809d66c8202e779255e5b660d2danthonystatic void RotateKernelInfo(KernelInfo *kernel, double angle) 444883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony{ 44491b2bc0a7da432e6e1cc0480280402df213faa940anthony /* angle the lower kernels first */ 44501b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 44511b2bc0a7da432e6e1cc0480280402df213faa940anthony RotateKernelInfo(kernel->next, angle); 44521b2bc0a7da432e6e1cc0480280402df213faa940anthony 445383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* WARNING: Currently assumes the kernel (rightly) is horizontally symetrical 445483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony ** 445583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony ** TODO: expand beyond simple 90 degree rotates, flips and flops 445683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony */ 445783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 445883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* Modulus the angle */ 445983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle = fmod(angle, 360.0); 446083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( angle < 0 ) 446183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle += 360.0; 446283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 44633c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 337.5 < angle || angle <= 22.5 ) 446443c4925e5305a26e48d68f7893e94f55d0831c39anthony return; /* Near zero angle - no change! - At least not at this time */ 446583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 44663dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* Handle special cases */ 446783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony switch (kernel->type) { 446883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These built-in kernels are cylindrical kernels, rotating is useless */ 446983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case GaussianKernel: 4470501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 4471501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 447283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case DiskKernel: 44733dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case PeaksKernel: 44743dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case LaplacianKernel: 447583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case ChebyshevKernel: 4476bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 447783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case EuclideanKernel: 447883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 447983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 448083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These may be rotatable at non-90 angles in the future */ 448183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* but simply rotating them in multiples of 90 degrees is useless */ 448283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case SquareKernel: 448383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case DiamondKernel: 448483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case PlusKernel: 44853dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case CrossKernel: 448683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 448783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 448883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These only allows a +/-90 degree rotation (by transpose) */ 448983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* A 180 degree rotation is useless */ 449083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case BlurKernel: 449183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 135.0 < angle && angle <= 225.0 ) 449283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 449383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 225.0 < angle && angle <= 315.0 ) 449483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle -= 180; 449583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony break; 449683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 44973dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony default: 449883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony break; 449983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 450057fe7a498c1302232dac8466864e84b12fad0807anthony /* Attempt rotations by 45 degrees -- 3x3 kernels only */ 45013c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 ) 45023c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { 45033c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( kernel->width == 3 && kernel->height == 3 ) 45043c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { /* Rotate a 3x3 square by 45 degree angle */ 4505a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy double t = kernel->values[0]; 450643c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[0] = kernel->values[3]; 450743c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[3] = kernel->values[6]; 450843c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[6] = kernel->values[7]; 450943c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[7] = kernel->values[8]; 451043c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[8] = kernel->values[5]; 451143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[5] = kernel->values[2]; 451243c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[2] = kernel->values[1]; 451343c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[1] = t; 45141d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* rotate non-centered origin */ 45151d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( kernel->x != 1 || kernel->y != 1 ) { 4516bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t x,y; 4517bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy x = (ssize_t) kernel->x-1; 4518bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy y = (ssize_t) kernel->y-1; 45191d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( x == y ) x = 0; 45201d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( x == 0 ) x = -y; 45211d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( x == -y ) y = 0; 45221d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( y == 0 ) y = x; 4523ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->x = (ssize_t) x+1; 4524ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->y = (ssize_t) y+1; 45251d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 452643c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+315.0, 360.0); /* angle reduced 45 degrees */ 452743c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+45.0, 360.0); 45283c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 45293c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else 45303c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony perror("Unable to rotate non-3x3 kernel by 45 degrees"); 45313c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 45323c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 45.0 < fmod(angle, 180.0) && fmod(angle,180.0) <= 135.0 ) 45333c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { 45343c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( kernel->width == 1 || kernel->height == 1 ) 45354c08aed51c5899665ade97263692328eea4af106cristy { /* Do a transpose of a 1 dimensional kernel, 4536bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ** which results in a fast 90 degree rotation of some type. 45373c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony */ 4538bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t 45393c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony t; 4540bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy t = (ssize_t) kernel->width; 45413c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->width = kernel->height; 4542bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t) t; 45433c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony t = kernel->x; 45443c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->x = kernel->y; 45453c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->y = t; 454643c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( kernel->width == 1 ) { 454743c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+270.0, 360.0); /* angle reduced 90 degrees */ 454843c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+90.0, 360.0); 454943c4925e5305a26e48d68f7893e94f55d0831c39anthony } else { 455043c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+90.0, 360.0); /* angle increased 90 degrees */ 455143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+270.0, 360.0); 455243c4925e5305a26e48d68f7893e94f55d0831c39anthony } 45533c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 45543c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else if ( kernel->width == kernel->height ) 45553c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { /* Rotate a square array of values by 90 degrees */ 4556d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy { register ssize_t 45571d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony i,j,x,y; 4558d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 4559d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register MagickRealType 45601d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony *k,t; 4561d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 45621d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k=kernel->values; 4563d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy for( i=0, x=(ssize_t) kernel->width-1; i<=x; i++, x--) 4564d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy for( j=0, y=(ssize_t) kernel->height-1; j<y; j++, y--) 45651d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony { t = k[i+j*kernel->width]; 45661d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[i+j*kernel->width] = k[j+x*kernel->width]; 45671d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[j+x*kernel->width] = k[x+y*kernel->width]; 45681d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[x+y*kernel->width] = k[y+i*kernel->width]; 45691d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[y+i*kernel->width] = t; 45701d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 45711d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 45721d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* rotate the origin - relative to center of array */ 4573bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy { register ssize_t x,y; 4574eaedf06777741da32408da72c1e512975c600c48cristy x = (ssize_t) (kernel->x*2-kernel->width+1); 4575eaedf06777741da32408da72c1e512975c600c48cristy y = (ssize_t) (kernel->y*2-kernel->height+1); 4576ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->x = (ssize_t) ( -y +(ssize_t) kernel->width-1)/2; 4577ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->y = (ssize_t) ( +x +(ssize_t) kernel->height-1)/2; 45781d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 457943c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+270.0, 360.0); /* angle reduced 90 degrees */ 458043c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+90.0, 360.0); 45813c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 45823c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else 45833c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony perror("Unable to rotate a non-square, non-linear kernel 90 degrees"); 45843c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 458583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 135.0 < angle && angle <= 225.0 ) 458683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony { 458743c4925e5305a26e48d68f7893e94f55d0831c39anthony /* For a 180 degree rotation - also know as a reflection 458843c4925e5305a26e48d68f7893e94f55d0831c39anthony * This is actually a very very common operation! 458943c4925e5305a26e48d68f7893e94f55d0831c39anthony * Basically all that is needed is a reversal of the kernel data! 459043c4925e5305a26e48d68f7893e94f55d0831c39anthony * And a reflection of the origon 459143c4925e5305a26e48d68f7893e94f55d0831c39anthony */ 4592a96f2494a8e79144a225056be9545cc75e868137cristy double 4593a96f2494a8e79144a225056be9545cc75e868137cristy t; 4594a96f2494a8e79144a225056be9545cc75e868137cristy 4595d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register MagickRealType 4596a96f2494a8e79144a225056be9545cc75e868137cristy *k; 4597a96f2494a8e79144a225056be9545cc75e868137cristy 4598a96f2494a8e79144a225056be9545cc75e868137cristy ssize_t 4599a96f2494a8e79144a225056be9545cc75e868137cristy i, 4600a96f2494a8e79144a225056be9545cc75e868137cristy j; 460183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 460283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony k=kernel->values; 4603e42f658533644aecb733785ffd91b286d6778deacristy j=(ssize_t) (kernel->width*kernel->height-1); 4604e42f658533644aecb733785ffd91b286d6778deacristy for (i=0; i < j; i++, j--) 460583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony t=k[i], k[i]=k[j], k[j]=t; 460683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 4607bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) kernel->width - kernel->x - 1; 4608bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = (ssize_t) kernel->height - kernel->y - 1; 460943c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle-180.0, 360.0); /* angle+180 degrees */ 461043c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+180.0, 360.0); 461183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 46123c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony /* At this point angle should at least between -45 (315) and +45 degrees 461383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony * In the future some form of non-orthogonal angled rotates could be 461483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony * performed here, posibily with a linear kernel restriction. 461583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony */ 461683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 461783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 461883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony} 461983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 462083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony/* 462183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 462283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 462383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 462483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 462546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% S c a l e G e o m e t r y K e r n e l I n f o % 462646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 462746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 462846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 462946a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 463046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 463146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% ScaleGeometryKernelInfo() takes a geometry argument string, typically 463246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% provided as a "-set option:convolve:scale {geometry}" user setting, 463346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% and modifies the kernel according to the parsed arguments of that setting. 463446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 463546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The first argument (and any normalization flags) are passed to 463646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% ScaleKernelInfo() to scale/normalize the kernel. The second argument 463746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% is then passed to UnityAddKernelInfo() to add a scled unity kernel 463846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% into the scaled/normalized kernel. 463946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 4640ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% The format of the ScaleGeometryKernelInfo method is: 464146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 4642ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% void ScaleGeometryKernelInfo(KernelInfo *kernel, 4643ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% const double scaling_factor,const MagickStatusType normalize_flags) 464446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 464546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% A description of each parameter follows: 464646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 464746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o kernel: the Morphology/Convolution kernel to modify 464846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 464946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o geometry: 465046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The geometry string to parse, typically from the user provided 465146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% "-set option:convolve:scale {geometry}" setting. 465246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 465346a369d839971ab627bdb31a93d8bd63e81b65a3anthony*/ 465446a369d839971ab627bdb31a93d8bd63e81b65a3anthonyMagickExport void ScaleGeometryKernelInfo (KernelInfo *kernel, 465546a369d839971ab627bdb31a93d8bd63e81b65a3anthony const char *geometry) 465646a369d839971ab627bdb31a93d8bd63e81b65a3anthony{ 465722de2722b682eb405b60ec6022a7546df994674eanthony //GeometryFlags 4658ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy MagickStatusType 465946a369d839971ab627bdb31a93d8bd63e81b65a3anthony flags; 4660ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy 466146a369d839971ab627bdb31a93d8bd63e81b65a3anthony GeometryInfo 466246a369d839971ab627bdb31a93d8bd63e81b65a3anthony args; 466346a369d839971ab627bdb31a93d8bd63e81b65a3anthony 466446a369d839971ab627bdb31a93d8bd63e81b65a3anthony SetGeometryInfo(&args); 466522de2722b682eb405b60ec6022a7546df994674eanthony flags = ParseGeometry(geometry, &args); 466646a369d839971ab627bdb31a93d8bd63e81b65a3anthony 466746a369d839971ab627bdb31a93d8bd63e81b65a3anthony#if 0 466846a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* For Debugging Geometry Input */ 46695acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", 467046a369d839971ab627bdb31a93d8bd63e81b65a3anthony flags, args.rho, args.sigma, args.xi, args.psi ); 467146a369d839971ab627bdb31a93d8bd63e81b65a3anthony#endif 467246a369d839971ab627bdb31a93d8bd63e81b65a3anthony 467346a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & PercentValue) != 0 ) /* Handle Percentage flag*/ 467446a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.rho *= 0.01, args.sigma *= 0.01; 467546a369d839971ab627bdb31a93d8bd63e81b65a3anthony 467646a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & RhoValue) == 0 ) /* Set Defaults for missing args */ 467746a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.rho = 1.0; 467846a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & SigmaValue) == 0 ) 467946a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.sigma = 0.0; 468046a369d839971ab627bdb31a93d8bd63e81b65a3anthony 468146a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Scale/Normalize the input kernel */ 4682d228c03fa334bae897eee6c2d8721fa48e1577bacristy ScaleKernelInfo(kernel, args.rho, (GeometryFlags) flags); 468346a369d839971ab627bdb31a93d8bd63e81b65a3anthony 468446a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Add Unity Kernel, for blending with original */ 468546a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & SigmaValue) != 0 ) 468646a369d839971ab627bdb31a93d8bd63e81b65a3anthony UnityAddKernelInfo(kernel, args.sigma); 468746a369d839971ab627bdb31a93d8bd63e81b65a3anthony 468846a369d839971ab627bdb31a93d8bd63e81b65a3anthony return; 468946a369d839971ab627bdb31a93d8bd63e81b65a3anthony} 469046a369d839971ab627bdb31a93d8bd63e81b65a3anthony/* 469146a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 469246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 469346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 469446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 46956771f1e8987fa49f52d4176281a2e8524b8e31cbcristy% S c a l e K e r n e l I n f o % 4696cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4697cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4698cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4699cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4700cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 47011b2bc0a7da432e6e1cc0480280402df213faa940anthony% ScaleKernelInfo() scales the given kernel list by the given amount, with or 47021b2bc0a7da432e6e1cc0480280402df213faa940anthony% without normalization of the sum of the kernel values (as per given flags). 4703999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4704999bb2c20aa9d42875bb5adba44951988d4ae354anthony% By default (no flags given) the values within the kernel is scaled 47051b2bc0a7da432e6e1cc0480280402df213faa940anthony% directly using given scaling factor without change. 4706999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 470746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% If either of the two 'normalize_flags' are given the kernel will first be 470846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% normalized and then further scaled by the scaling factor value given. 4709999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4710999bb2c20aa9d42875bb5adba44951988d4ae354anthony% Kernel normalization ('normalize_flags' given) is designed to ensure that 4711999bb2c20aa9d42875bb5adba44951988d4ae354anthony% any use of the kernel scaling factor with 'Convolve' or 'Correlate' 47121b2bc0a7da432e6e1cc0480280402df213faa940anthony% morphology methods will fall into -1.0 to +1.0 range. Note that for 47131b2bc0a7da432e6e1cc0480280402df213faa940anthony% non-HDRI versions of IM this may cause images to have any negative results 47141b2bc0a7da432e6e1cc0480280402df213faa940anthony% clipped, unless some 'bias' is used. 4715999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4716999bb2c20aa9d42875bb5adba44951988d4ae354anthony% More specifically. Kernels which only contain positive values (such as a 4717999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 'Gaussian' kernel) will be scaled so that those values sum to +1.0, 47181b2bc0a7da432e6e1cc0480280402df213faa940anthony% ensuring a 0.0 to +1.0 output range for non-HDRI images. 4719999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4720999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For Kernels that contain some negative values, (such as 'Sharpen' kernels) 4721999bb2c20aa9d42875bb5adba44951988d4ae354anthony% the kernel will be scaled by the absolute of the sum of kernel values, so 4722999bb2c20aa9d42875bb5adba44951988d4ae354anthony% that it will generally fall within the +/- 1.0 range. 4723cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4724999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For kernels whose values sum to zero, (such as 'Laplician' kernels) kernel 4725999bb2c20aa9d42875bb5adba44951988d4ae354anthony% will be scaled by just the sum of the postive values, so that its output 4726999bb2c20aa9d42875bb5adba44951988d4ae354anthony% range will again fall into the +/- 1.0 range. 4727cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4728999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For special kernels designed for locating shapes using 'Correlate', (often 4729999bb2c20aa9d42875bb5adba44951988d4ae354anthony% only containing +1 and -1 values, representing foreground/brackground 4730999bb2c20aa9d42875bb5adba44951988d4ae354anthony% matching) a special normalization method is provided to scale the positive 47311e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp% values separately to those of the negative values, so the kernel will be 4732999bb2c20aa9d42875bb5adba44951988d4ae354anthony% forced to become a zero-sum kernel better suited to such searches. 4733999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 47341b2bc0a7da432e6e1cc0480280402df213faa940anthony% WARNING: Correct normalization of the kernel assumes that the '*_range' 4735999bb2c20aa9d42875bb5adba44951988d4ae354anthony% attributes within the kernel structure have been correctly set during the 4736999bb2c20aa9d42875bb5adba44951988d4ae354anthony% kernels creation. 4737999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4738999bb2c20aa9d42875bb5adba44951988d4ae354anthony% NOTE: The values used for 'normalize_flags' have been selected specifically 473946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% to match the use of geometry options, so that '!' means NormalizeValue, '^' 474046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% means CorrelateNormalizeValue. All other GeometryFlags values are ignored. 4741cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 47424fd27e21043be809d66c8202e779255e5b660d2danthony% The format of the ScaleKernelInfo method is: 4743cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4744999bb2c20aa9d42875bb5adba44951988d4ae354anthony% void ScaleKernelInfo(KernelInfo *kernel, const double scaling_factor, 4745999bb2c20aa9d42875bb5adba44951988d4ae354anthony% const MagickStatusType normalize_flags ) 4746cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4747cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% A description of each parameter follows: 4748cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4749cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% o kernel: the Morphology/Convolution kernel 4750cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4751999bb2c20aa9d42875bb5adba44951988d4ae354anthony% o scaling_factor: 4752999bb2c20aa9d42875bb5adba44951988d4ae354anthony% multiply all values (after normalization) by this factor if not 4753999bb2c20aa9d42875bb5adba44951988d4ae354anthony% zero. If the kernel is normalized regardless of any flags. 4754999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4755999bb2c20aa9d42875bb5adba44951988d4ae354anthony% o normalize_flags: 4756999bb2c20aa9d42875bb5adba44951988d4ae354anthony% GeometryFlags defining normalization method to use. 4757999bb2c20aa9d42875bb5adba44951988d4ae354anthony% specifically: NormalizeValue, CorrelateNormalizeValue, 4758999bb2c20aa9d42875bb5adba44951988d4ae354anthony% and/or PercentValue 4759cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4760cc6c836da2a53b6023b716e4973090a6714dc3b0anthony*/ 47616771f1e8987fa49f52d4176281a2e8524b8e31cbcristyMagickExport void ScaleKernelInfo(KernelInfo *kernel, 47626771f1e8987fa49f52d4176281a2e8524b8e31cbcristy const double scaling_factor,const GeometryFlags normalize_flags) 4763cc6c836da2a53b6023b716e4973090a6714dc3b0anthony{ 4764bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 4765cc6c836da2a53b6023b716e4973090a6714dc3b0anthony i; 4766cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4767999bb2c20aa9d42875bb5adba44951988d4ae354anthony register double 4768999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale, 4769999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale; 4770999bb2c20aa9d42875bb5adba44951988d4ae354anthony 477146a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 47721b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 47731b2bc0a7da432e6e1cc0480280402df213faa940anthony ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags); 47741b2bc0a7da432e6e1cc0480280402df213faa940anthony 477546a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Normalization of Kernel */ 4776999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = 1.0; 4777999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( (normalize_flags&NormalizeValue) != 0 ) { 4778b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(kernel->positive_range + kernel->negative_range) >= MagickEpsilon ) 4779f4e0031305baeb01c89cfd2842cbbec021883550anthony /* non-zero-summing kernel (generally positive) */ 4780999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = fabs(kernel->positive_range + kernel->negative_range); 4781cc6c836da2a53b6023b716e4973090a6714dc3b0anthony else 4782f4e0031305baeb01c89cfd2842cbbec021883550anthony /* zero-summing kernel */ 4783f4e0031305baeb01c89cfd2842cbbec021883550anthony pos_scale = kernel->positive_range; 4784999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 478546a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Force kernel into a normalized zero-summing kernel */ 4786999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) { 4787b978e458a8e1f210bcb580951cf623687236b2fecristy pos_scale = ( fabs(kernel->positive_range) >= MagickEpsilon ) 4788999bb2c20aa9d42875bb5adba44951988d4ae354anthony ? kernel->positive_range : 1.0; 4789b978e458a8e1f210bcb580951cf623687236b2fecristy neg_scale = ( fabs(kernel->negative_range) >= MagickEpsilon ) 4790999bb2c20aa9d42875bb5adba44951988d4ae354anthony ? -kernel->negative_range : 1.0; 4791999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 4792999bb2c20aa9d42875bb5adba44951988d4ae354anthony else 4793999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale = pos_scale; 4794999bb2c20aa9d42875bb5adba44951988d4ae354anthony 4795999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* finialize scaling_factor for positive and negative components */ 4796999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = scaling_factor/pos_scale; 4797999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale = scaling_factor/neg_scale; 4798cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4799bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++) 4800cc6c836da2a53b6023b716e4973090a6714dc3b0anthony if ( ! IsNan(kernel->values[i]) ) 4801999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale; 4802999bb2c20aa9d42875bb5adba44951988d4ae354anthony 4803999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* convolution output range */ 4804999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->positive_range *= pos_scale; 4805999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->negative_range *= neg_scale; 4806999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* maximum and minimum values in kernel */ 4807999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale; 4808999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale; 4809999bb2c20aa9d42875bb5adba44951988d4ae354anthony 481046a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* swap kernel settings if user's scaling factor is negative */ 4811999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( scaling_factor < MagickEpsilon ) { 4812999bb2c20aa9d42875bb5adba44951988d4ae354anthony double t; 4813999bb2c20aa9d42875bb5adba44951988d4ae354anthony t = kernel->positive_range; 4814999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->positive_range = kernel->negative_range; 4815999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->negative_range = t; 4816999bb2c20aa9d42875bb5adba44951988d4ae354anthony t = kernel->maximum; 4817999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->maximum = kernel->minimum; 4818999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->minimum = 1; 4819999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 4820cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4821cc6c836da2a53b6023b716e4973090a6714dc3b0anthony return; 4822cc6c836da2a53b6023b716e4973090a6714dc3b0anthony} 4823cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4824cc6c836da2a53b6023b716e4973090a6714dc3b0anthony/* 4825cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4826cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4827cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4828cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 482946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% S h o w K e r n e l I n f o % 483083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 483183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 483283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 483383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 483483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 48354fd27e21043be809d66c8202e779255e5b660d2danthony% ShowKernelInfo() outputs the details of the given kernel defination to 48364fd27e21043be809d66c8202e779255e5b660d2danthony% standard error, generally due to a users 'showkernel' option request. 483783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 483883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% The format of the ShowKernel method is: 483983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 484057fe7a498c1302232dac8466864e84b12fad0807anthony% void ShowKernelInfo(const KernelInfo *kernel) 484183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 484283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A description of each parameter follows: 484383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 484483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o kernel: the Morphology/Convolution kernel 484583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 484683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony*/ 4847433d11887841b922ec5e6805f9fdd240c320b92ecristyMagickPrivate void ShowKernelInfo(const KernelInfo *kernel) 484883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony{ 484957fe7a498c1302232dac8466864e84b12fad0807anthony const KernelInfo 48507a01dcf50ce12cb2a789bedff51e9345f022432eanthony *k; 48517a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4852bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 48537a01dcf50ce12cb2a789bedff51e9345f022432eanthony c, i, u, v; 48547a01dcf50ce12cb2a789bedff51e9345f022432eanthony 48557a01dcf50ce12cb2a789bedff51e9345f022432eanthony for (c=0, k=kernel; k != (KernelInfo *) NULL; c++, k=k->next ) { 48567a01dcf50ce12cb2a789bedff51e9345f022432eanthony 48575acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Kernel"); 48587a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( kernel->next != (KernelInfo *) NULL ) 48595acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " #%lu", (unsigned long) c ); 48605acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " \"%s", 4861042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickKernelOptions, k->type) ); 4862b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(k->angle) >= MagickEpsilon ) 48635acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "@%lg", k->angle); 48645acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\" of size %lux%lu%+ld%+ld",(unsigned long) 48651e604812fad85bb96f757a2393015ae3d061c39acristy k->width,(unsigned long) k->height,(long) k->x,(long) k->y); 48665acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, 48677a01dcf50ce12cb2a789bedff51e9345f022432eanthony " with values from %.*lg to %.*lg\n", 48687a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->minimum, 48697a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->maximum); 48705acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Forming a output range from %.*lg to %.*lg", 48717a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->negative_range, 487246a369d839971ab627bdb31a93d8bd63e81b65a3anthony GetMagickPrecision(), k->positive_range); 487346a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( fabs(k->positive_range+k->negative_range) < MagickEpsilon ) 48745acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Zero-Summing)\n"); 487546a369d839971ab627bdb31a93d8bd63e81b65a3anthony else if ( fabs(k->positive_range+k->negative_range-1.0) < MagickEpsilon ) 48765acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Normalized)\n"); 487746a369d839971ab627bdb31a93d8bd63e81b65a3anthony else 48785acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Sum %.*lg)\n", 487946a369d839971ab627bdb31a93d8bd63e81b65a3anthony GetMagickPrecision(), k->positive_range+k->negative_range); 488043c4925e5305a26e48d68f7893e94f55d0831c39anthony for (i=v=0; v < k->height; v++) { 48815acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%2lu:", (unsigned long) v ); 488243c4925e5305a26e48d68f7893e94f55d0831c39anthony for (u=0; u < k->width; u++, i++) 48837a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( IsNan(k->values[i]) ) 48845acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr," %*s", GetMagickPrecision()+3, "nan"); 48857a01dcf50ce12cb2a789bedff51e9345f022432eanthony else 48865acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr," %*.*lg", GetMagickPrecision()+3, 4887d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy GetMagickPrecision(), (double) k->values[i]); 48885acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr,"\n"); 48897a01dcf50ce12cb2a789bedff51e9345f022432eanthony } 489083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 489183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony} 4892cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4893cc6c836da2a53b6023b716e4973090a6714dc3b0anthony/* 4894cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4895cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4896cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4897cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 489843c4925e5305a26e48d68f7893e94f55d0831c39anthony% U n i t y A d d K e r n a l I n f o % 489943c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 490043c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 490143c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 490243c4925e5305a26e48d68f7893e94f55d0831c39anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 490343c4925e5305a26e48d68f7893e94f55d0831c39anthony% 490443c4925e5305a26e48d68f7893e94f55d0831c39anthony% UnityAddKernelInfo() Adds a given amount of the 'Unity' Convolution Kernel 490543c4925e5305a26e48d68f7893e94f55d0831c39anthony% to the given pre-scaled and normalized Kernel. This in effect adds that 490643c4925e5305a26e48d68f7893e94f55d0831c39anthony% amount of the original image into the resulting convolution kernel. This 490743c4925e5305a26e48d68f7893e94f55d0831c39anthony% value is usually provided by the user as a percentage value in the 490843c4925e5305a26e48d68f7893e94f55d0831c39anthony% 'convolve:scale' setting. 490943c4925e5305a26e48d68f7893e94f55d0831c39anthony% 4910501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% The resulting effect is to convert the defined kernels into blended 4911501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% soft-blurs, unsharp kernels or into sharpening kernels. 491243c4925e5305a26e48d68f7893e94f55d0831c39anthony% 491346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The format of the UnityAdditionKernelInfo method is: 491443c4925e5305a26e48d68f7893e94f55d0831c39anthony% 491543c4925e5305a26e48d68f7893e94f55d0831c39anthony% void UnityAdditionKernelInfo(KernelInfo *kernel, const double scale ) 491643c4925e5305a26e48d68f7893e94f55d0831c39anthony% 491743c4925e5305a26e48d68f7893e94f55d0831c39anthony% A description of each parameter follows: 491843c4925e5305a26e48d68f7893e94f55d0831c39anthony% 491943c4925e5305a26e48d68f7893e94f55d0831c39anthony% o kernel: the Morphology/Convolution kernel 492043c4925e5305a26e48d68f7893e94f55d0831c39anthony% 492143c4925e5305a26e48d68f7893e94f55d0831c39anthony% o scale: 492243c4925e5305a26e48d68f7893e94f55d0831c39anthony% scaling factor for the unity kernel to be added to 492343c4925e5305a26e48d68f7893e94f55d0831c39anthony% the given kernel. 492443c4925e5305a26e48d68f7893e94f55d0831c39anthony% 492543c4925e5305a26e48d68f7893e94f55d0831c39anthony*/ 492643c4925e5305a26e48d68f7893e94f55d0831c39anthonyMagickExport void UnityAddKernelInfo(KernelInfo *kernel, 492743c4925e5305a26e48d68f7893e94f55d0831c39anthony const double scale) 492843c4925e5305a26e48d68f7893e94f55d0831c39anthony{ 492946a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 493046a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( kernel->next != (KernelInfo *) NULL) 493146a369d839971ab627bdb31a93d8bd63e81b65a3anthony UnityAddKernelInfo(kernel->next, scale); 493243c4925e5305a26e48d68f7893e94f55d0831c39anthony 493346a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Add the scaled unity kernel to the existing kernel */ 493443c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[kernel->x+kernel->y*kernel->width] += scale; 493546a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* recalculate the meta-data */ 493643c4925e5305a26e48d68f7893e94f55d0831c39anthony 493743c4925e5305a26e48d68f7893e94f55d0831c39anthony return; 493843c4925e5305a26e48d68f7893e94f55d0831c39anthony} 493943c4925e5305a26e48d68f7893e94f55d0831c39anthony 494043c4925e5305a26e48d68f7893e94f55d0831c39anthony/* 494143c4925e5305a26e48d68f7893e94f55d0831c39anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 494243c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 494343c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 494443c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 494543c4925e5305a26e48d68f7893e94f55d0831c39anthony% Z e r o K e r n e l N a n s % 4946cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4947cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4948cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4949cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4950cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4951cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% ZeroKernelNans() replaces any special 'nan' value that may be present in 4952cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% the kernel with a zero value. This is typically done when the kernel will 4953cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% be used in special hardware (GPU) convolution processors, to simply 4954cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% matters. 4955cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4956cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% The format of the ZeroKernelNans method is: 4957cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 495846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% void ZeroKernelNans (KernelInfo *kernel) 4959cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4960cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% A description of each parameter follows: 4961cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4962cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% o kernel: the Morphology/Convolution kernel 4963cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4964cc6c836da2a53b6023b716e4973090a6714dc3b0anthony*/ 4965cf592636b16d028b14c5fa9dffdc3a94eae7c2f3cristyMagickPrivate void ZeroKernelNans(KernelInfo *kernel) 4966cc6c836da2a53b6023b716e4973090a6714dc3b0anthony{ 4967bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 4968cc6c836da2a53b6023b716e4973090a6714dc3b0anthony i; 4969cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 497046a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 49711b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 49721b2bc0a7da432e6e1cc0480280402df213faa940anthony ZeroKernelNans(kernel->next); 49731b2bc0a7da432e6e1cc0480280402df213faa940anthony 497443c4925e5305a26e48d68f7893e94f55d0831c39anthony for (i=0; i < (kernel->width*kernel->height); i++) 4975cc6c836da2a53b6023b716e4973090a6714dc3b0anthony if ( IsNan(kernel->values[i]) ) 4976cc6c836da2a53b6023b716e4973090a6714dc3b0anthony kernel->values[i] = 0.0; 4977cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4978cc6c836da2a53b6023b716e4973090a6714dc3b0anthony return; 4979cc6c836da2a53b6023b716e4973090a6714dc3b0anthony} 4980