morphology.c revision 6aeeb023536796b4af0b5f5ea370df33953a750e
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% % 20fe676ee3a9cf43404bdc9ba8b27f597b5e4e28f7cristy% Copyright 1999-2014 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" 556a2180cee55312a7c0c633670803f9face88a82acristy#include "MagickCore/channel.h" 564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color-private.h" 574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/enhance.h" 584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h" 594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h" 604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/gem.h" 618ea81224e9ff022e56eb2cddb12860a8b2e90411cristy#include "MagickCore/gem-private.h" 624c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/hashmap.h" 634c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h" 644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h" 654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/list.h" 664c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/magick.h" 674c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h" 68e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy#include "MagickCore/memory-private.h" 694c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h" 704c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/morphology.h" 714c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/morphology-private.h" 724c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/option.h" 734c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h" 74f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy#include "MagickCore/pixel-private.h" 754c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/prepress.h" 764c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantize.h" 77ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy#include "MagickCore/resource_.h" 784c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/registry.h" 794c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/semaphore.h" 804c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/splay-tree.h" 814c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/statistic.h" 824c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h" 834c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string-private.h" 8416881e68c6165c6191fc44151a8a4320e3dd1ffdcristy#include "MagickCore/thread-private.h" 854c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/token.h" 864c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/utility.h" 87d1dd6e4fefa0810b9893e6ac9418f79c97c1b39acristy#include "MagickCore/utility-private.h" 88a29d45f897949f04a47bb3da077395969f13dcbacristy 89c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony/* 90a29d45f897949f04a47bb3da077395969f13dcbacristy Other global definitions used by module. 91a29d45f897949f04a47bb3da077395969f13dcbacristy*/ 9229188a8682a98d4b7882cca434b170517555fc7danthonystatic inline double MagickMin(const double x,const double y) 9329188a8682a98d4b7882cca434b170517555fc7danthony{ 9429188a8682a98d4b7882cca434b170517555fc7danthony return( x < y ? x : y); 9529188a8682a98d4b7882cca434b170517555fc7danthony} 9629188a8682a98d4b7882cca434b170517555fc7danthonystatic inline double MagickMax(const double x,const double y) 9729188a8682a98d4b7882cca434b170517555fc7danthony{ 9829188a8682a98d4b7882cca434b170517555fc7danthony return( x > y ? x : y); 9929188a8682a98d4b7882cca434b170517555fc7danthony} 10029188a8682a98d4b7882cca434b170517555fc7danthony#define Minimize(assign,value) assign=MagickMin(assign,value) 10129188a8682a98d4b7882cca434b170517555fc7danthony#define Maximize(assign,value) assign=MagickMax(assign,value) 10229188a8682a98d4b7882cca434b170517555fc7danthony 10340ca0b982379d4ab2716435a46603d56b5b218b1anthony/* Integer Factorial Function - for a Binomial kernel */ 10440ca0b982379d4ab2716435a46603d56b5b218b1anthony#if 1 10540ca0b982379d4ab2716435a46603d56b5b218b1anthonystatic inline size_t fact(size_t n) 10640ca0b982379d4ab2716435a46603d56b5b218b1anthony{ 107f13c594b1d9509e479fd845c3b8a5bb1351c32eacristy size_t f,l; 10840ca0b982379d4ab2716435a46603d56b5b218b1anthony for(f=1, l=2; l <= n; f=f*l, l++); 10940ca0b982379d4ab2716435a46603d56b5b218b1anthony return(f); 11040ca0b982379d4ab2716435a46603d56b5b218b1anthony} 11140ca0b982379d4ab2716435a46603d56b5b218b1anthony#elif 1 /* glibc floating point alternatives */ 11240ca0b982379d4ab2716435a46603d56b5b218b1anthony#define fact(n) ((size_t)tgamma((double)n+1)) 11340ca0b982379d4ab2716435a46603d56b5b218b1anthony#else 11440ca0b982379d4ab2716435a46603d56b5b218b1anthony#define fact(n) ((size_t)lgamma((double)n+1)) 11540ca0b982379d4ab2716435a46603d56b5b218b1anthony#endif 11640ca0b982379d4ab2716435a46603d56b5b218b1anthony 11740ca0b982379d4ab2716435a46603d56b5b218b1anthony 118c4c86e0ad78bebf6b9f931a659fb82987a7042e3anthony/* Currently these are only internal to this module */ 119c4c86e0ad78bebf6b9f931a659fb82987a7042e3anthonystatic void 12046a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(KernelInfo *), 121bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(KernelInfo *), 122bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(KernelInfo *, const double), 123ef656913b0b30d713ae94c82c47693c9dc69c9f4cristy RotateKernelInfo(KernelInfo *, double); 124602ab9b30b644a78a4057da93d838a77391ec0acanthony 1253dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony 1263dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony/* Quick function to find last kernel in a kernel list */ 1273dd0f620e7a1d12f747ce167844cd7269bfa9f12anthonystatic inline KernelInfo *LastKernelInfo(KernelInfo *kernel) 1283dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony{ 1293dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony while (kernel->next != (KernelInfo *) NULL) 130c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk kernel=kernel->next; 1313dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony return(kernel); 1323dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony} 1333dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony 134602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 135602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 136602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 137602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 138602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 13983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A c q u i r e K e r n e l I n f o % 140602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 141602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 142602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 143602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 144602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1452be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% AcquireKernelInfo() takes the given string (generally supplied by the 146602ab9b30b644a78a4057da93d838a77391ec0acanthony% user) and converts it into a Morphology/Convolution Kernel. This allows 147602ab9b30b644a78a4057da93d838a77391ec0acanthony% users to specify a kernel from a number of pre-defined kernels, or to fully 148602ab9b30b644a78a4057da93d838a77391ec0acanthony% specify their own kernel for a specific Convolution or Morphology 149602ab9b30b644a78a4057da93d838a77391ec0acanthony% Operation. 150602ab9b30b644a78a4057da93d838a77391ec0acanthony% 151602ab9b30b644a78a4057da93d838a77391ec0acanthony% The kernel so generated can be any rectangular array of floating point 152602ab9b30b644a78a4057da93d838a77391ec0acanthony% values (doubles) with the 'control point' or 'pixel being affected' 153602ab9b30b644a78a4057da93d838a77391ec0acanthony% anywhere within that array of values. 154602ab9b30b644a78a4057da93d838a77391ec0acanthony% 15583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% Previously IM was restricted to a square of odd size using the exact 15619910ef25dd3d99d1981a9e42c934133170ee714anthony% center as origin, this is no longer the case, and any rectangular kernel 15783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% with any value being declared the origin. This in turn allows the use of 15883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% highly asymmetrical kernels. 159602ab9b30b644a78a4057da93d838a77391ec0acanthony% 160602ab9b30b644a78a4057da93d838a77391ec0acanthony% The floating point values in the kernel can also include a special value 16183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% known as 'nan' or 'not a number' to indicate that this value is not part 16283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% of the kernel array. This allows you to shaped the kernel within its 16383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% rectangular area. That is 'nan' values provide a 'mask' for the kernel 16483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% shape. However at least one non-nan value must be provided for correct 16583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% working of a kernel. 166602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1677a01dcf50ce12cb2a789bedff51e9345f022432eanthony% The returned kernel should be freed using the DestroyKernelInfo() when you 1687a01dcf50ce12cb2a789bedff51e9345f022432eanthony% are finished with it. Do not free this memory yourself. 169602ab9b30b644a78a4057da93d838a77391ec0acanthony% 170602ab9b30b644a78a4057da93d838a77391ec0acanthony% Input kernel defintion strings can consist of any of three types. 171602ab9b30b644a78a4057da93d838a77391ec0acanthony% 172bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% "name:args[[@><]" 17329188a8682a98d4b7882cca434b170517555fc7danthony% Select from one of the built in kernels, using the name and 17429188a8682a98d4b7882cca434b170517555fc7danthony% geometry arguments supplied. See AcquireKernelBuiltIn() 175602ab9b30b644a78a4057da93d838a77391ec0acanthony% 176bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% "WxH[+X+Y][@><]:num, num, num ..." 1771b2bc0a7da432e6e1cc0480280402df213faa940anthony% a kernel of size W by H, with W*H floating point numbers following. 178602ab9b30b644a78a4057da93d838a77391ec0acanthony% the 'center' can be optionally be defined at +X+Y (such that +0+0 17929188a8682a98d4b7882cca434b170517555fc7danthony% is top left corner). If not defined the pixel in the center, for 18029188a8682a98d4b7882cca434b170517555fc7danthony% odd sizes, or to the immediate top or left of center for even sizes 18129188a8682a98d4b7882cca434b170517555fc7danthony% is automatically selected. 182602ab9b30b644a78a4057da93d838a77391ec0acanthony% 18329188a8682a98d4b7882cca434b170517555fc7danthony% "num, num, num, num, ..." 18429188a8682a98d4b7882cca434b170517555fc7danthony% list of floating point numbers defining an 'old style' odd sized 18529188a8682a98d4b7882cca434b170517555fc7danthony% square kernel. At least 9 values should be provided for a 3x3 18629188a8682a98d4b7882cca434b170517555fc7danthony% square kernel, 25 for a 5x5 square kernel, 49 for 7x7, etc. 18729188a8682a98d4b7882cca434b170517555fc7danthony% Values can be space or comma separated. This is not recommended. 188602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1897a01dcf50ce12cb2a789bedff51e9345f022432eanthony% You can define a 'list of kernels' which can be used by some morphology 1901e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp% operators A list is defined as a semi-colon separated list kernels. 1917a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 192dbc8989a61339951c6434d9a43e7b6fefb5da374anthony% " kernel ; kernel ; kernel ; " 1937a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 1941dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% Any extra ';' characters, at start, end or between kernel defintions are 19543c4925e5305a26e48d68f7893e94f55d0831c39anthony% simply ignored. 19643c4925e5305a26e48d68f7893e94f55d0831c39anthony% 197bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The special flags will expand a single kernel, into a list of rotated 198bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% kernels. A '@' flag will expand a 3x3 kernel into a list of 45-degree 199bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% cyclic rotations, while a '>' will generate a list of 90-degree rotations. 200bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The '<' also exands using 90-degree rotates, but giving a 180-degree 201bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% reflected kernel before the +/- 90-degree rotations, which can be important 202bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% for Thinning operations. 203bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 20443c4925e5305a26e48d68f7893e94f55d0831c39anthony% Note that 'name' kernels will start with an alphabetic character while the 20543c4925e5305a26e48d68f7893e94f55d0831c39anthony% new kernel specification has a ':' character in its specification string. 20643c4925e5305a26e48d68f7893e94f55d0831c39anthony% If neither is the case, it is assumed an old style of a simple list of 20743c4925e5305a26e48d68f7893e94f55d0831c39anthony% numbers generating a odd-sized square kernel has been given. 2087a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 209602ab9b30b644a78a4057da93d838a77391ec0acanthony% The format of the AcquireKernal method is: 210602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2112be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% KernelInfo *AcquireKernelInfo(const char *kernel_string) 212602ab9b30b644a78a4057da93d838a77391ec0acanthony% 213602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 214602ab9b30b644a78a4057da93d838a77391ec0acanthony% 215602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel_string: the Morphology/Convolution kernel wanted. 216602ab9b30b644a78a4057da93d838a77391ec0acanthony% 217602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 218602ab9b30b644a78a4057da93d838a77391ec0acanthony 219c84dce50867229e4872193e8eed5dbab58eb9f02anthony/* This was separated so that it could be used as a separate 2205ef8e94ff55717be2387d537bd49025780a1a558anthony** array input handling function, such as for -color-matrix 221c84dce50867229e4872193e8eed5dbab58eb9f02anthony*/ 2225ef8e94ff55717be2387d537bd49025780a1a558anthonystatic KernelInfo *ParseKernelArray(const char *kernel_string) 223602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 2242be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy KernelInfo 225602ab9b30b644a78a4057da93d838a77391ec0acanthony *kernel; 226602ab9b30b644a78a4057da93d838a77391ec0acanthony 227602ab9b30b644a78a4057da93d838a77391ec0acanthony char 228602ab9b30b644a78a4057da93d838a77391ec0acanthony token[MaxTextExtent]; 229602ab9b30b644a78a4057da93d838a77391ec0acanthony 230602ab9b30b644a78a4057da93d838a77391ec0acanthony const char 2315ef8e94ff55717be2387d537bd49025780a1a558anthony *p, 2325ef8e94ff55717be2387d537bd49025780a1a558anthony *end; 233602ab9b30b644a78a4057da93d838a77391ec0acanthony 234bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 235c84dce50867229e4872193e8eed5dbab58eb9f02anthony i; 236602ab9b30b644a78a4057da93d838a77391ec0acanthony 23729188a8682a98d4b7882cca434b170517555fc7danthony double 23829188a8682a98d4b7882cca434b170517555fc7danthony nan = sqrt((double)-1.0); /* Special Value : Not A Number */ 23929188a8682a98d4b7882cca434b170517555fc7danthony 24043c4925e5305a26e48d68f7893e94f55d0831c39anthony MagickStatusType 24143c4925e5305a26e48d68f7893e94f55d0831c39anthony flags; 24243c4925e5305a26e48d68f7893e94f55d0831c39anthony 24343c4925e5305a26e48d68f7893e94f55d0831c39anthony GeometryInfo 24443c4925e5305a26e48d68f7893e94f55d0831c39anthony args; 24543c4925e5305a26e48d68f7893e94f55d0831c39anthony 246a64b85d7873d5e540fe6e2941aa98ec7653a4e2dcristy kernel=(KernelInfo *) AcquireQuantumMemory(1,sizeof(*kernel)); 2472be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy if (kernel == (KernelInfo *)NULL) 248602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 249602ab9b30b644a78a4057da93d838a77391ec0acanthony (void) ResetMagickMemory(kernel,0,sizeof(*kernel)); 25043c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->minimum = kernel->maximum = kernel->angle = 0.0; 2517a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel->negative_range = kernel->positive_range = 0.0; 252602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->type = UserDefinedKernel; 2537a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel->next = (KernelInfo *) NULL; 254d43a46bc9598004091eae232bc7938e009b494a1cristy kernel->signature = MagickSignature; 2555e6be1e6a77c230e4a204fa9163d873104730c35cristy if (kernel_string == (const char *) NULL) 2565e6be1e6a77c230e4a204fa9163d873104730c35cristy return(kernel); 257602ab9b30b644a78a4057da93d838a77391ec0acanthony 2585ef8e94ff55717be2387d537bd49025780a1a558anthony /* find end of this specific kernel definition string */ 2595ef8e94ff55717be2387d537bd49025780a1a558anthony end = strchr(kernel_string, ';'); 2605ef8e94ff55717be2387d537bd49025780a1a558anthony if ( end == (char *) NULL ) 2615ef8e94ff55717be2387d537bd49025780a1a558anthony end = strchr(kernel_string, '\0'); 2625ef8e94ff55717be2387d537bd49025780a1a558anthony 263a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* clear flags - for Expanding kernel lists thorugh rotations */ 26443c4925e5305a26e48d68f7893e94f55d0831c39anthony flags = NoValue; 26543c4925e5305a26e48d68f7893e94f55d0831c39anthony 266f68116b9d5afef3c343faeb599a3c0ffc8e9b244anthony /* Has a ':' in argument - New user kernel specification 267f68116b9d5afef3c343faeb599a3c0ffc8e9b244anthony FUTURE: this split on ':' could be done by StringToken() 268f68116b9d5afef3c343faeb599a3c0ffc8e9b244anthony */ 269602ab9b30b644a78a4057da93d838a77391ec0acanthony p = strchr(kernel_string, ':'); 2705ef8e94ff55717be2387d537bd49025780a1a558anthony if ( p != (char *) NULL && p < end) 271602ab9b30b644a78a4057da93d838a77391ec0acanthony { 272602ab9b30b644a78a4057da93d838a77391ec0acanthony /* ParseGeometry() needs the geometry separated! -- Arrgghh */ 273150989ed67ef9da53141a65e5f3ebdb05dd025abcristy memcpy(token, kernel_string, (size_t) (p-kernel_string)); 274602ab9b30b644a78a4057da93d838a77391ec0acanthony token[p-kernel_string] = '\0'; 275c84dce50867229e4872193e8eed5dbab58eb9f02anthony SetGeometryInfo(&args); 276602ab9b30b644a78a4057da93d838a77391ec0acanthony flags = ParseGeometry(token, &args); 277602ab9b30b644a78a4057da93d838a77391ec0acanthony 27829188a8682a98d4b7882cca434b170517555fc7danthony /* Size handling and checks of geometry settings */ 279602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( (flags & WidthValue) == 0 ) /* if no width then */ 280602ab9b30b644a78a4057da93d838a77391ec0acanthony args.rho = args.sigma; /* then width = height */ 281602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.rho < 1.0 ) /* if width too small */ 282602ab9b30b644a78a4057da93d838a77391ec0acanthony args.rho = 1.0; /* then width = 1 */ 283602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.sigma < 1.0 ) /* if height too small */ 284602ab9b30b644a78a4057da93d838a77391ec0acanthony args.sigma = args.rho; /* then height = width */ 285bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args.rho; 286bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t)args.sigma; 287602ab9b30b644a78a4057da93d838a77391ec0acanthony 288602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Offset Handling and Checks */ 289602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.xi < 0.0 || args.psi < 0.0 ) 29083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 291bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi 292ea068a53d23d6dca08f1bce44c8937d54f83b983anthony : (ssize_t) (kernel->width-1)/2; 293bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi 294ea068a53d23d6dca08f1bce44c8937d54f83b983anthony : (ssize_t) (kernel->height-1)/2; 295bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( kernel->x >= (ssize_t) kernel->width || 296bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y >= (ssize_t) kernel->height ) 29783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 298602ab9b30b644a78a4057da93d838a77391ec0acanthony 299602ab9b30b644a78a4057da93d838a77391ec0acanthony p++; /* advance beyond the ':' */ 300602ab9b30b644a78a4057da93d838a77391ec0acanthony } 301602ab9b30b644a78a4057da93d838a77391ec0acanthony else 302c84dce50867229e4872193e8eed5dbab58eb9f02anthony { /* ELSE - Old old specification, forming odd-square kernel */ 303602ab9b30b644a78a4057da93d838a77391ec0acanthony /* count up number of values given */ 304602ab9b30b644a78a4057da93d838a77391ec0acanthony p=(const char *) kernel_string; 305a699b171eff7e0178463e8f271b35a3cbb995f0ecristy while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\'')) 30629188a8682a98d4b7882cca434b170517555fc7danthony p++; /* ignore "'" chars for convolve filter usage - Cristy */ 3075ef8e94ff55717be2387d537bd49025780a1a558anthony for (i=0; p < end; i++) 308602ab9b30b644a78a4057da93d838a77391ec0acanthony { 309602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 310602ab9b30b644a78a4057da93d838a77391ec0acanthony if (*token == ',') 311602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 312602ab9b30b644a78a4057da93d838a77391ec0acanthony } 313602ab9b30b644a78a4057da93d838a77391ec0acanthony /* set the size of the kernel - old sized square */ 314bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height= (size_t) sqrt((double) i+1.0); 315bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 316602ab9b30b644a78a4057da93d838a77391ec0acanthony p=(const char *) kernel_string; 31729188a8682a98d4b7882cca434b170517555fc7danthony while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\'')) 31829188a8682a98d4b7882cca434b170517555fc7danthony p++; /* ignore "'" chars for convolve filter usage - Cristy */ 319602ab9b30b644a78a4057da93d838a77391ec0acanthony } 320602ab9b30b644a78a4057da93d838a77391ec0acanthony 321602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Read in the kernel values from rest of input string argument */ 322e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory( 323e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->width,kernel->height*sizeof(*kernel->values))); 324d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 32583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 3260283b31ed43486c1b3c6d903f6992b6402419c40cristy kernel->minimum=MagickMaximumValue; 3270283b31ed43486c1b3c6d903f6992b6402419c40cristy kernel->maximum=(-MagickMaximumValue); 328c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 329bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++) 330602ab9b30b644a78a4057da93d838a77391ec0acanthony { 331602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 332602ab9b30b644a78a4057da93d838a77391ec0acanthony if (*token == ',') 333602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 33429188a8682a98d4b7882cca434b170517555fc7danthony if ( LocaleCompare("nan",token) == 0 335c84dce50867229e4872193e8eed5dbab58eb9f02anthony || LocaleCompare("-",token) == 0 ) { 336ea068a53d23d6dca08f1bce44c8937d54f83b983anthony kernel->values[i] = nan; /* this value is not part of neighbourhood */ 33729188a8682a98d4b7882cca434b170517555fc7danthony } 33829188a8682a98d4b7882cca434b170517555fc7danthony else { 3390ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony kernel->values[i] = StringToDouble(token,(char **) NULL); 34029188a8682a98d4b7882cca434b170517555fc7danthony ( kernel->values[i] < 0) 341c99304fe3c8d9c617da792b40b57c118bb1249afcristy ? ( kernel->negative_range += kernel->values[i] ) 342c99304fe3c8d9c617da792b40b57c118bb1249afcristy : ( kernel->positive_range += kernel->values[i] ); 343c99304fe3c8d9c617da792b40b57c118bb1249afcristy Minimize(kernel->minimum, kernel->values[i]); 344c99304fe3c8d9c617da792b40b57c118bb1249afcristy Maximize(kernel->maximum, kernel->values[i]); 34529188a8682a98d4b7882cca434b170517555fc7danthony } 34629188a8682a98d4b7882cca434b170517555fc7danthony } 34729188a8682a98d4b7882cca434b170517555fc7danthony 3485ef8e94ff55717be2387d537bd49025780a1a558anthony /* sanity check -- no more values in kernel definition */ 3495ef8e94ff55717be2387d537bd49025780a1a558anthony GetMagickToken(p,&p,token); 3505ef8e94ff55717be2387d537bd49025780a1a558anthony if ( *token != '\0' && *token != ';' && *token != '\'' ) 3515ef8e94ff55717be2387d537bd49025780a1a558anthony return(DestroyKernelInfo(kernel)); 3525ef8e94ff55717be2387d537bd49025780a1a558anthony 353c84dce50867229e4872193e8eed5dbab58eb9f02anthony#if 0 354c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* this was the old method of handling a incomplete kernel */ 355bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( i < (ssize_t) (kernel->width*kernel->height) ) { 356c99304fe3c8d9c617da792b40b57c118bb1249afcristy Minimize(kernel->minimum, kernel->values[i]); 357c99304fe3c8d9c617da792b40b57c118bb1249afcristy Maximize(kernel->maximum, kernel->values[i]); 358bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( ; i < (ssize_t) (kernel->width*kernel->height); i++) 35929188a8682a98d4b7882cca434b170517555fc7danthony kernel->values[i]=0.0; 360602ab9b30b644a78a4057da93d838a77391ec0acanthony } 361c84dce50867229e4872193e8eed5dbab58eb9f02anthony#else 362c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* Number of values for kernel was not enough - Report Error */ 363bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( i < (ssize_t) (kernel->width*kernel->height) ) 364c84dce50867229e4872193e8eed5dbab58eb9f02anthony return(DestroyKernelInfo(kernel)); 365c84dce50867229e4872193e8eed5dbab58eb9f02anthony#endif 366c84dce50867229e4872193e8eed5dbab58eb9f02anthony 367c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* check that we recieved at least one real (non-nan) value! */ 3680283b31ed43486c1b3c6d903f6992b6402419c40cristy if (kernel->minimum == MagickMaximumValue) 369c84dce50867229e4872193e8eed5dbab58eb9f02anthony return(DestroyKernelInfo(kernel)); 370602ab9b30b644a78a4057da93d838a77391ec0acanthony 37143c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( (flags & AreaValue) != 0 ) /* '@' symbol in kernel size */ 372bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 45.0); /* cyclic rotate 3x3 kernels */ 373bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */ 374bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 90.0); /* 90 degree rotate of kernel */ 375bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & LessValue) != 0 ) /* '<' symbol in kernel args */ 376bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(kernel); /* 90 degree mirror rotate */ 37743c4925e5305a26e48d68f7893e94f55d0831c39anthony 378602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 379602ab9b30b644a78a4057da93d838a77391ec0acanthony} 380c84dce50867229e4872193e8eed5dbab58eb9f02anthony 38143c4925e5305a26e48d68f7893e94f55d0831c39anthonystatic KernelInfo *ParseKernelName(const char *kernel_string) 382c84dce50867229e4872193e8eed5dbab58eb9f02anthony{ 383c84dce50867229e4872193e8eed5dbab58eb9f02anthony char 384c84dce50867229e4872193e8eed5dbab58eb9f02anthony token[MaxTextExtent]; 385c84dce50867229e4872193e8eed5dbab58eb9f02anthony 386c84dce50867229e4872193e8eed5dbab58eb9f02anthony const char 3877a01dcf50ce12cb2a789bedff51e9345f022432eanthony *p, 3887a01dcf50ce12cb2a789bedff51e9345f022432eanthony *end; 389c84dce50867229e4872193e8eed5dbab58eb9f02anthony 3909d314ff2c17a77996c05413c2013880387e50f0ecristy GeometryInfo 3919d314ff2c17a77996c05413c2013880387e50f0ecristy args; 3929d314ff2c17a77996c05413c2013880387e50f0ecristy 3939d314ff2c17a77996c05413c2013880387e50f0ecristy KernelInfo 3949d314ff2c17a77996c05413c2013880387e50f0ecristy *kernel; 3959d314ff2c17a77996c05413c2013880387e50f0ecristy 396c84dce50867229e4872193e8eed5dbab58eb9f02anthony MagickStatusType 397c84dce50867229e4872193e8eed5dbab58eb9f02anthony flags; 398c84dce50867229e4872193e8eed5dbab58eb9f02anthony 3999d314ff2c17a77996c05413c2013880387e50f0ecristy ssize_t 4009d314ff2c17a77996c05413c2013880387e50f0ecristy type; 401c84dce50867229e4872193e8eed5dbab58eb9f02anthony 402c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* Parse special 'named' kernel */ 4035ef8e94ff55717be2387d537bd49025780a1a558anthony GetMagickToken(kernel_string,&p,token); 404042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy type=ParseCommandOption(MagickKernelOptions,MagickFalse,token); 405c84dce50867229e4872193e8eed5dbab58eb9f02anthony if ( type < 0 || type == UserDefinedKernel ) 4065ef8e94ff55717be2387d537bd49025780a1a558anthony return((KernelInfo *)NULL); /* not a valid named kernel */ 407c84dce50867229e4872193e8eed5dbab58eb9f02anthony 408c84dce50867229e4872193e8eed5dbab58eb9f02anthony while (((isspace((int) ((unsigned char) *p)) != 0) || 4095ef8e94ff55717be2387d537bd49025780a1a558anthony (*p == ',') || (*p == ':' )) && (*p != '\0') && (*p != ';')) 410c84dce50867229e4872193e8eed5dbab58eb9f02anthony p++; 4117a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4127a01dcf50ce12cb2a789bedff51e9345f022432eanthony end = strchr(p, ';'); /* end of this kernel defintion */ 4137a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( end == (char *) NULL ) 4147a01dcf50ce12cb2a789bedff51e9345f022432eanthony end = strchr(p, '\0'); 4157a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4167a01dcf50ce12cb2a789bedff51e9345f022432eanthony /* ParseGeometry() needs the geometry separated! -- Arrgghh */ 4177a01dcf50ce12cb2a789bedff51e9345f022432eanthony memcpy(token, p, (size_t) (end-p)); 4187a01dcf50ce12cb2a789bedff51e9345f022432eanthony token[end-p] = '\0'; 419c84dce50867229e4872193e8eed5dbab58eb9f02anthony SetGeometryInfo(&args); 4207a01dcf50ce12cb2a789bedff51e9345f022432eanthony flags = ParseGeometry(token, &args); 421c84dce50867229e4872193e8eed5dbab58eb9f02anthony 4223c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony#if 0 4233c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony /* For Debugging Geometry Input */ 4245acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", 4251e604812fad85bb96f757a2393015ae3d061c39acristy flags, args.rho, args.sigma, args.xi, args.psi ); 4263c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony#endif 4273c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony 428c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* special handling of missing values in input string */ 429c84dce50867229e4872193e8eed5dbab58eb9f02anthony switch( type ) { 430a9892d898acb81e1ec73106d892855fdc5a69427anthony /* Shape Kernel Defaults */ 431529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 432529482f4b494010a13338a74446c510712f670b3anthony if ( (flags & WidthValue) == 0 ) 433a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = 1.0; /* Default scale = 1.0, zero is valid */ 4345ef8e94ff55717be2387d537bd49025780a1a558anthony break; 4355ef8e94ff55717be2387d537bd49025780a1a558anthony case SquareKernel: 4365ef8e94ff55717be2387d537bd49025780a1a558anthony case DiamondKernel: 4371ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 4385ef8e94ff55717be2387d537bd49025780a1a558anthony case DiskKernel: 4395ef8e94ff55717be2387d537bd49025780a1a558anthony case PlusKernel: 4403dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case CrossKernel: 4415ef8e94ff55717be2387d537bd49025780a1a558anthony if ( (flags & HeightValue) == 0 ) 442a9892d898acb81e1ec73106d892855fdc5a69427anthony args.sigma = 1.0; /* Default scale = 1.0, zero is valid */ 4435ef8e94ff55717be2387d537bd49025780a1a558anthony break; 444c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RingKernel: 445c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( (flags & XValue) == 0 ) 446a9892d898acb81e1ec73106d892855fdc5a69427anthony args.xi = 1.0; /* Default scale = 1.0, zero is valid */ 447c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 448a9892d898acb81e1ec73106d892855fdc5a69427anthony case RectangleKernel: /* Rectangle - set size defaults */ 449a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & WidthValue) == 0 ) /* if no width then */ 450a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = args.sigma; /* then width = height */ 451a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( args.rho < 1.0 ) /* if width too small */ 452a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = 3; /* then width = 3 */ 453a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( args.sigma < 1.0 ) /* if height too small */ 454a9892d898acb81e1ec73106d892855fdc5a69427anthony args.sigma = args.rho; /* then height = width */ 455a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & XValue) == 0 ) /* center offset if not defined */ 456a9892d898acb81e1ec73106d892855fdc5a69427anthony args.xi = (double)(((ssize_t)args.rho-1)/2); 457a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & YValue) == 0 ) 458a9892d898acb81e1ec73106d892855fdc5a69427anthony args.psi = (double)(((ssize_t)args.sigma-1)/2); 459a9892d898acb81e1ec73106d892855fdc5a69427anthony break; 460a9892d898acb81e1ec73106d892855fdc5a69427anthony /* Distance Kernel Defaults */ 4615ef8e94ff55717be2387d537bd49025780a1a558anthony case ChebyshevKernel: 462bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 4631ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonalKernel: 4645ef8e94ff55717be2387d537bd49025780a1a558anthony case EuclideanKernel: 46543c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( (flags & HeightValue) == 0 ) /* no distance scale */ 46643c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma = 100.0; /* default distance scaling */ 46743c4925e5305a26e48d68f7893e94f55d0831c39anthony else if ( (flags & AspectValue ) != 0 ) /* '!' flag */ 46843c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma = QuantumRange/(args.sigma+1); /* maximum pixel distance */ 46943c4925e5305a26e48d68f7893e94f55d0831c39anthony else if ( (flags & PercentValue ) != 0 ) /* '%' flag */ 47043c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma *= QuantumRange/100.0; /* percentage of color range */ 4715ef8e94ff55717be2387d537bd49025780a1a558anthony break; 4725ef8e94ff55717be2387d537bd49025780a1a558anthony default: 4735ef8e94ff55717be2387d537bd49025780a1a558anthony break; 474c84dce50867229e4872193e8eed5dbab58eb9f02anthony } 475c84dce50867229e4872193e8eed5dbab58eb9f02anthony 476f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony kernel = AcquireKernelBuiltIn((KernelInfoType)type, &args); 477529482f4b494010a13338a74446c510712f670b3anthony if ( kernel == (KernelInfo *) NULL ) 478529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 479f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony 480f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony /* global expand to rotated kernel list - only for single kernels */ 481f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony if ( kernel->next == (KernelInfo *) NULL ) { 482f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony if ( (flags & AreaValue) != 0 ) /* '@' symbol in kernel args */ 483bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 45.0); 484bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */ 485bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 90.0); 486bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & LessValue) != 0 ) /* '<' symbol in kernel args */ 487bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(kernel); 488f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony } 489f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony 490f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony return(kernel); 491c84dce50867229e4872193e8eed5dbab58eb9f02anthony} 492c84dce50867229e4872193e8eed5dbab58eb9f02anthony 4935ef8e94ff55717be2387d537bd49025780a1a558anthonyMagickExport KernelInfo *AcquireKernelInfo(const char *kernel_string) 4945ef8e94ff55717be2387d537bd49025780a1a558anthony{ 4957a01dcf50ce12cb2a789bedff51e9345f022432eanthony KernelInfo 496dbc8989a61339951c6434d9a43e7b6fefb5da374anthony *kernel, 49743c4925e5305a26e48d68f7893e94f55d0831c39anthony *new_kernel; 4987a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4995ef8e94ff55717be2387d537bd49025780a1a558anthony char 5005ef8e94ff55717be2387d537bd49025780a1a558anthony token[MaxTextExtent]; 5015ef8e94ff55717be2387d537bd49025780a1a558anthony 5027a01dcf50ce12cb2a789bedff51e9345f022432eanthony const char 503dbc8989a61339951c6434d9a43e7b6fefb5da374anthony *p; 5047a01dcf50ce12cb2a789bedff51e9345f022432eanthony 5055e6be1e6a77c230e4a204fa9163d873104730c35cristy if (kernel_string == (const char *) NULL) 5065e6be1e6a77c230e4a204fa9163d873104730c35cristy return(ParseKernelArray(kernel_string)); 507c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk p=kernel_string; 508c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk kernel=NULL; 5097a01dcf50ce12cb2a789bedff51e9345f022432eanthony 510c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk while (GetMagickToken(p,NULL,token), *token != '\0') 511c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk { 5121e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp /* ignore extra or multiple ';' kernel separators */ 513c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk if (*token != ';') 514c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk { 515c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk /* tokens starting with alpha is a Named kernel */ 516c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk if (isalpha((int) ((unsigned char) *token)) != 0) 517c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk new_kernel=ParseKernelName(p); 518c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk else /* otherwise a user defined kernel array */ 519c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk new_kernel=ParseKernelArray(p); 520c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk 521c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk /* Error handling -- this is not proper error handling! */ 522c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk if (new_kernel == (KernelInfo *) NULL) 523c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk { 524c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk if (kernel != (KernelInfo *) NULL) 525c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk kernel=DestroyKernelInfo(kernel); 526c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk return((KernelInfo *) NULL); 527c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk } 528e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony 529c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk /* initialise or append the kernel list */ 530c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk if (kernel == (KernelInfo *) NULL) 531c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk kernel=new_kernel; 532c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk else 533c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk LastKernelInfo(kernel)->next=new_kernel; 534c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk } 535dbc8989a61339951c6434d9a43e7b6fefb5da374anthony 536dbc8989a61339951c6434d9a43e7b6fefb5da374anthony /* look for the next kernel in list */ 537c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk p=strchr(p,';'); 538c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk if (p == (char *) NULL) 539dbc8989a61339951c6434d9a43e7b6fefb5da374anthony break; 540dbc8989a61339951c6434d9a43e7b6fefb5da374anthony p++; 541dbc8989a61339951c6434d9a43e7b6fefb5da374anthony } 5427a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(kernel); 5435ef8e94ff55717be2387d537bd49025780a1a558anthony} 5445ef8e94ff55717be2387d537bd49025780a1a558anthony 545602ab9b30b644a78a4057da93d838a77391ec0acanthony 546602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 547602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 548602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 549602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 550602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 551602ab9b30b644a78a4057da93d838a77391ec0acanthony% A c q u i r e K e r n e l B u i l t I n % 552602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 553602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 554602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 555602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 556602ab9b30b644a78a4057da93d838a77391ec0acanthony% 557602ab9b30b644a78a4057da93d838a77391ec0acanthony% AcquireKernelBuiltIn() returned one of the 'named' built-in types of 558602ab9b30b644a78a4057da93d838a77391ec0acanthony% kernels used for special purposes such as gaussian blurring, skeleton 559602ab9b30b644a78a4057da93d838a77391ec0acanthony% pruning, and edge distance determination. 560602ab9b30b644a78a4057da93d838a77391ec0acanthony% 561602ab9b30b644a78a4057da93d838a77391ec0acanthony% They take a KernelType, and a set of geometry style arguments, which were 562602ab9b30b644a78a4057da93d838a77391ec0acanthony% typically decoded from a user supplied string, or from a more complex 563602ab9b30b644a78a4057da93d838a77391ec0acanthony% Morphology Method that was requested. 564602ab9b30b644a78a4057da93d838a77391ec0acanthony% 565602ab9b30b644a78a4057da93d838a77391ec0acanthony% The format of the AcquireKernalBuiltIn method is: 566602ab9b30b644a78a4057da93d838a77391ec0acanthony% 5672be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type, 568602ab9b30b644a78a4057da93d838a77391ec0acanthony% const GeometryInfo args) 569602ab9b30b644a78a4057da93d838a77391ec0acanthony% 570602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 571602ab9b30b644a78a4057da93d838a77391ec0acanthony% 572602ab9b30b644a78a4057da93d838a77391ec0acanthony% o type: the pre-defined type of kernel wanted 573602ab9b30b644a78a4057da93d838a77391ec0acanthony% 574602ab9b30b644a78a4057da93d838a77391ec0acanthony% o args: arguments defining or modifying the kernel 575602ab9b30b644a78a4057da93d838a77391ec0acanthony% 576602ab9b30b644a78a4057da93d838a77391ec0acanthony% Convolution Kernels 577602ab9b30b644a78a4057da93d838a77391ec0acanthony% 57846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Unity 579529482f4b494010a13338a74446c510712f670b3anthony% The a No-Op or Scaling single element kernel. 58046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 5813c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Gaussian:{radius},{sigma} 5822489f53a1153c2b619b1c9a6744602e8840bd9a9glennrp% Generate a two-dimensional gaussian kernel, as used by -gaussian. 583c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The sigma for the curve is required. The resulting kernel is 584c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% normalized, 585c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 586c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% If 'sigma' is zero, you get a single pixel on a field of zeros. 587602ab9b30b644a78a4057da93d838a77391ec0acanthony% 588602ab9b30b644a78a4057da93d838a77391ec0acanthony% NOTE: that the 'radius' is optional, but if provided can limit (clip) 589602ab9b30b644a78a4057da93d838a77391ec0acanthony% the final size of the resulting kernel to a square 2*radius+1 in size. 590602ab9b30b644a78a4057da93d838a77391ec0acanthony% The radius should be at least 2 times that of the sigma value, or 591602ab9b30b644a78a4057da93d838a77391ec0acanthony% sever clipping and aliasing may result. If not given or set to 0 the 592602ab9b30b644a78a4057da93d838a77391ec0acanthony% radius will be determined so as to produce the best minimal error 593602ab9b30b644a78a4057da93d838a77391ec0acanthony% result, which is usally much larger than is normally needed. 594602ab9b30b644a78a4057da93d838a77391ec0acanthony% 595501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% LoG:{radius},{sigma} 596501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% "Laplacian of a Gaussian" or "Mexician Hat" Kernel. 597501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% The supposed ideal edge detection, zero-summing kernel. 598501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 599501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% An alturnative to this kernel is to use a "DoG" with a sigma ratio of 600501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% approx 1.6 (according to wikipedia). 601501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 602501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% DoG:{radius},{sigma1},{sigma2} 603c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% "Difference of Gaussians" Kernel. 604c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% As "Gaussian" but with a gaussian produced by 'sigma2' subtracted 605c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% from the gaussian produced by 'sigma1'. Typically sigma2 > sigma1. 606c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The result is a zero-summing kernel. 607c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 608c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Blur:{radius},{sigma}[,{angle}] 6094c08aed51c5899665ade97263692328eea4af106cristy% Generates a 1 dimensional or linear gaussian blur, at the angle given 610c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% (current restricted to orthogonal angles). If a 'radius' is given the 611c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% kernel is clipped to a width of 2*radius+1. Kernel can be rotated 612c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% by a 90 degree angle. 613c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 614c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% If 'sigma' is zero, you get a single pixel on a field of zeros. 615c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 616c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Note that two convolutions with two "Blur" kernels perpendicular to 617f0a92fd8deb68d411304359906b12679b675691fglennrp% each other, is equivalent to a far larger "Gaussian" kernel with the 618c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% same sigma value, However it is much faster to apply. This is how the 619c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% "-blur" operator actually works. 620c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 6213c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Comet:{width},{sigma},{angle} 6223c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Blur in one direction only, much like how a bright object leaves 623602ab9b30b644a78a4057da93d838a77391ec0acanthony% a comet like trail. The Kernel is actually half a gaussian curve, 6243c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Adding two such blurs in opposite directions produces a Blur Kernel. 6253c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Angle can be rotated in multiples of 90 degrees. 626602ab9b30b644a78a4057da93d838a77391ec0acanthony% 6273c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Note that the first argument is the width of the kernel and not the 628602ab9b30b644a78a4057da93d838a77391ec0acanthony% radius of the kernel. 629602ab9b30b644a78a4057da93d838a77391ec0acanthony% 63040ca0b982379d4ab2716435a46603d56b5b218b1anthony% Binomial:[{radius}] 63140ca0b982379d4ab2716435a46603d56b5b218b1anthony% Generate a discrete kernel using a 2 dimentional Pascel's Triangle 632eef684ff80c7d5aca1493f4755426c88b3d3accdanthony% of values. Used for special forma of image filters. 63340ca0b982379d4ab2716435a46603d56b5b218b1anthony% 634602ab9b30b644a78a4057da93d838a77391ec0acanthony% # Still to be implemented... 635602ab9b30b644a78a4057da93d838a77391ec0acanthony% # 6364fd27e21043be809d66c8202e779255e5b660d2danthony% # Filter2D 6374fd27e21043be809d66c8202e779255e5b660d2danthony% # Filter1D 6384fd27e21043be809d66c8202e779255e5b660d2danthony% # Set kernel values using a resize filter, and given scale (sigma) 639dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp% # Cylindrical or Linear. Is this possible with an image? 6404fd27e21043be809d66c8202e779255e5b660d2danthony% # 641602ab9b30b644a78a4057da93d838a77391ec0acanthony% 6423c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Named Constant Convolution Kernels 6433c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 644c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% All these are unscaled, zero-summing kernels by default. As such for 645c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% non-HDRI version of ImageMagick some form of normalization, user scaling, 646c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% and biasing the results is recommended, to prevent the resulting image 647c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% being 'clipped'. 648c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 649c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The 3x3 kernels (most of these) can be circularly rotated in multiples of 650c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 45 degrees to generate the 8 angled varients of each of the kernels. 6513c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 6523c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Laplacian:{type} 65343c4925e5305a26e48d68f7893e94f55d0831c39anthony% Discrete Lapacian Kernels, (without normalization) 654c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Type 0 : 3x3 with center:8 surounded by -1 (8 neighbourhood) 655c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Type 1 : 3x3 with center:4 edge:-1 corner:0 (4 neighbourhood) 6569eb4f74649b23c053b308ce1152dce51239450baanthony% Type 2 : 3x3 with center:4 edge:1 corner:-2 6579eb4f74649b23c053b308ce1152dce51239450baanthony% Type 3 : 3x3 with center:4 edge:-2 corner:1 6589eb4f74649b23c053b308ce1152dce51239450baanthony% Type 5 : 5x5 laplacian 6599eb4f74649b23c053b308ce1152dce51239450baanthony% Type 7 : 7x7 laplacian 660501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Type 15 : 5x5 LoG (sigma approx 1.4) 661501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Type 19 : 9x9 LoG (sigma approx 1.4) 662c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 663c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Sobel:{angle} 66446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Sobel 'Edge' convolution kernel (3x3) 665c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 666c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 0,-2 | 667c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 668c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 669c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Roberts:{angle} 67046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Roberts convolution kernel (3x3) 671c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | 672c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 0 | 673c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | 674c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 675c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Prewitt:{angle} 676c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Prewitt Edge convolution kernel (3x3) 677c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 678c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 679c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 680c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 6819eb4f74649b23c053b308ce1152dce51239450baanthony% Compass:{angle} 6829eb4f74649b23c053b308ce1152dce51239450baanthony% Prewitt's "Compass" convolution kernel (3x3) 683c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 1 | 684c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1,-2, 1 | 685c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 1 | 686c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 6879eb4f74649b23c053b308ce1152dce51239450baanthony% Kirsch:{angle} 6889eb4f74649b23c053b308ce1152dce51239450baanthony% Kirsch's "Compass" convolution kernel (3x3) 689c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3,-3, 5 | 690c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3, 0, 5 | 691c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3,-3, 5 | 6923c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 693c40ac1e79923a1516075ba1197ae4ed90244af9banthony% FreiChen:{angle} 6941d5e67090dc7232b35bfcc71b31266c20838defcanthony% Frei-Chen Edge Detector is based on a kernel that is similar to 6951d5e67090dc7232b35bfcc71b31266c20838defcanthony% the Sobel Kernel, but is designed to be isotropic. That is it takes 6961d5e67090dc7232b35bfcc71b31266c20838defcanthony% into account the distance of the diagonal in the kernel. 697c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 698c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 699c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | 700c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 701c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 702c40ac1e79923a1516075ba1197ae4ed90244af9banthony% FreiChen:{type},{angle} 703c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 704c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Frei-Chen Pre-weighted kernels... 705c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 706c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 0: default un-nomalized version shown above. 707c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 708c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 1: Orthogonal Kernel (same as type 11 below) 709c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 710c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 711c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 712c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 713c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 2: Diagonal form of Kernel... 714c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, sqrt(2), 0 | 715c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 716c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, -sqrt(2) -1 | 717c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 7181d5e67090dc7232b35bfcc71b31266c20838defcanthony% However this kernel is als at the heart of the FreiChen Edge Detection 7191d5e67090dc7232b35bfcc71b31266c20838defcanthony% Process which uses a set of 9 specially weighted kernel. These 9 7201d5e67090dc7232b35bfcc71b31266c20838defcanthony% kernels not be normalized, but directly applied to the image. The 7211d5e67090dc7232b35bfcc71b31266c20838defcanthony% results is then added together, to produce the intensity of an edge in 7221d5e67090dc7232b35bfcc71b31266c20838defcanthony% a specific direction. The square root of the pixel value can then be 7231d5e67090dc7232b35bfcc71b31266c20838defcanthony% taken as the cosine of the edge, and at least 2 such runs at 90 degrees 7241d5e67090dc7232b35bfcc71b31266c20838defcanthony% from each other, both the direction and the strength of the edge can be 7251d5e67090dc7232b35bfcc71b31266c20838defcanthony% determined. 7261d5e67090dc7232b35bfcc71b31266c20838defcanthony% 727c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 10: All 9 of the following pre-weighted kernels... 728c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 729c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 11: | 1, 0, -1 | 730c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 731c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 732e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 733c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 12: | 1, sqrt(2), 1 | 734c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | / 2*sqrt(2) 735c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, sqrt(2), 1 | 736e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 737c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 13: | sqrt(2), -1, 0 | 738c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | / 2*sqrt(2) 739c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 1, -sqrt(2) | 740e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 741c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 14: | 0, 1, -sqrt(2) | 742c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | / 2*sqrt(2) 743c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), -1, 0 | 744e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 745c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 15: | 0, -1, 0 | 746c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, 1 | / 2 747c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, -1, 0 | 748e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 749c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 16: | 1, 0, -1 | 750c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | / 2 751c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 752e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 753c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 17: | 1, -2, 1 | 754c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 4, -2 | / 6 755c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, -2, 1 | 756501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 757c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 18: | -2, 1, -2 | 758c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 4, 1 | / 6 759c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 1, -2 | 760e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 761c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 19: | 1, 1, 1 | 762c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 1, 1 | / 3 763c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 1, 1 | 764e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 765e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% The first 4 are for edge detection, the next 4 are for line detection 766e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% and the last is to add a average component to the results. 767e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 768c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% Using a special type of '-1' will return all 9 pre-weighted kernels 769c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% as a multi-kernel list, so that you can use them directly (without 770c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% normalization) with the special "-set option:morphology:compose Plus" 771c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% setting to apply the full FreiChen Edge Detection Technique. 772c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 7731dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% If 'type' is large it will be taken to be an actual rotation angle for 7741dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% the default FreiChen (type 0) kernel. As such FreiChen:45 will look 7751dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% like a Sobel:45 but with 'sqrt(2)' instead of '2' values. 7761dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% 777501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% WARNING: The above was layed out as per 778501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf 779501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% But rotated 90 degrees so direction is from left rather than the top. 780501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% I have yet to find any secondary confirmation of the above. The only 781501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% other source found was actual source code at 782501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf 783501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Neigher paper defineds the kernels in a way that looks locical or 784501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% correct when taken as a whole. 785e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 786602ab9b30b644a78a4057da93d838a77391ec0acanthony% Boolean Kernels 787602ab9b30b644a78a4057da93d838a77391ec0acanthony% 7883c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Diamond:[{radius}[,{scale}]] 7891b2bc0a7da432e6e1cc0480280402df213faa940anthony% Generate a diamond shaped kernel with given radius to the points. 790602ab9b30b644a78a4057da93d838a77391ec0acanthony% Kernel size will again be radius*2+1 square and defaults to radius 1, 791602ab9b30b644a78a4057da93d838a77391ec0acanthony% generating a 3x3 kernel that is slightly larger than a square. 792602ab9b30b644a78a4057da93d838a77391ec0acanthony% 7933c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Square:[{radius}[,{scale}]] 794602ab9b30b644a78a4057da93d838a77391ec0acanthony% Generate a square shaped kernel of size radius*2+1, and defaulting 795602ab9b30b644a78a4057da93d838a77391ec0acanthony% to a 3x3 (radius 1). 796602ab9b30b644a78a4057da93d838a77391ec0acanthony% 7971ef941fea2534a0d20ba7d71307d35040247decbanthony% Octagon:[{radius}[,{scale}]] 7981ef941fea2534a0d20ba7d71307d35040247decbanthony% Generate octagonal shaped kernel of given radius and constant scale. 7990bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% Default radius is 3 producing a 7x7 kernel. A radius of 1 will result 8001ef941fea2534a0d20ba7d71307d35040247decbanthony% in "Diamond" kernel. 8011ef941fea2534a0d20ba7d71307d35040247decbanthony% 8023c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Disk:[{radius}[,{scale}]] 8031ef941fea2534a0d20ba7d71307d35040247decbanthony% Generate a binary disk, thresholded at the radius given, the radius 8041ef941fea2534a0d20ba7d71307d35040247decbanthony% may be a float-point value. Final Kernel size is floor(radius)*2+1 8050bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% square. A radius of 5.3 is the default. 8061ef941fea2534a0d20ba7d71307d35040247decbanthony% 8071ef941fea2534a0d20ba7d71307d35040247decbanthony% NOTE: That a low radii Disk kernels produce the same results as 8081ef941fea2534a0d20ba7d71307d35040247decbanthony% many of the previously defined kernels, but differ greatly at larger 8091ef941fea2534a0d20ba7d71307d35040247decbanthony% radii. Here is a table of equivalences... 8101ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:1" => "Diamond", "Octagon:1", or "Cross:1" 8111ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:1.5" => "Square" 8121ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2" => "Diamond:2" 8131ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2.5" => "Octagon" 8141ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2.9" => "Square:2" 8150bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% "Disk:3.5" => "Octagon:3" 8161ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:4.5" => "Octagon:4" 8171ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:5.4" => "Octagon:5" 8181ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:6.4" => "Octagon:6" 8191ef941fea2534a0d20ba7d71307d35040247decbanthony% All other Disk shapes are unique to this kernel, but because a "Disk" 8201ef941fea2534a0d20ba7d71307d35040247decbanthony% is more circular when using a larger radius, using a larger radius is 8211ef941fea2534a0d20ba7d71307d35040247decbanthony% preferred over iterating the morphological operation. 822602ab9b30b644a78a4057da93d838a77391ec0acanthony% 823a9892d898acb81e1ec73106d892855fdc5a69427anthony% Rectangle:{geometry} 824a9892d898acb81e1ec73106d892855fdc5a69427anthony% Simply generate a rectangle of 1's with the size given. You can also 825a9892d898acb81e1ec73106d892855fdc5a69427anthony% specify the location of the 'control point', otherwise the closest 826a9892d898acb81e1ec73106d892855fdc5a69427anthony% pixel to the center of the rectangle is selected. 827a9892d898acb81e1ec73106d892855fdc5a69427anthony% 828a9892d898acb81e1ec73106d892855fdc5a69427anthony% Properly centered and odd sized rectangles work the best. 829a9892d898acb81e1ec73106d892855fdc5a69427anthony% 830c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Symbol Dilation Kernels 831c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 832c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% These kernel is not a good general morphological kernel, but is used 833c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% more for highlighting and marking any single pixels in an image using, 834c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a "Dilate" method as appropriate. 835c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 836c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% For the same reasons iterating these kernels does not produce the 837c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% same result as using a larger radius for the symbol. 838c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 8393c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Plus:[{radius}[,{scale}]] 8403dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Cross:[{radius}[,{scale}]] 841c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Generate a kernel in the shape of a 'plus' or a 'cross' with 842c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a each arm the length of the given radius (default 2). 8433dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% 844f0a92fd8deb68d411304359906b12679b675691fglennrp% NOTE: "plus:1" is equivalent to a "Diamond" kernel. 845602ab9b30b644a78a4057da93d838a77391ec0acanthony% 846c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Ring:{radius1},{radius2}[,{scale}] 847c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% A ring of the values given that falls between the two radii. 848c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Defaults to a ring of approximataly 3 radius in a 7x7 kernel. 849c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% This is the 'edge' pixels of the default "Disk" kernel, 850c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% More specifically, "Ring" -> "Ring:2.5,3.5,1.0" 8513dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% 8523dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Hit and Miss Kernels 853602ab9b30b644a78a4057da93d838a77391ec0acanthony% 8543dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Peak:radius1,radius2 855c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Find any peak larger than the pixels the fall between the two radii. 856c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The default ring of pixels is as per "Ring". 85743c4925e5305a26e48d68f7893e94f55d0831c39anthony% Edges 858694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find flat orthogonal edges of a binary shape 8593dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Corners 860694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find 90 degree corners of a binary shape 861529482f4b494010a13338a74446c510712f670b3anthony% Diagonals:type 862529482f4b494010a13338a74446c510712f670b3anthony% A special kernel to thin the 'outside' of diagonals 863694934fa79dd310f727588b1d0a7481fa6170f1danthony% LineEnds:type 8643dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Find end points of lines (for pruning a skeletion) 865694934fa79dd310f727588b1d0a7481fa6170f1danthony% Two types of lines ends (default to both) can be searched for 866694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 0: All line ends 867694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: single kernel for 4-conneected line ends 868694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: single kernel for simple line ends 8693dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% LineJunctions 87043c4925e5305a26e48d68f7893e94f55d0831c39anthony% Find three line junctions (within a skeletion) 871694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 0: all line junctions 872694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Y Junction kernel 873694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: Diagonal T Junction kernel 874694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 3: Orthogonal T Junction kernel 875694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 4: Diagonal X Junction kernel 876694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 5: Orthogonal + Junction kernel 877694934fa79dd310f727588b1d0a7481fa6170f1danthony% Ridges:type 878694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find single pixel ridges or thin lines 879694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Fine single pixel thick lines and ridges 880694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: Find two pixel thick lines and ridges 8813dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% ConvexHull 882a9892d898acb81e1ec73106d892855fdc5a69427anthony% Octagonal Thickening Kernel, to generate convex hulls of 45 degrees 883c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Skeleton:type 884c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Traditional skeleton generating kernels. 885694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Tradional Skeleton kernel (4 connected skeleton) 886694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: HIPR2 Skeleton kernel (8 connected skeleton) 887e816a586a13717bab2d6839ced6e5c3828a37f19anthony% Type 3: Thinning skeleton based on a ressearch paper by 8882b2290b46c246ce1f14cb78f1695394e4c4a3ddfanthony% Dan S. Bloomberg (Default Type) 889e816a586a13717bab2d6839ced6e5c3828a37f19anthony% ThinSE:type 890e816a586a13717bab2d6839ced6e5c3828a37f19anthony% A huge variety of Thinning Kernels designed to preserve conectivity. 891e816a586a13717bab2d6839ced6e5c3828a37f19anthony% many other kernel sets use these kernels as source definitions. 892e816a586a13717bab2d6839ced6e5c3828a37f19anthony% Type numbers are 41-49, 81-89, 481, and 482 which are based on 893e816a586a13717bab2d6839ced6e5c3828a37f19anthony% the super and sub notations used in the source research paper. 894602ab9b30b644a78a4057da93d838a77391ec0acanthony% 895602ab9b30b644a78a4057da93d838a77391ec0acanthony% Distance Measuring Kernels 896602ab9b30b644a78a4057da93d838a77391ec0acanthony% 897c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Different types of distance measuring methods, which are used with the 898c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a 'Distance' morphology method for generating a gradient based on 899c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% distance from an edge of a binary shape, though there is a technique 900c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% for handling a anti-aliased shape. 901602ab9b30b644a78a4057da93d838a77391ec0acanthony% 902c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% See the 'Distance' Morphological Method, for information of how it is 903c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% applied. 904602ab9b30b644a78a4057da93d838a77391ec0acanthony% 905c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Chebyshev:[{radius}][x{scale}[%!]] 9061ef941fea2534a0d20ba7d71307d35040247decbanthony% Chebyshev Distance (also known as Tchebychev or Chessboard distance) 9071ef941fea2534a0d20ba7d71307d35040247decbanthony% is a value of one to any neighbour, orthogonal or diagonal. One why 9081ef941fea2534a0d20ba7d71307d35040247decbanthony% of thinking of it is the number of squares a 'King' or 'Queen' in 9091ef941fea2534a0d20ba7d71307d35040247decbanthony% chess needs to traverse reach any other position on a chess board. 9101ef941fea2534a0d20ba7d71307d35040247decbanthony% It results in a 'square' like distance function, but one where 9111ef941fea2534a0d20ba7d71307d35040247decbanthony% diagonals are given a value that is closer than expected. 912c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 913bee715c4c0fd9efe6e21d8627ae8664434df7750anthony% Manhattan:[{radius}][x{scale}[%!]] 9141ef941fea2534a0d20ba7d71307d35040247decbanthony% Manhattan Distance (also known as Rectilinear, City Block, or the Taxi 9151ef941fea2534a0d20ba7d71307d35040247decbanthony% Cab distance metric), it is the distance needed when you can only 9161ef941fea2534a0d20ba7d71307d35040247decbanthony% travel in horizontal or vertical directions only. It is the 9171ef941fea2534a0d20ba7d71307d35040247decbanthony% distance a 'Rook' in chess would have to travel, and results in a 9181ef941fea2534a0d20ba7d71307d35040247decbanthony% diamond like distances, where diagonals are further than expected. 9191ef941fea2534a0d20ba7d71307d35040247decbanthony% 9201ef941fea2534a0d20ba7d71307d35040247decbanthony% Octagonal:[{radius}][x{scale}[%!]] 9211ef941fea2534a0d20ba7d71307d35040247decbanthony% An interleving of Manhatten and Chebyshev metrics producing an 9221ef941fea2534a0d20ba7d71307d35040247decbanthony% increasing octagonally shaped distance. Distances matches those of 9231ef941fea2534a0d20ba7d71307d35040247decbanthony% the "Octagon" shaped kernel of the same radius. The minimum radius 9241ef941fea2534a0d20ba7d71307d35040247decbanthony% and default is 2, producing a 5x5 kernel. 925c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 926c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Euclidean:[{radius}][x{scale}[%!]] 9271ef941fea2534a0d20ba7d71307d35040247decbanthony% Euclidean distance is the 'direct' or 'as the crow flys' distance. 928c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% However by default the kernel size only has a radius of 1, which 929c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% limits the distance to 'Knight' like moves, with only orthogonal and 930c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% diagonal measurements being correct. As such for the default kernel 9311ef941fea2534a0d20ba7d71307d35040247decbanthony% you will get octagonal like distance function. 9321ef941fea2534a0d20ba7d71307d35040247decbanthony% 9331ef941fea2534a0d20ba7d71307d35040247decbanthony% However using a larger radius such as "Euclidean:4" you will get a 9341ef941fea2534a0d20ba7d71307d35040247decbanthony% much smoother distance gradient from the edge of the shape. Especially 9351ef941fea2534a0d20ba7d71307d35040247decbanthony% if the image is pre-processed to include any anti-aliasing pixels. 9361ef941fea2534a0d20ba7d71307d35040247decbanthony% Of course a larger kernel is slower to use, and not always needed. 9371ef941fea2534a0d20ba7d71307d35040247decbanthony% 9381ef941fea2534a0d20ba7d71307d35040247decbanthony% The first three Distance Measuring Kernels will only generate distances 9391ef941fea2534a0d20ba7d71307d35040247decbanthony% of exact multiples of {scale} in binary images. As such you can use a 9401ef941fea2534a0d20ba7d71307d35040247decbanthony% scale of 1 without loosing any information. However you also need some 9411ef941fea2534a0d20ba7d71307d35040247decbanthony% scaling when handling non-binary anti-aliased shapes. 9421ef941fea2534a0d20ba7d71307d35040247decbanthony% 9431ef941fea2534a0d20ba7d71307d35040247decbanthony% The "Euclidean" Distance Kernel however does generate a non-integer 9441ef941fea2534a0d20ba7d71307d35040247decbanthony% fractional results, and as such scaling is vital even for binary shapes. 945c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 946602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 947602ab9b30b644a78a4057da93d838a77391ec0acanthony 9482be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristyMagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type, 949602ab9b30b644a78a4057da93d838a77391ec0acanthony const GeometryInfo *args) 950602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 9512be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy KernelInfo 952602ab9b30b644a78a4057da93d838a77391ec0acanthony *kernel; 953602ab9b30b644a78a4057da93d838a77391ec0acanthony 954bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 955602ab9b30b644a78a4057da93d838a77391ec0acanthony i; 956602ab9b30b644a78a4057da93d838a77391ec0acanthony 957bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 958602ab9b30b644a78a4057da93d838a77391ec0acanthony u, 959602ab9b30b644a78a4057da93d838a77391ec0acanthony v; 960602ab9b30b644a78a4057da93d838a77391ec0acanthony 961602ab9b30b644a78a4057da93d838a77391ec0acanthony double 962602ab9b30b644a78a4057da93d838a77391ec0acanthony nan = sqrt((double)-1.0); /* Special Value : Not A Number */ 963602ab9b30b644a78a4057da93d838a77391ec0acanthony 964c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Generate a new empty kernel if needed */ 965e96405a0f45f803fb9c26f75e7bdee252437febbcristy kernel=(KernelInfo *) NULL; 966c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony switch(type) { 9671dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case UndefinedKernel: /* These should not call this function */ 9689eb4f74649b23c053b308ce1152dce51239450baanthony case UserDefinedKernel: 969529482f4b494010a13338a74446c510712f670b3anthony assert("Should not call this function" != (char *)NULL); 9709eb4f74649b23c053b308ce1152dce51239450baanthony break; 971529482f4b494010a13338a74446c510712f670b3anthony case LaplacianKernel: /* Named Descrete Convolution Kernels */ 972529482f4b494010a13338a74446c510712f670b3anthony case SobelKernel: /* these are defined using other kernels */ 9739eb4f74649b23c053b308ce1152dce51239450baanthony case RobertsKernel: 9749eb4f74649b23c053b308ce1152dce51239450baanthony case PrewittKernel: 9759eb4f74649b23c053b308ce1152dce51239450baanthony case CompassKernel: 9769eb4f74649b23c053b308ce1152dce51239450baanthony case KirschKernel: 9771dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case FreiChenKernel: 978694934fa79dd310f727588b1d0a7481fa6170f1danthony case EdgesKernel: /* Hit and Miss kernels */ 979694934fa79dd310f727588b1d0a7481fa6170f1danthony case CornersKernel: 980529482f4b494010a13338a74446c510712f670b3anthony case DiagonalsKernel: 9819eb4f74649b23c053b308ce1152dce51239450baanthony case LineEndsKernel: 9829eb4f74649b23c053b308ce1152dce51239450baanthony case LineJunctionsKernel: 9831dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case RidgesKernel: 9849eb4f74649b23c053b308ce1152dce51239450baanthony case ConvexHullKernel: 9859eb4f74649b23c053b308ce1152dce51239450baanthony case SkeletonKernel: 9869a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case ThinSEKernel: 987c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; /* A pre-generated kernel is not needed */ 988c40ac1e79923a1516075ba1197ae4ed90244af9banthony#if 0 989c40ac1e79923a1516075ba1197ae4ed90244af9banthony /* set to 1 to do a compile-time check that we haven't missed anything */ 990529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 991c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case GaussianKernel: 992501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 993501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 994c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case BlurKernel: 995c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CometKernel: 99640ca0b982379d4ab2716435a46603d56b5b218b1anthony case BinomialKernel: 997c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiamondKernel: 998c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SquareKernel: 999c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RectangleKernel: 10001ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 1001c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiskKernel: 1002c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PlusKernel: 1003c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CrossKernel: 1004c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RingKernel: 1005c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PeaksKernel: 1006c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case ChebyshevKernel: 1007bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 10081ef941fea2534a0d20ba7d71307d35040247decbanthony case OctangonalKernel: 1009c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case EuclideanKernel: 10101dd091ae3bc17edc26c16cc47f436a24bd48412aanthony#else 10119eb4f74649b23c053b308ce1152dce51239450baanthony default: 10121dd091ae3bc17edc26c16cc47f436a24bd48412aanthony#endif 10139eb4f74649b23c053b308ce1152dce51239450baanthony /* Generate the base Kernel Structure */ 1014c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel)); 1015c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1016c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1017c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony (void) ResetMagickMemory(kernel,0,sizeof(*kernel)); 101843c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->minimum = kernel->maximum = kernel->angle = 0.0; 1019c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->negative_range = kernel->positive_range = 0.0; 1020c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 1021c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->next = (KernelInfo *) NULL; 1022c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->signature = MagickSignature; 1023c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1024c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1025602ab9b30b644a78a4057da93d838a77391ec0acanthony 1026602ab9b30b644a78a4057da93d838a77391ec0acanthony switch(type) { 1027529482f4b494010a13338a74446c510712f670b3anthony /* 1028529482f4b494010a13338a74446c510712f670b3anthony Convolution Kernels 1029529482f4b494010a13338a74446c510712f670b3anthony */ 1030529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 1031529482f4b494010a13338a74446c510712f670b3anthony { 1032529482f4b494010a13338a74446c510712f670b3anthony kernel->height = kernel->width = (size_t) 1; 1033529482f4b494010a13338a74446c510712f670b3anthony kernel->x = kernel->y = (ssize_t) 0; 1034e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1035e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(1,sizeof(*kernel->values))); 1036d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 1037529482f4b494010a13338a74446c510712f670b3anthony return(DestroyKernelInfo(kernel)); 1038529482f4b494010a13338a74446c510712f670b3anthony kernel->maximum = kernel->values[0] = args->rho; 1039529482f4b494010a13338a74446c510712f670b3anthony break; 1040529482f4b494010a13338a74446c510712f670b3anthony } 1041529482f4b494010a13338a74446c510712f670b3anthony break; 1042602ab9b30b644a78a4057da93d838a77391ec0acanthony case GaussianKernel: 1043501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 1044501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 1045602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 1046c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma = fabs(args->sigma), 1047c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma2 = fabs(args->xi), 10489eb4f74649b23c053b308ce1152dce51239450baanthony A, B, R; 1049c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1050c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( args->rho >= 1.0 ) 1051bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho*2+1; 1052501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony else if ( (type != DoGKernel) || (sigma >= sigma2) ) 1053c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = GetOptimalKernelWidth2D(args->rho,sigma); 1054c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1055c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2); 1056c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->height = kernel->width; 1057bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 1058e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1059e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1060e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1061d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 106283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1063602ab9b30b644a78a4057da93d838a77391ec0acanthony 106446a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* WARNING: The following generates a 'sampled gaussian' kernel. 10659eb4f74649b23c053b308ce1152dce51239450baanthony * What we really want is a 'discrete gaussian' kernel. 106646a369d839971ab627bdb31a93d8bd63e81b65a3anthony * 1067529482f4b494010a13338a74446c510712f670b3anthony * How to do this is I don't know, but appears to be basied on the 1068529482f4b494010a13338a74446c510712f670b3anthony * Error Function 'erf()' (intergral of a gaussian) 10699eb4f74649b23c053b308ce1152dce51239450baanthony */ 10709eb4f74649b23c053b308ce1152dce51239450baanthony 1071501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == GaussianKernel || type == DoGKernel ) 1072501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony { /* Calculate a Gaussian, OR positive half of a DoG */ 10739eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 10749eb4f74649b23c053b308ce1152dce51239450baanthony { A = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 107555a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(Magick2PI*sigma*sigma)); 1076bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1077bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 10789eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] = exp(-((double)(u*u+v*v))*A)*B; 10799eb4f74649b23c053b308ce1152dce51239450baanthony } 10809eb4f74649b23c053b308ce1152dce51239450baanthony else /* limiting case - a unity (normalized Dirac) kernel */ 10819eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 108275920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*kernel->height*sizeof(*kernel->values)); 10839eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 10849eb4f74649b23c053b308ce1152dce51239450baanthony } 1085c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 10869eb4f74649b23c053b308ce1152dce51239450baanthony 1087501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == DoGKernel ) 1088c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { /* Subtract a Negative Gaussian for "Difference of Gaussian" */ 1089c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma2 > MagickEpsilon ) 1090c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { sigma = sigma2; /* simplify loop expressions */ 10919eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); 109255a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(Magick2PI*sigma*sigma)); 1093bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1094bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 10959eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] -= exp(-((double)(u*u+v*v))*A)*B; 1096c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 10979eb4f74649b23c053b308ce1152dce51239450baanthony else /* limiting case - a unity (normalized Dirac) kernel */ 1098c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] -= 1.0; 1099c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 11009eb4f74649b23c053b308ce1152dce51239450baanthony 1101501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == LoGKernel ) 11029eb4f74649b23c053b308ce1152dce51239450baanthony { /* Calculate a Laplacian of a Gaussian - Or Mexician Hat */ 11039eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 11049eb4f74649b23c053b308ce1152dce51239450baanthony { A = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 110555a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(MagickPI*sigma*sigma*sigma*sigma)); 1106bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1107bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 11089eb4f74649b23c053b308ce1152dce51239450baanthony { R = ((double)(u*u+v*v))*A; 11099eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] = (1-R)*exp(-R)*B; 11109eb4f74649b23c053b308ce1152dce51239450baanthony } 11119eb4f74649b23c053b308ce1152dce51239450baanthony } 11129eb4f74649b23c053b308ce1152dce51239450baanthony else /* special case - generate a unity kernel */ 11139eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 111475920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*kernel->height*sizeof(*kernel->values)); 11159eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 11169eb4f74649b23c053b308ce1152dce51239450baanthony } 11179eb4f74649b23c053b308ce1152dce51239450baanthony } 11189eb4f74649b23c053b308ce1152dce51239450baanthony 11199eb4f74649b23c053b308ce1152dce51239450baanthony /* Note the above kernels may have been 'clipped' by a user defined 1120c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** radius, producing a smaller (darker) kernel. Also for very small 1121c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** sigma's (> 0.1) the central value becomes larger than one, and thus 1122c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** producing a very bright kernel. 1123c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 1124c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** Normalization will still be needed. 1125c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony */ 1126602ab9b30b644a78a4057da93d838a77391ec0acanthony 11273dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* Normalize the 2D Gaussian Kernel 11283dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** 1129c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** NB: a CorrelateNormalize performs a normal Normalize if 1130c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there are no negative values. 11313dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony */ 113246a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* the other kernel meta-data */ 1133c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue); 1134602ab9b30b644a78a4057da93d838a77391ec0acanthony 1135602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1136602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1137602ab9b30b644a78a4057da93d838a77391ec0acanthony case BlurKernel: 1138602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 1139c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma = fabs(args->sigma), 1140501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony alpha, beta; 1141602ab9b30b644a78a4057da93d838a77391ec0acanthony 1142c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( args->rho >= 1.0 ) 1143bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho*2+1; 1144c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1145501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->width = GetOptimalKernelWidth1D(args->rho,sigma); 1146602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height = 1; 1147bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) (kernel->width-1)/2; 1148c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->y = 0; 1149c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 1150e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1151e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1152e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1153d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 115483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1155602ab9b30b644a78a4057da93d838a77391ec0acanthony 1156602ab9b30b644a78a4057da93d838a77391ec0acanthony#if 1 1157602ab9b30b644a78a4057da93d838a77391ec0acanthony#define KernelRank 3 1158602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Formula derived from GetBlurKernel() in "effect.c" (plus bug fix). 1159602ab9b30b644a78a4057da93d838a77391ec0acanthony ** It generates a gaussian 3 times the width, and compresses it into 1160602ab9b30b644a78a4057da93d838a77391ec0acanthony ** the expected range. This produces a closer normalization of the 1161602ab9b30b644a78a4057da93d838a77391ec0acanthony ** resulting kernel, especially for very low sigma values. 1162602ab9b30b644a78a4057da93d838a77391ec0acanthony ** As such while wierd it is prefered. 1163602ab9b30b644a78a4057da93d838a77391ec0acanthony ** 1164602ab9b30b644a78a4057da93d838a77391ec0acanthony ** I am told this method originally came from Photoshop. 11659eb4f74649b23c053b308ce1152dce51239450baanthony ** 11669eb4f74649b23c053b308ce1152dce51239450baanthony ** A properly normalized curve is generated (apart from edge clipping) 11679eb4f74649b23c053b308ce1152dce51239450baanthony ** even though we later normalize the result (for edge clipping) 11689eb4f74649b23c053b308ce1152dce51239450baanthony ** to allow the correct generation of a "Difference of Blurs". 1169602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 1170c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1171c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* initialize */ 1172bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy v = (ssize_t) (kernel->width*KernelRank-1)/2; /* start/end points to fit range */ 11739eb4f74649b23c053b308ce1152dce51239450baanthony (void) ResetMagickMemory(kernel->values,0, (size_t) 117475920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*kernel->height*sizeof(*kernel->values)); 1175c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Calculate a Positive 1D Gaussian */ 1176c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma > MagickEpsilon ) 1177c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { sigma *= KernelRank; /* simplify loop expressions */ 1178501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony alpha = 1.0/(2.0*sigma*sigma); 117955a91cddcdea3aa002893186a773e1704884a9dfcristy beta= (double) (1.0/(MagickSQ2PI*sigma )); 1180c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony for ( u=-v; u <= v; u++) { 1181501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[(u+v)/KernelRank] += 1182501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony exp(-((double)(u*u))*alpha)*beta; 1183c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1184c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1185c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else /* special case - generate a unity kernel */ 1186c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 1187602ab9b30b644a78a4057da93d838a77391ec0acanthony#else 118853f576d128f0bb744a82e7f9c0d8f05b2923972canthony /* Direct calculation without curve averaging 118953f576d128f0bb744a82e7f9c0d8f05b2923972canthony This is equivelent to a KernelRank of 1 */ 1190c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1191c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Calculate a Positive Gaussian */ 1192c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma > MagickEpsilon ) 1193501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony { alpha = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 1194501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony beta = 1.0/(MagickSQ2PI*sigma); 1195bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 1196501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[i] = exp(-((double)(u*u))*alpha)*beta; 1197c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1198c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else /* special case - generate a unity kernel */ 1199c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 120075920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*kernel->height*sizeof(*kernel->values)); 1201c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 1202c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1203602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 1204c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Note the above kernel may have been 'clipped' by a user defined 1205cc6c836da2a53b6023b716e4973090a6714dc3b0anthony ** radius, producing a smaller (darker) kernel. Also for very small 120653f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** sigma's (> 0.1) the central value becomes larger than one, as a 120753f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** result of not generating a actual 'discrete' kernel, and thus 120853f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** producing a very bright 'impulse'. 1209c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 121053f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** Becuase of these two factors Normalization is required! 1211602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 1212cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 1213602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Normalize the 1D Gaussian Kernel 1214602ab9b30b644a78a4057da93d838a77391ec0acanthony ** 1215c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** NB: a CorrelateNormalize performs a normal Normalize if 1216c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there are no negative values. 1217602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 121846a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* the other kernel meta-data */ 121946a369d839971ab627bdb31a93d8bd63e81b65a3anthony ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue); 1220cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 1221c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* rotate the 1D kernel by given angle */ 1222501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony RotateKernelInfo(kernel, args->xi ); 1223602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1224602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1225602ab9b30b644a78a4057da93d838a77391ec0acanthony case CometKernel: 1226602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 12279eb4f74649b23c053b308ce1152dce51239450baanthony sigma = fabs(args->sigma), 12289eb4f74649b23c053b308ce1152dce51239450baanthony A; 1229602ab9b30b644a78a4057da93d838a77391ec0acanthony 1230602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->rho < 1.0 ) 1231e1cf9465864144e8b8043d522906c1e47bbf6192anthony kernel->width = (GetOptimalKernelWidth1D(args->rho,sigma)-1)/2+1; 1232602ab9b30b644a78a4057da93d838a77391ec0acanthony else 1233bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho; 1234c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->x = kernel->y = 0; 1235602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height = 1; 1236c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 1237e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1238e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1239e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1240d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 124183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1242602ab9b30b644a78a4057da93d838a77391ec0acanthony 1243c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* A comet blur is half a 1D gaussian curve, so that the object is 1244602ab9b30b644a78a4057da93d838a77391ec0acanthony ** blurred in one direction only. This may not be quite the right 12453dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** curve to use so may change in the future. The function must be 12463dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** normalised after generation, which also resolves any clipping. 1247c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 1248c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** As we are normalizing and not subtracting gaussians, 1249c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there is no need for a divisor in the gaussian formula 1250c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 125143c4925e5305a26e48d68f7893e94f55d0831c39anthony ** It is less comples 1252602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 12539eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 12549eb4f74649b23c053b308ce1152dce51239450baanthony { 1255602ab9b30b644a78a4057da93d838a77391ec0acanthony#if 1 1256602ab9b30b644a78a4057da93d838a77391ec0acanthony#define KernelRank 3 1257bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy v = (ssize_t) kernel->width*KernelRank; /* start/end points */ 12589eb4f74649b23c053b308ce1152dce51239450baanthony (void) ResetMagickMemory(kernel->values,0, (size_t) 125975920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*sizeof(*kernel->values)); 12609eb4f74649b23c053b308ce1152dce51239450baanthony sigma *= KernelRank; /* simplify the loop expression */ 12619eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); 12629eb4f74649b23c053b308ce1152dce51239450baanthony /* B = 1.0/(MagickSQ2PI*sigma); */ 12639eb4f74649b23c053b308ce1152dce51239450baanthony for ( u=0; u < v; u++) { 12649eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[u/KernelRank] += 12659eb4f74649b23c053b308ce1152dce51239450baanthony exp(-((double)(u*u))*A); 12669eb4f74649b23c053b308ce1152dce51239450baanthony /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */ 12679eb4f74649b23c053b308ce1152dce51239450baanthony } 1268bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) kernel->width; i++) 12699eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range += kernel->values[i]; 1270602ab9b30b644a78a4057da93d838a77391ec0acanthony#else 12719eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); /* simplify the loop expression */ 12729eb4f74649b23c053b308ce1152dce51239450baanthony /* B = 1.0/(MagickSQ2PI*sigma); */ 1273bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0; i < (ssize_t) kernel->width; i++) 12749eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range += 127553f576d128f0bb744a82e7f9c0d8f05b2923972canthony kernel->values[i] = exp(-((double)(i*i))*A); 12769eb4f74649b23c053b308ce1152dce51239450baanthony /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */ 1277602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 12789eb4f74649b23c053b308ce1152dce51239450baanthony } 12799eb4f74649b23c053b308ce1152dce51239450baanthony else /* special case - generate a unity kernel */ 12809eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 128175920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*kernel->height*sizeof(*kernel->values)); 12829eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 12839eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range = 1.0; 12849eb4f74649b23c053b308ce1152dce51239450baanthony } 128546a369d839971ab627bdb31a93d8bd63e81b65a3anthony 128646a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->minimum = 0.0; 1287c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 128846a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->negative_range = 0.0; 1289602ab9b30b644a78a4057da93d838a77391ec0acanthony 1290999bb2c20aa9d42875bb5adba44951988d4ae354anthony ScaleKernelInfo(kernel, 1.0, NormalizeValue); /* Normalize */ 1291999bb2c20aa9d42875bb5adba44951988d4ae354anthony RotateKernelInfo(kernel, args->xi); /* Rotate by angle */ 1292602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1293602ab9b30b644a78a4057da93d838a77391ec0acanthony } 129440ca0b982379d4ab2716435a46603d56b5b218b1anthony case BinomialKernel: 129540ca0b982379d4ab2716435a46603d56b5b218b1anthony { 129640ca0b982379d4ab2716435a46603d56b5b218b1anthony size_t 129740ca0b982379d4ab2716435a46603d56b5b218b1anthony order_f; 129840ca0b982379d4ab2716435a46603d56b5b218b1anthony 129940ca0b982379d4ab2716435a46603d56b5b218b1anthony if (args->rho < 1.0) 130040ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->width = kernel->height = 3; /* default radius = 1 */ 130140ca0b982379d4ab2716435a46603d56b5b218b1anthony else 130240ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 130340ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 130440ca0b982379d4ab2716435a46603d56b5b218b1anthony 130540ca0b982379d4ab2716435a46603d56b5b218b1anthony order_f = fact(kernel->width-1); 130640ca0b982379d4ab2716435a46603d56b5b218b1anthony 1307e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1308e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1309e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1310d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 131140ca0b982379d4ab2716435a46603d56b5b218b1anthony return(DestroyKernelInfo(kernel)); 131240ca0b982379d4ab2716435a46603d56b5b218b1anthony 131340ca0b982379d4ab2716435a46603d56b5b218b1anthony /* set all kernel values within diamond area to scale given */ 131440ca0b982379d4ab2716435a46603d56b5b218b1anthony for ( i=0, v=0; v < (ssize_t)kernel->height; v++) 131540ca0b982379d4ab2716435a46603d56b5b218b1anthony { size_t 1316f13c594b1d9509e479fd845c3b8a5bb1351c32eacristy alpha = order_f / ( fact((size_t) v) * fact(kernel->height-v-1) ); 131740ca0b982379d4ab2716435a46603d56b5b218b1anthony for ( u=0; u < (ssize_t)kernel->width; u++, i++) 131840ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->positive_range += kernel->values[i] = (double) 1319f13c594b1d9509e479fd845c3b8a5bb1351c32eacristy (alpha * order_f / ( fact((size_t) u) * fact(kernel->height-u-1) )); 132040ca0b982379d4ab2716435a46603d56b5b218b1anthony } 132140ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->minimum = 1.0; 132240ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->maximum = kernel->values[kernel->x+kernel->y*kernel->width]; 132340ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->negative_range = 0.0; 132440ca0b982379d4ab2716435a46603d56b5b218b1anthony break; 132540ca0b982379d4ab2716435a46603d56b5b218b1anthony } 1326c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1327529482f4b494010a13338a74446c510712f670b3anthony /* 1328529482f4b494010a13338a74446c510712f670b3anthony Convolution Kernels - Well Known Named Constant Kernels 1329529482f4b494010a13338a74446c510712f670b3anthony */ 13303c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony case LaplacianKernel: 1331e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony { switch ( (int) args->rho ) { 13323dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case 0: 13339eb4f74649b23c053b308ce1152dce51239450baanthony default: /* laplacian square filter -- default */ 1334c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: -1,-1,-1 -1,8,-1 -1,-1,-1"); 13353dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony break; 13369eb4f74649b23c053b308ce1152dce51239450baanthony case 1: /* laplacian diamond filter */ 1337c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: 0,-1,0 -1,4,-1 0,-1,0"); 13383c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13393c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony case 2: 13409eb4f74649b23c053b308ce1152dce51239450baanthony kernel=ParseKernelArray("3: -2,1,-2 1,4,1 -2,1,-2"); 13419eb4f74649b23c053b308ce1152dce51239450baanthony break; 13429eb4f74649b23c053b308ce1152dce51239450baanthony case 3: 1343c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: 1,-2,1 -2,4,-2 1,-2,1"); 13443c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13459eb4f74649b23c053b308ce1152dce51239450baanthony case 5: /* a 5x5 laplacian */ 13463c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel=ParseKernelArray( 13479eb4f74649b23c053b308ce1152dce51239450baanthony "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"); 13483c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13499eb4f74649b23c053b308ce1152dce51239450baanthony case 7: /* a 7x7 laplacian */ 13503c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel=ParseKernelArray( 1351c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony "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" ); 13523c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 1353501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case 15: /* a 5x5 LoG (sigma approx 1.4) */ 13549eb4f74649b23c053b308ce1152dce51239450baanthony kernel=ParseKernelArray( 13559eb4f74649b23c053b308ce1152dce51239450baanthony "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"); 13569eb4f74649b23c053b308ce1152dce51239450baanthony break; 1357501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case 19: /* a 9x9 LoG (sigma approx 1.4) */ 135843c4925e5305a26e48d68f7893e94f55d0831c39anthony /* http://www.cscjournals.org/csc/manuscript/Journals/IJIP/volume3/Issue1/IJIP-15.pdf */ 135943c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel=ParseKernelArray( 1360bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony "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"); 136143c4925e5305a26e48d68f7893e94f55d0831c39anthony break; 13623c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 13633c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if (kernel == (KernelInfo *) NULL) 13643c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony return(kernel); 13653c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->type = type; 13663c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13673c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 1368c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SobelKernel: 1369cceb6f05c2016ea3854b29e7770ec5ff49034ecfanthony { /* Simple Sobel Kernel */ 1370dcc2a474c98415e565434fe52f630acba36fa0c1anthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1371dcc2a474c98415e565434fe52f630acba36fa0c1anthony if (kernel == (KernelInfo *) NULL) 1372dcc2a474c98415e565434fe52f630acba36fa0c1anthony return(kernel); 1373dcc2a474c98415e565434fe52f630acba36fa0c1anthony kernel->type = type; 1374dcc2a474c98415e565434fe52f630acba36fa0c1anthony RotateKernelInfo(kernel, args->rho); 1375dcc2a474c98415e565434fe52f630acba36fa0c1anthony break; 1376dcc2a474c98415e565434fe52f630acba36fa0c1anthony } 1377c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RobertsKernel: 1378c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1379501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 0,0,0 1,-1,0 0,0,0"); 1380c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1381c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1382c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 138346a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1384c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1385c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1386c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PrewittKernel: 1387c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1388501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 1,0,-1 1,0,-1"); 1389c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1390c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1391c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 139246a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1393c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1394c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1395c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CompassKernel: 1396c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1397501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,1,-1 1,-2,-1 1,1,-1"); 1398c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1399c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1400c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 140146a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1402c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1403c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 14049eb4f74649b23c053b308ce1152dce51239450baanthony case KirschKernel: 14059eb4f74649b23c053b308ce1152dce51239450baanthony { 1406501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 5,-3,-3 5,0,-3 5,-3,-3"); 14079eb4f74649b23c053b308ce1152dce51239450baanthony if (kernel == (KernelInfo *) NULL) 14089eb4f74649b23c053b308ce1152dce51239450baanthony return(kernel); 14099eb4f74649b23c053b308ce1152dce51239450baanthony kernel->type = type; 141046a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 14119eb4f74649b23c053b308ce1152dce51239450baanthony break; 14129eb4f74649b23c053b308ce1152dce51239450baanthony } 1413e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony case FreiChenKernel: 1414501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* Direction is set to be left to right positive */ 1415501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf -- RIGHT? */ 1416501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf -- WRONG? */ 14171dd091ae3bc17edc26c16cc47f436a24bd48412aanthony { switch ( (int) args->rho ) { 1418e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony default: 1419c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony case 0: 1420501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1421c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony if (kernel == (KernelInfo *) NULL) 1422c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony return(kernel); 1423ef33d9f66f955c1f6f5f7105e164cc2d5c5e2a41anthony kernel->type = type; 1424d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[3] = +(MagickRealType) MagickSQ2; 1425d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[5] = -(MagickRealType) MagickSQ2; 1426c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 1427c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony break; 1428c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 2: 1429c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel=ParseKernelArray("3: 1,2,0 2,0,-2 0,-2,-1"); 1430c40ac1e79923a1516075ba1197ae4ed90244af9banthony if (kernel == (KernelInfo *) NULL) 1431c40ac1e79923a1516075ba1197ae4ed90244af9banthony return(kernel); 1432c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel->type = type; 1433d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[1] = kernel->values[3]= +(MagickRealType) MagickSQ2; 1434d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[5] = kernel->values[7]= -(MagickRealType) MagickSQ2; 1435c40ac1e79923a1516075ba1197ae4ed90244af9banthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 1436d4e3ffa7f64077da0f32c2d8a599737ee8d115ddcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1437c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; 1438c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 10: 1439c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel=AcquireKernelInfo("FreiChen:11;FreiChen:12;FreiChen:13;FreiChen:14;FreiChen:15;FreiChen:16;FreiChen:17;FreiChen:18;FreiChen:19"); 1440c40ac1e79923a1516075ba1197ae4ed90244af9banthony if (kernel == (KernelInfo *) NULL) 1441c40ac1e79923a1516075ba1197ae4ed90244af9banthony return(kernel); 1442c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; 1443e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony case 1: 1444c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 11: 1445501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1446e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1447e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1448c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1449d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[3] = +(MagickRealType) MagickSQ2; 1450d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[5] = -(MagickRealType) MagickSQ2; 1451e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 145255a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1453e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1454c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 12: 1455501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,2,1 0,0,0 1,2,1"); 1456e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1457e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1458c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1459d9123437a79f9d56a3e8c32aa912ae3ae1d47337cristy kernel->values[1] = +(MagickRealType) MagickSQ2; 1460d9123437a79f9d56a3e8c32aa912ae3ae1d47337cristy kernel->values[7] = +(MagickRealType) MagickSQ2; 1461e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 146255a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1463e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1464c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 13: 1465501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 2,-1,0 -1,0,1 0,1,-2"); 1466e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1467e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1468c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1469d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[0] = +(MagickRealType) MagickSQ2; 1470d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[8] = -(MagickRealType) MagickSQ2; 1471e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 147255a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1473e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1474c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 14: 14751d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel=ParseKernelArray("3: 0,1,-2 -1,0,1 2,-1,0"); 1476e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1477e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1478c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1479d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[2] = -(MagickRealType) MagickSQ2; 1480d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[6] = +(MagickRealType) MagickSQ2; 1481e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 148255a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1483e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1484c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 15: 1485501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 0,-1,0 1,0,1 0,-1,0"); 1486e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1487e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1488c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1489e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/2.0, NoValue); 1490e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1491c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 16: 14921d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel=ParseKernelArray("3: 1,0,-1 0,0,0 -1,0,1"); 1493e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1494e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1495c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1496e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/2.0, NoValue); 1497e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1498c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 17: 1499501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,-2,1 -2,4,-2 -1,-2,1"); 1500e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1501e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1502c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1503e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/6.0, NoValue); 1504e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1505c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 18: 1506501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: -2,1,-2 1,4,1 -2,1,-2"); 1507e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1508e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1509c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1510e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/6.0, NoValue); 1511e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1512c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 19: 1513c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel=ParseKernelArray("3: 1,1,1 1,1,1 1,1,1"); 1514e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1515e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1516c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1517e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/3.0, NoValue); 1518e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1519e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony } 1520b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(args->sigma) >= MagickEpsilon ) 1521c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony /* Rotate by correctly supplied 'angle' */ 1522c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony RotateKernelInfo(kernel, args->sigma); 1523c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony else if ( args->rho > 30.0 || args->rho < -30.0 ) 1524c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony /* Rotate by out of bounds 'type' */ 1525c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony RotateKernelInfo(kernel, args->rho); 1526e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1527e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony } 1528e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony 1529529482f4b494010a13338a74446c510712f670b3anthony /* 1530529482f4b494010a13338a74446c510712f670b3anthony Boolean or Shaped Kernels 1531529482f4b494010a13338a74446c510712f670b3anthony */ 1532c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiamondKernel: 1533602ab9b30b644a78a4057da93d838a77391ec0acanthony { 1534c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (args->rho < 1.0) 1535c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = kernel->height = 3; /* default radius = 1 */ 1536c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1537bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = ((size_t)args->rho)*2+1; 1538bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 1539c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1540e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1541e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1542e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1543d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 1544c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(DestroyKernelInfo(kernel)); 1545c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1546c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* set all kernel values within diamond area to scale given */ 1547bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1548bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 15491d5e67090dc7232b35bfcc71b31266c20838defcanthony if ( (labs((long) u)+labs((long) v)) <= (long) kernel->x) 1550c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->positive_range += kernel->values[i] = args->sigma; 1551c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1552c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[i] = nan; 1553c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 1554c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1555c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1556c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SquareKernel: 1557c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RectangleKernel: 1558c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { double 1559c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony scale; 1560602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( type == SquareKernel ) 1561602ab9b30b644a78a4057da93d838a77391ec0acanthony { 1562602ab9b30b644a78a4057da93d838a77391ec0acanthony if (args->rho < 1.0) 1563c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 1564602ab9b30b644a78a4057da93d838a77391ec0acanthony else 1565bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = (size_t) (2*args->rho+1); 1566bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 15674fd27e21043be809d66c8202e779255e5b660d2danthony scale = args->sigma; 1568602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1569602ab9b30b644a78a4057da93d838a77391ec0acanthony else { 15702be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy /* NOTE: user defaults set in "AcquireKernelInfo()" */ 1571602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->rho < 1.0 || args->sigma < 1.0 ) 157283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); /* invalid args given */ 1573bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho; 1574bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t)args->sigma; 1575602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->xi < 0.0 || args->xi > (double)kernel->width || 1576602ab9b30b644a78a4057da93d838a77391ec0acanthony args->psi < 0.0 || args->psi > (double)kernel->height ) 157783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); /* invalid args given */ 1578bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) args->xi; 1579bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = (ssize_t) args->psi; 15804fd27e21043be809d66c8202e779255e5b660d2danthony scale = 1.0; 1581602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1582e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1583e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1584e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1585d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 158683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1587602ab9b30b644a78a4057da93d838a77391ec0acanthony 15883dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* set all kernel values to scale given */ 1589eaedf06777741da32408da72c1e512975c600c48cristy u=(ssize_t) (kernel->width*kernel->height); 1590150989ed67ef9da53141a65e5f3ebdb05dd025abcristy for ( i=0; i < u; i++) 15914fd27e21043be809d66c8202e779255e5b660d2danthony kernel->values[i] = scale; 15924fd27e21043be809d66c8202e779255e5b660d2danthony kernel->minimum = kernel->maximum = scale; /* a flat shape */ 15934fd27e21043be809d66c8202e779255e5b660d2danthony kernel->positive_range = scale*u; 1594cc6c836da2a53b6023b716e4973090a6714dc3b0anthony break; 1595602ab9b30b644a78a4057da93d838a77391ec0acanthony } 15961ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 15971ef941fea2534a0d20ba7d71307d35040247decbanthony { 15981ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 1599a9892d898acb81e1ec73106d892855fdc5a69427anthony kernel->width = kernel->height = 5; /* default radius = 2 */ 16001ef941fea2534a0d20ba7d71307d35040247decbanthony else 16011ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 16021ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16031ef941fea2534a0d20ba7d71307d35040247decbanthony 1604e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1605e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1606e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1607d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 16081ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16091ef941fea2534a0d20ba7d71307d35040247decbanthony 16101ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16111ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16121ef941fea2534a0d20ba7d71307d35040247decbanthony if ( (labs((long) u)+labs((long) v)) <= 16131ef941fea2534a0d20ba7d71307d35040247decbanthony ((long)kernel->x + (long)(kernel->x/2)) ) 16141ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = args->sigma; 16151ef941fea2534a0d20ba7d71307d35040247decbanthony else 16161ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = nan; 1617a9892d898acb81e1ec73106d892855fdc5a69427anthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16181ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16191ef941fea2534a0d20ba7d71307d35040247decbanthony } 16201ef941fea2534a0d20ba7d71307d35040247decbanthony case DiskKernel: 16211ef941fea2534a0d20ba7d71307d35040247decbanthony { 16221ef941fea2534a0d20ba7d71307d35040247decbanthony ssize_t 16230bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony limit = (ssize_t)(args->rho*args->rho); 16241ef941fea2534a0d20ba7d71307d35040247decbanthony 16259bf68d590429a72aa70894f6aea7fc3c94876e54anthony if (args->rho < 0.4) /* default radius approx 4.3 */ 16269bf68d590429a72aa70894f6aea7fc3c94876e54anthony kernel->width = kernel->height = 9L, limit = 18L; 16271ef941fea2534a0d20ba7d71307d35040247decbanthony else 16281ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = (size_t)fabs(args->rho)*2+1; 16291ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16301ef941fea2534a0d20ba7d71307d35040247decbanthony 1631e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1632e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1633e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1634d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 16351ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16361ef941fea2534a0d20ba7d71307d35040247decbanthony 16371ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16381ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16391ef941fea2534a0d20ba7d71307d35040247decbanthony if ((u*u+v*v) <= limit) 16401ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = args->sigma; 16413dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony else 16423dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony kernel->values[i] = nan; 16431ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16441ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16451ef941fea2534a0d20ba7d71307d35040247decbanthony } 16461ef941fea2534a0d20ba7d71307d35040247decbanthony case PlusKernel: 16471ef941fea2534a0d20ba7d71307d35040247decbanthony { 16481ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 16491ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default radius 2 */ 16501ef941fea2534a0d20ba7d71307d35040247decbanthony else 16511ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 16521ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16531ef941fea2534a0d20ba7d71307d35040247decbanthony 1654e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1655e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1656e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1657d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 16581ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16591ef941fea2534a0d20ba7d71307d35040247decbanthony 16601ef941fea2534a0d20ba7d71307d35040247decbanthony /* set all kernel values along axises to given scale */ 16611ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16621ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16631ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan; 16641ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16651ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0); 16661ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16671ef941fea2534a0d20ba7d71307d35040247decbanthony } 16681ef941fea2534a0d20ba7d71307d35040247decbanthony case CrossKernel: 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 == v || u == -v) ? 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 } 1690529482f4b494010a13338a74446c510712f670b3anthony /* 1691529482f4b494010a13338a74446c510712f670b3anthony HitAndMiss Kernels 1692529482f4b494010a13338a74446c510712f670b3anthony */ 16931ef941fea2534a0d20ba7d71307d35040247decbanthony case RingKernel: 16941ef941fea2534a0d20ba7d71307d35040247decbanthony case PeaksKernel: 16951ef941fea2534a0d20ba7d71307d35040247decbanthony { 16961ef941fea2534a0d20ba7d71307d35040247decbanthony ssize_t 16971ef941fea2534a0d20ba7d71307d35040247decbanthony limit1, 16981ef941fea2534a0d20ba7d71307d35040247decbanthony limit2, 16991ef941fea2534a0d20ba7d71307d35040247decbanthony scale; 17001ef941fea2534a0d20ba7d71307d35040247decbanthony 17011ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < args->sigma) 17021ef941fea2534a0d20ba7d71307d35040247decbanthony { 17031ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = ((size_t)args->sigma)*2+1; 17041ef941fea2534a0d20ba7d71307d35040247decbanthony limit1 = (ssize_t)(args->rho*args->rho); 17051ef941fea2534a0d20ba7d71307d35040247decbanthony limit2 = (ssize_t)(args->sigma*args->sigma); 17063dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony } 17071ef941fea2534a0d20ba7d71307d35040247decbanthony else 17081ef941fea2534a0d20ba7d71307d35040247decbanthony { 17091ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = ((size_t)args->rho)*2+1; 17101ef941fea2534a0d20ba7d71307d35040247decbanthony limit1 = (ssize_t)(args->sigma*args->sigma); 17111ef941fea2534a0d20ba7d71307d35040247decbanthony limit2 = (ssize_t)(args->rho*args->rho); 17121ef941fea2534a0d20ba7d71307d35040247decbanthony } 17131ef941fea2534a0d20ba7d71307d35040247decbanthony if ( limit2 <= 0 ) 17141ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = 7L, limit1 = 7L, limit2 = 11L; 17151ef941fea2534a0d20ba7d71307d35040247decbanthony 17161ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height = kernel->width; 17171ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 1718e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1719e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1720e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1721d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 17221ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 17231ef941fea2534a0d20ba7d71307d35040247decbanthony 17241ef941fea2534a0d20ba7d71307d35040247decbanthony /* set a ring of points of 'scale' ( 0.0 for PeaksKernel ) */ 17251ef941fea2534a0d20ba7d71307d35040247decbanthony scale = (ssize_t) (( type == PeaksKernel) ? 0.0 : args->xi); 17261ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v= -kernel->y; v <= (ssize_t)kernel->y; v++) 17271ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 17281ef941fea2534a0d20ba7d71307d35040247decbanthony { ssize_t radius=u*u+v*v; 17291ef941fea2534a0d20ba7d71307d35040247decbanthony if (limit1 < radius && radius <= limit2) 17301ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = (double) scale; 17311ef941fea2534a0d20ba7d71307d35040247decbanthony else 17321ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = nan; 17331ef941fea2534a0d20ba7d71307d35040247decbanthony } 17341ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = (double) scale; 17351ef941fea2534a0d20ba7d71307d35040247decbanthony if ( type == PeaksKernel ) { 17361ef941fea2534a0d20ba7d71307d35040247decbanthony /* set the central point in the middle */ 17371ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 17381ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = 1.0; 17391ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = 1.0; 17401ef941fea2534a0d20ba7d71307d35040247decbanthony } 17411ef941fea2534a0d20ba7d71307d35040247decbanthony break; 1742c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 17431ef941fea2534a0d20ba7d71307d35040247decbanthony case EdgesKernel: 17441ef941fea2534a0d20ba7d71307d35040247decbanthony { 1745529482f4b494010a13338a74446c510712f670b3anthony kernel=AcquireKernelInfo("ThinSE:482"); 17461ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17471ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17481ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 1749529482f4b494010a13338a74446c510712f670b3anthony ExpandMirrorKernelInfo(kernel); /* mirror expansion of kernels */ 17501ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17511ef941fea2534a0d20ba7d71307d35040247decbanthony } 17521ef941fea2534a0d20ba7d71307d35040247decbanthony case CornersKernel: 17531ef941fea2534a0d20ba7d71307d35040247decbanthony { 1754529482f4b494010a13338a74446c510712f670b3anthony kernel=AcquireKernelInfo("ThinSE:87"); 17551ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17561ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17571ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 17581ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* Expand 90 degree rotations */ 17591ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17601ef941fea2534a0d20ba7d71307d35040247decbanthony } 1761529482f4b494010a13338a74446c510712f670b3anthony case DiagonalsKernel: 17621ef941fea2534a0d20ba7d71307d35040247decbanthony { 17631ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 17641ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 17651ef941fea2534a0d20ba7d71307d35040247decbanthony default: 17661ef941fea2534a0d20ba7d71307d35040247decbanthony { KernelInfo 17671ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 1768529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,0 0,-,1 1,1,-"); 17691ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17701ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17711ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 1772529482f4b494010a13338a74446c510712f670b3anthony new_kernel=ParseKernelArray("3: 0,0,1 0,-,1 0,1,-"); 17731ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 17741ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 17751ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 17761ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 17771ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandMirrorKernelInfo(kernel); 1778529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 17791ef941fea2534a0d20ba7d71307d35040247decbanthony } 17801ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 1781529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,0 0,-,1 1,1,-"); 17821ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17831ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 1784529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,1 0,-,1 0,1,-"); 17851ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17861ef941fea2534a0d20ba7d71307d35040247decbanthony } 1787529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1788529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1789529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1790529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 17911ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17921ef941fea2534a0d20ba7d71307d35040247decbanthony } 17931ef941fea2534a0d20ba7d71307d35040247decbanthony case LineEndsKernel: 17941ef941fea2534a0d20ba7d71307d35040247decbanthony { /* Kernels for finding the end of thin lines */ 17951ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 17961ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 17971ef941fea2534a0d20ba7d71307d35040247decbanthony default: 17981ef941fea2534a0d20ba7d71307d35040247decbanthony /* set of kernels to find all end of lines */ 1799529482f4b494010a13338a74446c510712f670b3anthony return(AcquireKernelInfo("LineEnds:1>;LineEnds:2>")); 18001ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 18011ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel for 4-connected line ends - no rotation */ 18021ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,- 0,1,1 0,0,-"); 18031ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18041ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 18051ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel to add for 8-connected lines - no rotation */ 18061ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,0 0,0,1"); 18071ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18081ef941fea2534a0d20ba7d71307d35040247decbanthony case 3: 18091ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel to add for orthogonal line ends - does not find corners */ 18101ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,1 0,0,0"); 18111ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18121ef941fea2534a0d20ba7d71307d35040247decbanthony case 4: 18131ef941fea2534a0d20ba7d71307d35040247decbanthony /* traditional line end - fails on last T end */ 18141ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,- 0,0,-"); 18151ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18161ef941fea2534a0d20ba7d71307d35040247decbanthony } 1817529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1818529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1819529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1820529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 18211ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18221ef941fea2534a0d20ba7d71307d35040247decbanthony } 18231ef941fea2534a0d20ba7d71307d35040247decbanthony case LineJunctionsKernel: 18241ef941fea2534a0d20ba7d71307d35040247decbanthony { /* kernels for finding the junctions of multiple lines */ 18251ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 18261ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 18271ef941fea2534a0d20ba7d71307d35040247decbanthony default: 18281ef941fea2534a0d20ba7d71307d35040247decbanthony /* set of kernels to find all line junctions */ 1829529482f4b494010a13338a74446c510712f670b3anthony return(AcquireKernelInfo("LineJunctions:1@;LineJunctions:2>")); 18301ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 18311ef941fea2534a0d20ba7d71307d35040247decbanthony /* Y Junction */ 18321ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,1 -,1,- -,1,-"); 18331ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18341ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 18351ef941fea2534a0d20ba7d71307d35040247decbanthony /* Diagonal T Junctions */ 18361ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,- -,1,- 1,-,1"); 18371ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18381ef941fea2534a0d20ba7d71307d35040247decbanthony case 3: 18391ef941fea2534a0d20ba7d71307d35040247decbanthony /* Orthogonal T Junctions */ 18401ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: -,-,- 1,1,1 -,1,-"); 18411ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18421ef941fea2534a0d20ba7d71307d35040247decbanthony case 4: 18431ef941fea2534a0d20ba7d71307d35040247decbanthony /* Diagonal X Junctions */ 18441ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,1 -,1,- 1,-,1"); 18451ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18461ef941fea2534a0d20ba7d71307d35040247decbanthony case 5: 18471ef941fea2534a0d20ba7d71307d35040247decbanthony /* Orthogonal X Junctions - minimal diamond kernel */ 18481ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: -,1,- 1,1,1 -,1,-"); 18491ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18501ef941fea2534a0d20ba7d71307d35040247decbanthony } 1851529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1852529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1853529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1854529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 18551ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18561ef941fea2534a0d20ba7d71307d35040247decbanthony } 18571ef941fea2534a0d20ba7d71307d35040247decbanthony case RidgesKernel: 18581ef941fea2534a0d20ba7d71307d35040247decbanthony { /* Ridges - Ridge finding kernels */ 18591ef941fea2534a0d20ba7d71307d35040247decbanthony KernelInfo 18601ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 18611ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 18621ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 18631ef941fea2534a0d20ba7d71307d35040247decbanthony default: 18641ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3x1:0,1,0"); 18651ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 18661ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 18671ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 18681ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* 2 rotated kernels (symmetrical) */ 18691ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18701ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 18711ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("4x1:0,1,1,0"); 18721ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 18731ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 18741ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 18751ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotated kernels */ 18761ef941fea2534a0d20ba7d71307d35040247decbanthony 18771ef941fea2534a0d20ba7d71307d35040247decbanthony /* Kernels to find a stepped 'thick' line, 4 rotates + mirrors */ 18781ef941fea2534a0d20ba7d71307d35040247decbanthony /* Unfortunatally we can not yet rotate a non-square kernel */ 18791ef941fea2534a0d20ba7d71307d35040247decbanthony /* But then we can't flip a non-symetrical kernel either */ 18801ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+1+1:0,1,1,- -,1,1,- -,1,1,0"); 18811ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18821ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18831ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18841ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18851ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+2+1:0,1,1,- -,1,1,- -,1,1,0"); 18861ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18871ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18881ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18891ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18901ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+1+1:-,1,1,0 -,1,1,- 0,1,1,-"); 18911ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18921ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18931ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18941ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18951ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+2+1:-,1,1,0 -,1,1,- 0,1,1,-"); 18961ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18971ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18981ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18991ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19001ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+1:0,-,- 1,1,1 1,1,1 -,-,0"); 19011ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19021ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19031ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19041ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19051ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+2:0,-,- 1,1,1 1,1,1 -,-,0"); 19061ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19071ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19081ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19091ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19101ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+1:-,-,0 1,1,1 1,1,1 0,-,-"); 19111ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19121ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19131ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19141ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19151ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+2:-,-,0 1,1,1 1,1,1 0,-,-"); 191668cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony if (new_kernel == (KernelInfo *) NULL) 191768cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony return(DestroyKernelInfo(kernel)); 191868cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony new_kernel->type = type; 191968cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony LastKernelInfo(kernel)->next = new_kernel; 192068cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony break; 19211ef941fea2534a0d20ba7d71307d35040247decbanthony } 19221ef941fea2534a0d20ba7d71307d35040247decbanthony break; 192368cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony } 19241ef941fea2534a0d20ba7d71307d35040247decbanthony case ConvexHullKernel: 19251ef941fea2534a0d20ba7d71307d35040247decbanthony { 19261ef941fea2534a0d20ba7d71307d35040247decbanthony KernelInfo 19271ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 19281ef941fea2534a0d20ba7d71307d35040247decbanthony /* first set of 8 kernels */ 19291ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,1,- 1,0,- 1,-,0"); 19301ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 19311ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 19321ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 19331ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); 19341ef941fea2534a0d20ba7d71307d35040247decbanthony /* append the mirror versions too - no flip function yet */ 19351ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3: 1,1,1 1,0,- -,-,0"); 19361ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19371ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19381ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19391ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(new_kernel, 90.0); 19401ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19411ef941fea2534a0d20ba7d71307d35040247decbanthony break; 1942694934fa79dd310f727588b1d0a7481fa6170f1danthony } 19439a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case SkeletonKernel: 19449a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony { 19459a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony switch ( (int) args->rho ) { 19469a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 1: 19479a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony default: 19489a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* Traditional Skeleton... 19499a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** A cyclically rotated single kernel 19509a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19519a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo("ThinSE:482"); 19529a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19539a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19549a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19559a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandRotateKernelInfo(kernel, 45.0); /* 8 rotations */ 19569a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19579a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 2: 19589a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* HIPR Variation of the cyclic skeleton 19599a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** Corners of the traditional method made more forgiving, 19609a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** but the retain the same cyclic order. 19619a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19629a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo("ThinSE:482; ThinSE:87x90;"); 19639a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19649a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19659a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel->next == (KernelInfo *) NULL) 19669a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(DestroyKernelInfo(kernel)); 19679a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19689a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->type = type; 19699a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotations of the 2 kernels */ 19709a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19719a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 3: 19729a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* Dan Bloomberg Skeleton, from his paper on 3x3 thinning SE's 19739a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** "Connectivity-Preserving Morphological Image Thransformations" 19749a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** by Dan S. Bloomberg, available on Leptonica, Selected Papers, 19759a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** http://www.leptonica.com/papers/conn.pdf 19769a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19779a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo( 19789a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony "ThinSE:41; ThinSE:42; ThinSE:43"); 19799a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19809a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19819a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19829a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->type = type; 19839a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->next->type = type; 19849a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandMirrorKernelInfo(kernel); /* 12 kernels total */ 19859a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19869a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony } 19879a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19889a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony } 1989529482f4b494010a13338a74446c510712f670b3anthony case ThinSEKernel: 1990529482f4b494010a13338a74446c510712f670b3anthony { /* Special kernels for general thinning, while preserving connections 1991529482f4b494010a13338a74446c510712f670b3anthony ** "Connectivity-Preserving Morphological Image Thransformations" 1992529482f4b494010a13338a74446c510712f670b3anthony ** by Dan S. Bloomberg, available on Leptonica, Selected Papers, 1993529482f4b494010a13338a74446c510712f670b3anthony ** http://www.leptonica.com/papers/conn.pdf 1994529482f4b494010a13338a74446c510712f670b3anthony ** And 1995529482f4b494010a13338a74446c510712f670b3anthony ** http://tpgit.github.com/Leptonica/ccthin_8c_source.html 1996529482f4b494010a13338a74446c510712f670b3anthony ** 1997529482f4b494010a13338a74446c510712f670b3anthony ** Note kernels do not specify the origin pixel, allowing them 1998529482f4b494010a13338a74446c510712f670b3anthony ** to be used for both thickening and thinning operations. 1999529482f4b494010a13338a74446c510712f670b3anthony */ 2000529482f4b494010a13338a74446c510712f670b3anthony switch ( (int) args->rho ) { 2001529482f4b494010a13338a74446c510712f670b3anthony /* SE for 4-connected thinning */ 2002529482f4b494010a13338a74446c510712f670b3anthony case 41: /* SE_4_1 */ 2003529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 -,-,1"); 2004529482f4b494010a13338a74446c510712f670b3anthony break; 2005529482f4b494010a13338a74446c510712f670b3anthony case 42: /* SE_4_2 */ 2006529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 -,0,-"); 2007529482f4b494010a13338a74446c510712f670b3anthony break; 2008529482f4b494010a13338a74446c510712f670b3anthony case 43: /* SE_4_3 */ 2009529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,-,1"); 2010529482f4b494010a13338a74446c510712f670b3anthony break; 2011529482f4b494010a13338a74446c510712f670b3anthony case 44: /* SE_4_4 */ 2012529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,0,-"); 2013529482f4b494010a13338a74446c510712f670b3anthony break; 2014529482f4b494010a13338a74446c510712f670b3anthony case 45: /* SE_4_5 */ 2015529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,1 0,-,1 -,0,-"); 2016529482f4b494010a13338a74446c510712f670b3anthony break; 2017529482f4b494010a13338a74446c510712f670b3anthony case 46: /* SE_4_6 */ 2018529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,0,1"); 2019529482f4b494010a13338a74446c510712f670b3anthony break; 2020529482f4b494010a13338a74446c510712f670b3anthony case 47: /* SE_4_7 */ 2021529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,1 0,-,1 -,0,-"); 2022529482f4b494010a13338a74446c510712f670b3anthony break; 2023529482f4b494010a13338a74446c510712f670b3anthony case 48: /* SE_4_8 */ 2024529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 0,-,1"); 2025529482f4b494010a13338a74446c510712f670b3anthony break; 2026529482f4b494010a13338a74446c510712f670b3anthony case 49: /* SE_4_9 */ 2027529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 -,-,1"); 2028529482f4b494010a13338a74446c510712f670b3anthony break; 2029529482f4b494010a13338a74446c510712f670b3anthony /* SE for 8-connected thinning - negatives of the above */ 2030529482f4b494010a13338a74446c510712f670b3anthony case 81: /* SE_8_0 */ 2031529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 -,1,-"); 2032529482f4b494010a13338a74446c510712f670b3anthony break; 2033529482f4b494010a13338a74446c510712f670b3anthony case 82: /* SE_8_2 */ 2034529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,-,-"); 2035529482f4b494010a13338a74446c510712f670b3anthony break; 2036529482f4b494010a13338a74446c510712f670b3anthony case 83: /* SE_8_3 */ 2037529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 -,1,-"); 2038529482f4b494010a13338a74446c510712f670b3anthony break; 2039529482f4b494010a13338a74446c510712f670b3anthony case 84: /* SE_8_4 */ 2040529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 0,-,-"); 2041529482f4b494010a13338a74446c510712f670b3anthony break; 2042529482f4b494010a13338a74446c510712f670b3anthony case 85: /* SE_8_5 */ 2043529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 0,-,-"); 2044529482f4b494010a13338a74446c510712f670b3anthony break; 2045529482f4b494010a13338a74446c510712f670b3anthony case 86: /* SE_8_6 */ 2046529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 0,-,1"); 2047529482f4b494010a13338a74446c510712f670b3anthony break; 2048529482f4b494010a13338a74446c510712f670b3anthony case 87: /* SE_8_7 */ 2049529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,0,-"); 2050529482f4b494010a13338a74446c510712f670b3anthony break; 2051529482f4b494010a13338a74446c510712f670b3anthony case 88: /* SE_8_8 */ 2052529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,1,-"); 2053529482f4b494010a13338a74446c510712f670b3anthony break; 2054529482f4b494010a13338a74446c510712f670b3anthony case 89: /* SE_8_9 */ 2055529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,1,- 0,-,1 -,1,-"); 2056529482f4b494010a13338a74446c510712f670b3anthony break; 2057529482f4b494010a13338a74446c510712f670b3anthony /* Special combined SE kernels */ 20589a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 423: /* SE_4_2 , SE_4_3 Combined Kernel */ 20599a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=ParseKernelArray("3: -,-,1 0,-,- -,0,-"); 20609a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 20619a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 823: /* SE_8_2 , SE_8_3 Combined Kernel */ 20629a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=ParseKernelArray("3: -,1,- -,-,1 0,-,-"); 20639a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 2064529482f4b494010a13338a74446c510712f670b3anthony case 481: /* SE_48_1 - General Connected Corner Kernel */ 2065529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,1 0,-,1 0,0,-"); 2066529482f4b494010a13338a74446c510712f670b3anthony break; 2067529482f4b494010a13338a74446c510712f670b3anthony default: 2068529482f4b494010a13338a74446c510712f670b3anthony case 482: /* SE_48_2 - General Edge Kernel */ 2069529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 0,-,1"); 2070529482f4b494010a13338a74446c510712f670b3anthony break; 2071529482f4b494010a13338a74446c510712f670b3anthony } 2072529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 2073529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 2074529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 2075529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 2076529482f4b494010a13338a74446c510712f670b3anthony break; 2077529482f4b494010a13338a74446c510712f670b3anthony } 2078529482f4b494010a13338a74446c510712f670b3anthony /* 2079529482f4b494010a13338a74446c510712f670b3anthony Distance Measuring Kernels 2080529482f4b494010a13338a74446c510712f670b3anthony */ 20811ef941fea2534a0d20ba7d71307d35040247decbanthony case ChebyshevKernel: 20821ef941fea2534a0d20ba7d71307d35040247decbanthony { 20831ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 20841ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 20851ef941fea2534a0d20ba7d71307d35040247decbanthony else 20861ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 20871ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 20881ef941fea2534a0d20ba7d71307d35040247decbanthony 2089e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2090e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2091e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2092d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 20931ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 20941ef941fea2534a0d20ba7d71307d35040247decbanthony 20951ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 20961ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 20971ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += ( kernel->values[i] = 20981ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*MagickMax(fabs((double)u),fabs((double)v)) ); 20991ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = kernel->values[0]; 21001ef941fea2534a0d20ba7d71307d35040247decbanthony break; 2101c40ac1e79923a1516075ba1197ae4ed90244af9banthony } 21021ef941fea2534a0d20ba7d71307d35040247decbanthony case ManhattanKernel: 21031ef941fea2534a0d20ba7d71307d35040247decbanthony { 21041ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 21051ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 21061ef941fea2534a0d20ba7d71307d35040247decbanthony else 21071ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 21081ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 21091ef941fea2534a0d20ba7d71307d35040247decbanthony 2110e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2111e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2112e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2113d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 21141ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 21151ef941fea2534a0d20ba7d71307d35040247decbanthony 21161ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 21171ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 21181ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += ( kernel->values[i] = 21191ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*(labs((long) u)+labs((long) v)) ); 21201ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = kernel->values[0]; 21211ef941fea2534a0d20ba7d71307d35040247decbanthony break; 2122c40ac1e79923a1516075ba1197ae4ed90244af9banthony } 21231ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonalKernel: 2124602ab9b30b644a78a4057da93d838a77391ec0acanthony { 21251ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 2.0) 21261ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default/minimum radius = 2 */ 2127602ab9b30b644a78a4057da93d838a77391ec0acanthony else 2128bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = ((size_t)args->rho)*2+1; 2129bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 2130602ab9b30b644a78a4057da93d838a77391ec0acanthony 2131e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2132e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2133e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2134d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 213583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 2136602ab9b30b644a78a4057da93d838a77391ec0acanthony 2137bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 2138bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 21391ef941fea2534a0d20ba7d71307d35040247decbanthony { 21401ef941fea2534a0d20ba7d71307d35040247decbanthony double 21411ef941fea2534a0d20ba7d71307d35040247decbanthony r1 = MagickMax(fabs((double)u),fabs((double)v)), 21421ef941fea2534a0d20ba7d71307d35040247decbanthony r2 = floor((double)(labs((long)u)+labs((long)v)+1)/1.5); 21431ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = 21441ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*MagickMax(r1,r2); 21451ef941fea2534a0d20ba7d71307d35040247decbanthony } 2146c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 2147602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2148602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2149602ab9b30b644a78a4057da93d838a77391ec0acanthony case EuclideanKernel: 2150602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2151602ab9b30b644a78a4057da93d838a77391ec0acanthony if (args->rho < 1.0) 2152c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 2153602ab9b30b644a78a4057da93d838a77391ec0acanthony else 21541ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 2155bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 2156602ab9b30b644a78a4057da93d838a77391ec0acanthony 2157e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2158e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2159e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2160d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 216183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 2162602ab9b30b644a78a4057da93d838a77391ec0acanthony 2163bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 2164bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 2165c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->positive_range += ( kernel->values[i] = 21660ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony args->sigma*sqrt((double)(u*u+v*v)) ); 2167c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 2168602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2169602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2170602ab9b30b644a78a4057da93d838a77391ec0acanthony default: 2171c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 2172529482f4b494010a13338a74446c510712f670b3anthony /* No-Op Kernel - Basically just a single pixel on its own */ 21733ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony kernel=ParseKernelArray("1:1"); 2174c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 2175c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 2176529482f4b494010a13338a74446c510712f670b3anthony kernel->type = UndefinedKernel; 2177c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 2178c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 2179602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2180602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2181602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 2182602ab9b30b644a78a4057da93d838a77391ec0acanthony} 2183c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony 2184602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 2185602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2186602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2187602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2188602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 21896771f1e8987fa49f52d4176281a2e8524b8e31cbcristy% C l o n e K e r n e l I n f o % 21904fd27e21043be809d66c8202e779255e5b660d2danthony% % 21914fd27e21043be809d66c8202e779255e5b660d2danthony% % 21924fd27e21043be809d66c8202e779255e5b660d2danthony% % 21934fd27e21043be809d66c8202e779255e5b660d2danthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21944fd27e21043be809d66c8202e779255e5b660d2danthony% 21951b2bc0a7da432e6e1cc0480280402df213faa940anthony% CloneKernelInfo() creates a new clone of the given Kernel List so that its 21961b2bc0a7da432e6e1cc0480280402df213faa940anthony% can be modified without effecting the original. The cloned kernel should 21970ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony% be destroyed using DestoryKernelInfo() when no longer needed. 21987a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 2199e636559dfadfdb115cc93f223315052a1ee89238cristy% The format of the CloneKernelInfo method is: 22004fd27e21043be809d66c8202e779255e5b660d2danthony% 2201930be614b4595b97cd79ee864a394796740f76adanthony% KernelInfo *CloneKernelInfo(const KernelInfo *kernel) 22024fd27e21043be809d66c8202e779255e5b660d2danthony% 22034fd27e21043be809d66c8202e779255e5b660d2danthony% A description of each parameter follows: 22044fd27e21043be809d66c8202e779255e5b660d2danthony% 22054fd27e21043be809d66c8202e779255e5b660d2danthony% o kernel: the Morphology/Convolution kernel to be cloned 22064fd27e21043be809d66c8202e779255e5b660d2danthony% 22074fd27e21043be809d66c8202e779255e5b660d2danthony*/ 2208ef656913b0b30d713ae94c82c47693c9dc69c9f4cristyMagickExport KernelInfo *CloneKernelInfo(const KernelInfo *kernel) 22094fd27e21043be809d66c8202e779255e5b660d2danthony{ 2210bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 22114fd27e21043be809d66c8202e779255e5b660d2danthony i; 22124fd27e21043be809d66c8202e779255e5b660d2danthony 221319eb64195ef744f61293025952df1e5e6de66524cristy KernelInfo 22147a01dcf50ce12cb2a789bedff51e9345f022432eanthony *new_kernel; 22154fd27e21043be809d66c8202e779255e5b660d2danthony 22164fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel != (KernelInfo *) NULL); 22177a01dcf50ce12cb2a789bedff51e9345f022432eanthony new_kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel)); 22187a01dcf50ce12cb2a789bedff51e9345f022432eanthony if (new_kernel == (KernelInfo *) NULL) 22197a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(new_kernel); 22207a01dcf50ce12cb2a789bedff51e9345f022432eanthony *new_kernel=(*kernel); /* copy values in structure */ 22217a01dcf50ce12cb2a789bedff51e9345f022432eanthony 22227a01dcf50ce12cb2a789bedff51e9345f022432eanthony /* replace the values with a copy of the values */ 2223e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy new_kernel->values=(MagickRealType *) MagickAssumeAligned( 2224e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height*sizeof(*kernel->values))); 2225d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (new_kernel->values == (MagickRealType *) NULL) 22267a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(DestroyKernelInfo(new_kernel)); 2227bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++) 22287a01dcf50ce12cb2a789bedff51e9345f022432eanthony new_kernel->values[i]=kernel->values[i]; 22291b2bc0a7da432e6e1cc0480280402df213faa940anthony 22301b2bc0a7da432e6e1cc0480280402df213faa940anthony /* Also clone the next kernel in the kernel list */ 22311b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL ) { 22321b2bc0a7da432e6e1cc0480280402df213faa940anthony new_kernel->next = CloneKernelInfo(kernel->next); 22331b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( new_kernel->next == (KernelInfo *) NULL ) 22341b2bc0a7da432e6e1cc0480280402df213faa940anthony return(DestroyKernelInfo(new_kernel)); 22351b2bc0a7da432e6e1cc0480280402df213faa940anthony } 22361b2bc0a7da432e6e1cc0480280402df213faa940anthony 22377a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(new_kernel); 22384fd27e21043be809d66c8202e779255e5b660d2danthony} 22394fd27e21043be809d66c8202e779255e5b660d2danthony 22404fd27e21043be809d66c8202e779255e5b660d2danthony/* 22414fd27e21043be809d66c8202e779255e5b660d2danthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22424fd27e21043be809d66c8202e779255e5b660d2danthony% % 22434fd27e21043be809d66c8202e779255e5b660d2danthony% % 22444fd27e21043be809d66c8202e779255e5b660d2danthony% % 224583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% D e s t r o y K e r n e l I n f o % 2246602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2247602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2248602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2249602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2250602ab9b30b644a78a4057da93d838a77391ec0acanthony% 225183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% DestroyKernelInfo() frees the memory used by a Convolution/Morphology 225283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% kernel. 2253602ab9b30b644a78a4057da93d838a77391ec0acanthony% 225483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% The format of the DestroyKernelInfo method is: 2255602ab9b30b644a78a4057da93d838a77391ec0acanthony% 225683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% KernelInfo *DestroyKernelInfo(KernelInfo *kernel) 2257602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2258602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 2259602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2260602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel: the Morphology/Convolution kernel to be destroyed 2261602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2262602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 226383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthonyMagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel) 2264602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 22652be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy assert(kernel != (KernelInfo *) NULL); 2266c4a4878e8962f8b885b3df3fe928ed6c20f91066dirk if (kernel->next != (KernelInfo *) NULL) 22679f752c092332bf2c4e599ea49e9422c13f3fb11bcristy kernel->next=DestroyKernelInfo(kernel->next); 2268d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values=(MagickRealType *) RelinquishAlignedMemory(kernel->values); 22699f752c092332bf2c4e599ea49e9422c13f3fb11bcristy kernel=(KernelInfo *) RelinquishMagickMemory(kernel); 2270602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 2271602ab9b30b644a78a4057da93d838a77391ec0acanthony} 2272c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony 2273c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony/* 2274c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2275c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2276c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2277c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2278ce0fd95b65b90e1dc307600bb14b346b777e8137anthony+ E x p a n d M i r r o r K e r n e l I n f o % 22793c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 22803c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 22813c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 22823c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22833c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2284bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% ExpandMirrorKernelInfo() takes a single kernel, and expands it into a 2285bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% sequence of 90-degree rotated kernels but providing a reflected 180 2286bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% rotatation, before the -/+ 90-degree rotations. 2287bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2288bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% This special rotation order produces a better, more symetrical thinning of 2289bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% objects. 2290bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2291bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The format of the ExpandMirrorKernelInfo method is: 2292bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2293bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% void ExpandMirrorKernelInfo(KernelInfo *kernel) 2294bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2295bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% A description of each parameter follows: 2296bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2297bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% o kernel: the Morphology/Convolution kernel 2298bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2299bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% This function is only internel to this module, as it is not finalized, 2300bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% especially with regard to non-orthogonal angles, and rotation of larger 2301bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2D kernels. 2302bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony*/ 2303bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2304bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony#if 0 2305bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void FlopKernelInfo(KernelInfo *kernel) 2306bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony { /* Do a Flop by reversing each row. */ 2307bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony size_t 2308bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony y; 2309bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony register ssize_t 2310bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony x,r; 2311bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony register double 2312bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *k,t; 2313bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2314bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width) 2315bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--) 2316bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony t=k[x], k[x]=k[r], k[r]=t; 2317bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2318bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony kernel->x = kernel->width - kernel->x - 1; 2319bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony angle = fmod(angle+180.0, 360.0); 2320bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony } 2321bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony#endif 2322bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2323bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void ExpandMirrorKernelInfo(KernelInfo *kernel) 2324bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony{ 2325bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony KernelInfo 2326bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *clone, 2327bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *last; 2328bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2329bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = kernel; 2330bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2331bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2332bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 180); /* flip */ 2333bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2334bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = clone; 2335bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2336bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2337bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 90); /* transpose */ 2338bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2339bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = clone; 2340bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2341bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2342bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 180); /* flop */ 2343bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2344bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2345bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony return; 2346bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony} 2347bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2348bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony/* 2349bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2350bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2351bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2352bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2353ce0fd95b65b90e1dc307600bb14b346b777e8137anthony+ E x p a n d R o t a t e K e r n e l I n f o % 2354bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2355bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2356bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2357bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2358bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2359bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% ExpandRotateKernelInfo() takes a kernel list, and expands it by rotating 2360529482f4b494010a13338a74446c510712f670b3anthony% incrementally by the angle given, until the kernel repeats. 23613c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23623c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% WARNING: 45 degree rotations only works for 3x3 kernels. 23633c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% While 90 degree roatations only works for linear and square kernels 23643c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2365bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The format of the ExpandRotateKernelInfo method is: 23663c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2367bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% void ExpandRotateKernelInfo(KernelInfo *kernel, double angle) 23683c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23693c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% A description of each parameter follows: 23703c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23713c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% o kernel: the Morphology/Convolution kernel 23723c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23733c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% o angle: angle to rotate in degrees 23743c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23753c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% This function is only internel to this module, as it is not finalized, 23763c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% especially with regard to non-orthogonal angles, and rotation of larger 23773c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2D kernels. 23783c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony*/ 237947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 238047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony/* Internal Routine - Return true if two kernels are the same */ 238147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthonystatic MagickBooleanType SameKernelInfo(const KernelInfo *kernel1, 238247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony const KernelInfo *kernel2) 238347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony{ 2384bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 238547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony i; 23861d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 23871d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* check size and origin location */ 23881d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( kernel1->width != kernel2->width 23891d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->height != kernel2->height 23901d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->x != kernel2->x 23911d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->y != kernel2->y ) 239247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 23931d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 23941d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* check actual kernel values */ 239547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony for (i=0; i < (kernel1->width*kernel1->height); i++) { 2396f0a92fd8deb68d411304359906b12679b675691fglennrp /* Test for Nan equivalence */ 2397a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ( IfNaN(kernel1->values[i]) && !IfNaN(kernel2->values[i]) ) 239847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 2399a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ( IfNaN(kernel2->values[i]) && !IfNaN(kernel1->values[i]) ) 240047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 2401f0a92fd8deb68d411304359906b12679b675691fglennrp /* Test actual values are equivalent */ 2402b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(kernel1->values[i] - kernel2->values[i]) >= MagickEpsilon ) 240347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 240447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 24051d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 240647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickTrue; 240747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony} 240847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 2409bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void ExpandRotateKernelInfo(KernelInfo *kernel, const double angle) 24103c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony{ 24113c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony KernelInfo 241284d9b5596c0900609dea18795861e2b0936b21c6cristy *clone, 24133c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony *last; 2414a9a61ad96c5112acd968f97b689bd42ca392d70bcristy 24153c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony last = kernel; 241693b02b797c4127ce2b06dbd3b2d75ecc33fca759dirkDisableMSCWarning(4127) 241747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while(1) { 241893b02b797c4127ce2b06dbd3b2d75ecc33fca759dirkRestoreMSCWarning 241984d9b5596c0900609dea18795861e2b0936b21c6cristy clone = CloneKernelInfo(last); 242084d9b5596c0900609dea18795861e2b0936b21c6cristy RotateKernelInfo(clone, angle); 2421cd8b331760407523f2a59cc65c1cd9c3d4422bafcristy if ( SameKernelInfo(kernel, clone) != MagickFalse ) 242247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 2423bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 242484d9b5596c0900609dea18795861e2b0936b21c6cristy last = clone; 24253c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 2426bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = DestroyKernelInfo(clone); /* kernel has repeated - junk the clone */ 242747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return; 24283c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony} 24293c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony 24303c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony/* 24313c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 24323c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 24333c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 24343c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 243546a369d839971ab627bdb31a93d8bd63e81b65a3anthony+ C a l c M e t a K e r n a l I n f o % 243646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 243746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 243846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 243946a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 244046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 244146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% CalcKernelMetaData() recalculate the KernelInfo meta-data of this kernel only, 2442dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp% using the kernel values. This should only ne used if it is not possible to 244346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% calculate that meta-data in some easier way. 244446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 244546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% It is important that the meta-data is correct before ScaleKernelInfo() is 244646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% used to perform kernel normalization. 244746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 244846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The format of the CalcKernelMetaData method is: 244946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 245046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% void CalcKernelMetaData(KernelInfo *kernel, const double scale ) 245146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 245246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% A description of each parameter follows: 245346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 245446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o kernel: the Morphology/Convolution kernel to modify 245546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 245646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% WARNING: Minimum and Maximum values are assumed to include zero, even if 245746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% zero is not part of the kernel (as in Gaussian Derived kernels). This 245846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% however is not true for flat-shaped morphological kernels. 245946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 246046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% WARNING: Only the specific kernel pointed to is modified, not a list of 246146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% multiple kernels. 246246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 246346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This is an internal function and not expected to be useful outside this 246446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% module. This could change however. 246546a369d839971ab627bdb31a93d8bd63e81b65a3anthony*/ 246646a369d839971ab627bdb31a93d8bd63e81b65a3anthonystatic void CalcKernelMetaData(KernelInfo *kernel) 246746a369d839971ab627bdb31a93d8bd63e81b65a3anthony{ 2468bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 246946a369d839971ab627bdb31a93d8bd63e81b65a3anthony i; 247046a369d839971ab627bdb31a93d8bd63e81b65a3anthony 247146a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->minimum = kernel->maximum = 0.0; 247246a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->negative_range = kernel->positive_range = 0.0; 247346a369d839971ab627bdb31a93d8bd63e81b65a3anthony for (i=0; i < (kernel->width*kernel->height); i++) 247446a369d839971ab627bdb31a93d8bd63e81b65a3anthony { 247546a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( fabs(kernel->values[i]) < MagickEpsilon ) 247646a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->values[i] = 0.0; 247746a369d839971ab627bdb31a93d8bd63e81b65a3anthony ( kernel->values[i] < 0) 247846a369d839971ab627bdb31a93d8bd63e81b65a3anthony ? ( kernel->negative_range += kernel->values[i] ) 247946a369d839971ab627bdb31a93d8bd63e81b65a3anthony : ( kernel->positive_range += kernel->values[i] ); 248046a369d839971ab627bdb31a93d8bd63e81b65a3anthony Minimize(kernel->minimum, kernel->values[i]); 248146a369d839971ab627bdb31a93d8bd63e81b65a3anthony Maximize(kernel->maximum, kernel->values[i]); 248246a369d839971ab627bdb31a93d8bd63e81b65a3anthony } 248346a369d839971ab627bdb31a93d8bd63e81b65a3anthony 248446a369d839971ab627bdb31a93d8bd63e81b65a3anthony return; 248546a369d839971ab627bdb31a93d8bd63e81b65a3anthony} 248646a369d839971ab627bdb31a93d8bd63e81b65a3anthony 248746a369d839971ab627bdb31a93d8bd63e81b65a3anthony/* 248846a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 248946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 249046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 249146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 24929eb4f74649b23c053b308ce1152dce51239450baanthony% M o r p h o l o g y A p p l y % 2493602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2494602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2495602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2496602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2497602ab9b30b644a78a4057da93d838a77391ec0acanthony% 24989eb4f74649b23c053b308ce1152dce51239450baanthony% MorphologyApply() applies a morphological method, multiple times using 249922de2722b682eb405b60ec6022a7546df994674eanthony% a list of multiple kernels. This is the method that should be called by 250022de2722b682eb405b60ec6022a7546df994674eanthony% other 'operators' that internally use morphology operations as part of 250122de2722b682eb405b60ec6022a7546df994674eanthony% their processing. 2502602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2503ec9ace44c23c302f336f6e672f6857312747d29bcristy% It is basically equivalent to as MorphologyImage() (see below) but without 2504ec9ace44c23c302f336f6e672f6857312747d29bcristy% any user controls. This allows internel programs to use this method to 2505ec9ace44c23c302f336f6e672f6857312747d29bcristy% perform a specific task without possible interference by any API user 2506ec9ace44c23c302f336f6e672f6857312747d29bcristy% supplied settings. 2507e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% 2508f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% It is MorphologyImage() task to extract any such user controls, and 2509e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% pass them to this function for processing. 25109eb4f74649b23c053b308ce1152dce51239450baanthony% 251122de2722b682eb405b60ec6022a7546df994674eanthony% More specifically all given kernels should already be scaled, normalised, 251222de2722b682eb405b60ec6022a7546df994674eanthony% and blended appropriatally before being parred to this routine. The 251322de2722b682eb405b60ec6022a7546df994674eanthony% appropriate bias, and compose (typically 'UndefinedComposeOp') given. 2514602ab9b30b644a78a4057da93d838a77391ec0acanthony% 251547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% The format of the MorphologyApply method is: 2516602ab9b30b644a78a4057da93d838a77391ec0acanthony% 25179eb4f74649b23c053b308ce1152dce51239450baanthony% Image *MorphologyApply(const Image *image,MorphologyMethod method, 2518f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% const ssize_t iterations,const KernelInfo *kernel, 2519f46d42620631d2581e0b6a56456e203e17c427c8anthony% const CompositeMethod compose,const double bias, 2520f46d42620631d2581e0b6a56456e203e17c427c8anthony% ExceptionInfo *exception) 2521602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2522602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 2523602ab9b30b644a78a4057da93d838a77391ec0acanthony% 25248d18850dee4bed193a64866a6d2353eeeb73e145anthony% o image: the source image 2525602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2526602ab9b30b644a78a4057da93d838a77391ec0acanthony% o method: the morphology method to be applied. 2527602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2528602ab9b30b644a78a4057da93d838a77391ec0acanthony% o iterations: apply the operation this many times (or no change). 2529602ab9b30b644a78a4057da93d838a77391ec0acanthony% A value of -1 means loop until no change found. 2530602ab9b30b644a78a4057da93d838a77391ec0acanthony% How this is applied may depend on the morphology method. 2531602ab9b30b644a78a4057da93d838a77391ec0acanthony% Typically this is a value of 1. 2532602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2533602ab9b30b644a78a4057da93d838a77391ec0acanthony% o channel: the channel type. 2534602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2535602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel: An array of double representing the morphology kernel. 2536602ab9b30b644a78a4057da93d838a77391ec0acanthony% 253747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% o compose: How to handle or merge multi-kernel results. 25388d18850dee4bed193a64866a6d2353eeeb73e145anthony% If 'UndefinedCompositeOp' use default for the Morphology method. 25398d18850dee4bed193a64866a6d2353eeeb73e145anthony% If 'NoCompositeOp' force image to be re-iterated by each kernel. 25408d18850dee4bed193a64866a6d2353eeeb73e145anthony% Otherwise merge the results using the compose method given. 254147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% 2542f46d42620631d2581e0b6a56456e203e17c427c8anthony% o bias: Convolution Output Bias. 2543f46d42620631d2581e0b6a56456e203e17c427c8anthony% 25449eb4f74649b23c053b308ce1152dce51239450baanthony% o exception: return any errors or warnings in this structure. 2545602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2546602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 2547f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristystatic ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image, 2548f46d42620631d2581e0b6a56456e203e17c427c8anthony const MorphologyMethod method,const KernelInfo *kernel,const double bias, 2549f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 2550602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 25512be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy#define MorphologyTag "Morphology/Image" 2552602ab9b30b644a78a4057da93d838a77391ec0acanthony 25535f959473f334e196c6bf39b740c12cb4963fceebcristy CacheView 25544c08aed51c5899665ade97263692328eea4af106cristy *image_view, 25554c08aed51c5899665ade97263692328eea4af106cristy *morphology_view; 25565f959473f334e196c6bf39b740c12cb4963fceebcristy 2557ec9ace44c23c302f336f6e672f6857312747d29bcristy OffsetInfo 2558ec9ace44c23c302f336f6e672f6857312747d29bcristy offset; 2559ec9ace44c23c302f336f6e672f6857312747d29bcristy 2560c5876076825b539bd230ddadab1d876805c18291cristy register ssize_t 2561c5876076825b539bd230ddadab1d876805c18291cristy i; 2562c5876076825b539bd230ddadab1d876805c18291cristy 2563d9435776384a479c2f0d621b4bef12a35592fd5dcristy ssize_t 2564d9435776384a479c2f0d621b4bef12a35592fd5dcristy y; 2565d9435776384a479c2f0d621b4bef12a35592fd5dcristy 2566a8843c1f815ffad2568ec592d5b446cb1476aab5anthony size_t 2567306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy *changes, 2568306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy changed, 2569306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy width; 2570602ab9b30b644a78a4057da93d838a77391ec0acanthony 2571d9435776384a479c2f0d621b4bef12a35592fd5dcristy MagickBooleanType 2572d9435776384a479c2f0d621b4bef12a35592fd5dcristy status; 2573d9435776384a479c2f0d621b4bef12a35592fd5dcristy 2574d9435776384a479c2f0d621b4bef12a35592fd5dcristy MagickOffsetType 2575d9435776384a479c2f0d621b4bef12a35592fd5dcristy progress; 2576602ab9b30b644a78a4057da93d838a77391ec0acanthony 2577e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(image != (Image *) NULL); 2578e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(image->signature == MagickSignature); 25794c08aed51c5899665ade97263692328eea4af106cristy assert(morphology_image != (Image *) NULL); 25804c08aed51c5899665ade97263692328eea4af106cristy assert(morphology_image->signature == MagickSignature); 2581e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(kernel != (KernelInfo *) NULL); 2582e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(kernel->signature == MagickSignature); 2583e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(exception != (ExceptionInfo *) NULL); 2584e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(exception->signature == MagickSignature); 2585602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickTrue; 2586602ab9b30b644a78a4057da93d838a77391ec0acanthony progress=0; 2587d9435776384a479c2f0d621b4bef12a35592fd5dcristy image_view=AcquireVirtualCacheView(image,exception); 2588d9435776384a479c2f0d621b4bef12a35592fd5dcristy morphology_view=AcquireAuthenticCacheView(morphology_image,exception); 2589d9435776384a479c2f0d621b4bef12a35592fd5dcristy width=image->columns+kernel->width-1; 2590d9435776384a479c2f0d621b4bef12a35592fd5dcristy offset.x=0.0; 2591d9435776384a479c2f0d621b4bef12a35592fd5dcristy offset.y=0.0; 2592ec9ace44c23c302f336f6e672f6857312747d29bcristy switch (method) 2593ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2594930be614b4595b97cd79ee864a394796740f76adanthony case ConvolveMorphology: 2595930be614b4595b97cd79ee864a394796740f76adanthony case DilateMorphology: 2596930be614b4595b97cd79ee864a394796740f76adanthony case DilateIntensityMorphology: 2597f34d9b2df49a407af764c79e07d587af0600983aanthony case IterativeDistanceMorphology: 2598ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2599ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 2600ec9ace44c23c302f336f6e672f6857312747d29bcristy Kernel needs to used with reflection about origin. 2601ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 2602ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.x=(ssize_t) kernel->width-kernel->x-1; 2603ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.y=(ssize_t) kernel->height-kernel->y-1; 260429188a8682a98d4b7882cca434b170517555fc7danthony break; 2605ec9ace44c23c302f336f6e672f6857312747d29bcristy } 26065ef8e94ff55717be2387d537bd49025780a1a558anthony case ErodeMorphology: 26075ef8e94ff55717be2387d537bd49025780a1a558anthony case ErodeIntensityMorphology: 26085ef8e94ff55717be2387d537bd49025780a1a558anthony case HitAndMissMorphology: 26095ef8e94ff55717be2387d537bd49025780a1a558anthony case ThinningMorphology: 26105ef8e94ff55717be2387d537bd49025780a1a558anthony case ThickenMorphology: 2611ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2612ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.x=kernel->x; 2613ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.y=kernel->y; 26145ef8e94ff55717be2387d537bd49025780a1a558anthony break; 2615ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2616930be614b4595b97cd79ee864a394796740f76adanthony default: 2617ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2618d9435776384a479c2f0d621b4bef12a35592fd5dcristy assert("Not a Primitive Morphology Method" != (char *) NULL); 2619930be614b4595b97cd79ee864a394796740f76adanthony break; 2620ec9ace44c23c302f336f6e672f6857312747d29bcristy } 262129188a8682a98d4b7882cca434b170517555fc7danthony } 2622c5876076825b539bd230ddadab1d876805c18291cristy changed=0; 2623306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy changes=(size_t *) AcquireQuantumMemory(GetOpenMPMaximumThreads(), 2624306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy sizeof(*changes)); 2625306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy if (changes == (size_t *) NULL) 2626306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 2627c5876076825b539bd230ddadab1d876805c18291cristy for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++) 2628c5876076825b539bd230ddadab1d876805c18291cristy changes[i]=0; 2629ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((method == ConvolveMorphology) && (kernel->width == 1)) 2630780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2631d9435776384a479c2f0d621b4bef12a35592fd5dcristy register ssize_t 2632780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy x; 2633fd1175952254cf1ac848ddb441e483c5e33d517fcristy 2634780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy /* 2635d9435776384a479c2f0d621b4bef12a35592fd5dcristy Special handling (for speed) of vertical (blur) kernels. This performs 2636d9435776384a479c2f0d621b4bef12a35592fd5dcristy its handling in columns rather than in rows. This is only done 2637d9435776384a479c2f0d621b4bef12a35592fd5dcristy for convolve as it is the only method that generates very large 1-D 2638d9435776384a479c2f0d621b4bef12a35592fd5dcristy vertical kernels (such as a 'BlurKernel') 2639d9435776384a479c2f0d621b4bef12a35592fd5dcristy */ 26408d18850dee4bed193a64866a6d2353eeeb73e145anthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 2641d9435776384a479c2f0d621b4bef12a35592fd5dcristy #pragma omp parallel for schedule(static,4) shared(progress,status) \ 2642d9435776384a479c2f0d621b4bef12a35592fd5dcristy magick_threads(image,morphology_image,image->columns,1) 26438d18850dee4bed193a64866a6d2353eeeb73e145anthony#endif 2644780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy for (x=0; x < (ssize_t) image->columns; x++) 2645780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2646d9435776384a479c2f0d621b4bef12a35592fd5dcristy const int 2647d9435776384a479c2f0d621b4bef12a35592fd5dcristy id = GetOpenMPThreadId(); 2648d9435776384a479c2f0d621b4bef12a35592fd5dcristy 2649780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register const Quantum 2650780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy *restrict p; 26518d18850dee4bed193a64866a6d2353eeeb73e145anthony 2652780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register Quantum 2653780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy *restrict q; 26548d18850dee4bed193a64866a6d2353eeeb73e145anthony 2655780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register ssize_t 2656780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy y; 26578d18850dee4bed193a64866a6d2353eeeb73e145anthony 2658780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy ssize_t 2659780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy center; 26608d18850dee4bed193a64866a6d2353eeeb73e145anthony 2661780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (status == MagickFalse) 26628d18850dee4bed193a64866a6d2353eeeb73e145anthony continue; 2663ec9ace44c23c302f336f6e672f6857312747d29bcristy p=GetCacheViewVirtualPixels(image_view,x,-offset.y,1,image->rows+ 2664780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy kernel->height-1,exception); 2665780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy q=GetCacheViewAuthenticPixels(morphology_view,x,0,1, 2666780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy morphology_image->rows,exception); 2667780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 2668780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2669780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy status=MagickFalse; 2670780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy continue; 2671780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 2672ec9ace44c23c302f336f6e672f6857312747d29bcristy center=(ssize_t) GetPixelChannels(image)*offset.y; 2673780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy for (y=0; y < (ssize_t) image->rows; y++) 2674f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy { 2675d9435776384a479c2f0d621b4bef12a35592fd5dcristy register ssize_t 2676d9435776384a479c2f0d621b4bef12a35592fd5dcristy i; 26778d18850dee4bed193a64866a6d2353eeeb73e145anthony 2678d9435776384a479c2f0d621b4bef12a35592fd5dcristy for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 2679d9435776384a479c2f0d621b4bef12a35592fd5dcristy { 2680d9435776384a479c2f0d621b4bef12a35592fd5dcristy double 2681d9435776384a479c2f0d621b4bef12a35592fd5dcristy alpha, 2682d9435776384a479c2f0d621b4bef12a35592fd5dcristy gamma, 2683d9435776384a479c2f0d621b4bef12a35592fd5dcristy pixel; 26848d18850dee4bed193a64866a6d2353eeeb73e145anthony 2685d9435776384a479c2f0d621b4bef12a35592fd5dcristy PixelChannel 2686d9435776384a479c2f0d621b4bef12a35592fd5dcristy channel; 26878d18850dee4bed193a64866a6d2353eeeb73e145anthony 2688d9435776384a479c2f0d621b4bef12a35592fd5dcristy PixelTrait 2689d9435776384a479c2f0d621b4bef12a35592fd5dcristy morphology_traits, 2690d9435776384a479c2f0d621b4bef12a35592fd5dcristy traits; 269117f57990dae485e8d3e5ea44e624882692424669cristy 2692d9435776384a479c2f0d621b4bef12a35592fd5dcristy register const MagickRealType 2693d9435776384a479c2f0d621b4bef12a35592fd5dcristy *restrict k; 269417f57990dae485e8d3e5ea44e624882692424669cristy 2695d9435776384a479c2f0d621b4bef12a35592fd5dcristy register const Quantum 2696d9435776384a479c2f0d621b4bef12a35592fd5dcristy *restrict pixels; 2697f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy 269809347642526e7e61646b7c549e410d21790e5e50cristy register ssize_t 269909347642526e7e61646b7c549e410d21790e5e50cristy u; 2700e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy 2701d9435776384a479c2f0d621b4bef12a35592fd5dcristy size_t 2702d9435776384a479c2f0d621b4bef12a35592fd5dcristy count; 2703d9435776384a479c2f0d621b4bef12a35592fd5dcristy 2704d9435776384a479c2f0d621b4bef12a35592fd5dcristy ssize_t 2705d9435776384a479c2f0d621b4bef12a35592fd5dcristy v; 2706d9435776384a479c2f0d621b4bef12a35592fd5dcristy 2707d9435776384a479c2f0d621b4bef12a35592fd5dcristy channel=GetPixelChannelChannel(image,i); 2708d9435776384a479c2f0d621b4bef12a35592fd5dcristy traits=GetPixelChannelTraits(image,channel); 2709d9435776384a479c2f0d621b4bef12a35592fd5dcristy morphology_traits=GetPixelChannelTraits(morphology_image,channel); 2710d9435776384a479c2f0d621b4bef12a35592fd5dcristy if ((traits == UndefinedPixelTrait) || 2711d9435776384a479c2f0d621b4bef12a35592fd5dcristy (morphology_traits == UndefinedPixelTrait)) 2712f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy continue; 27136aeeb023536796b4af0b5f5ea370df33953a750ecristy if (((traits & CopyPixelTrait) != 0) || 27146aeeb023536796b4af0b5f5ea370df33953a750ecristy (GetPixelReadMask(image,p+center) == 0)) 2715f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy { 2716d9435776384a479c2f0d621b4bef12a35592fd5dcristy SetPixelChannel(morphology_image,channel,p[center+i],q); 2717780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy continue; 2718780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 2719d9435776384a479c2f0d621b4bef12a35592fd5dcristy k=(&kernel->values[kernel->width*kernel->height-1]); 2720d9435776384a479c2f0d621b4bef12a35592fd5dcristy pixels=p; 2721d9435776384a479c2f0d621b4bef12a35592fd5dcristy pixel=bias; 2722d9435776384a479c2f0d621b4bef12a35592fd5dcristy gamma=0.0; 2723d9435776384a479c2f0d621b4bef12a35592fd5dcristy count=0; 2724d9435776384a479c2f0d621b4bef12a35592fd5dcristy if ((morphology_traits & BlendPixelTrait) == 0) 2725d9435776384a479c2f0d621b4bef12a35592fd5dcristy for (v=0; v < (ssize_t) kernel->height; v++) 2726d9435776384a479c2f0d621b4bef12a35592fd5dcristy { 2727d9435776384a479c2f0d621b4bef12a35592fd5dcristy for (u=0; u < (ssize_t) kernel->width; u++) 2728d9435776384a479c2f0d621b4bef12a35592fd5dcristy { 2729d9435776384a479c2f0d621b4bef12a35592fd5dcristy if (IfNaN(*k) == MagickFalse) 2730d9435776384a479c2f0d621b4bef12a35592fd5dcristy { 2731d9435776384a479c2f0d621b4bef12a35592fd5dcristy pixel+=(*k)*pixels[i]; 2732d9435776384a479c2f0d621b4bef12a35592fd5dcristy gamma+=(*k); 2733d9435776384a479c2f0d621b4bef12a35592fd5dcristy count++; 2734d9435776384a479c2f0d621b4bef12a35592fd5dcristy } 2735d9435776384a479c2f0d621b4bef12a35592fd5dcristy k--; 2736d9435776384a479c2f0d621b4bef12a35592fd5dcristy pixels+=GetPixelChannels(image); 2737d9435776384a479c2f0d621b4bef12a35592fd5dcristy } 2738d9435776384a479c2f0d621b4bef12a35592fd5dcristy } 2739d9435776384a479c2f0d621b4bef12a35592fd5dcristy else 2740d9435776384a479c2f0d621b4bef12a35592fd5dcristy for (v=0; v < (ssize_t) kernel->height; v++) 2741d9435776384a479c2f0d621b4bef12a35592fd5dcristy { 2742d9435776384a479c2f0d621b4bef12a35592fd5dcristy for (u=0; u < (ssize_t) kernel->width; u++) 2743d9435776384a479c2f0d621b4bef12a35592fd5dcristy { 2744d9435776384a479c2f0d621b4bef12a35592fd5dcristy if (IfNaN(*k) == MagickFalse) 2745d9435776384a479c2f0d621b4bef12a35592fd5dcristy { 2746d9435776384a479c2f0d621b4bef12a35592fd5dcristy alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels)); 2747d9435776384a479c2f0d621b4bef12a35592fd5dcristy pixel+=alpha*(*k)*pixels[i]; 2748d9435776384a479c2f0d621b4bef12a35592fd5dcristy gamma+=alpha*(*k); 2749d9435776384a479c2f0d621b4bef12a35592fd5dcristy count++; 2750d9435776384a479c2f0d621b4bef12a35592fd5dcristy } 2751d9435776384a479c2f0d621b4bef12a35592fd5dcristy k--; 2752d9435776384a479c2f0d621b4bef12a35592fd5dcristy pixels+=GetPixelChannels(image); 2753d9435776384a479c2f0d621b4bef12a35592fd5dcristy } 2754d9435776384a479c2f0d621b4bef12a35592fd5dcristy } 2755d9435776384a479c2f0d621b4bef12a35592fd5dcristy if (fabs(pixel-p[center+i]) > MagickEpsilon) 2756c5876076825b539bd230ddadab1d876805c18291cristy changes[id]++; 2757d9435776384a479c2f0d621b4bef12a35592fd5dcristy gamma=PerceptibleReciprocal(gamma); 2758d9435776384a479c2f0d621b4bef12a35592fd5dcristy if (count != 0) 2759d9435776384a479c2f0d621b4bef12a35592fd5dcristy gamma*=(double) kernel->height*kernel->width/count; 2760d9435776384a479c2f0d621b4bef12a35592fd5dcristy SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma* 2761d9435776384a479c2f0d621b4bef12a35592fd5dcristy pixel),q); 27628d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2763780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy p+=GetPixelChannels(image); 2764780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy q+=GetPixelChannels(morphology_image); 2765ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2766780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 2767780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy status=MagickFalse; 2768780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (image->progress_monitor != (MagickProgressMonitor) NULL) 2769780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2770780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy MagickBooleanType 2771780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy proceed; 27728d18850dee4bed193a64866a6d2353eeeb73e145anthony 27738d18850dee4bed193a64866a6d2353eeeb73e145anthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 2774954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy #pragma omp critical (MagickCore_MorphologyPrimitive) 27758d18850dee4bed193a64866a6d2353eeeb73e145anthony#endif 2776ec9ace44c23c302f336f6e672f6857312747d29bcristy proceed=SetImageProgress(image,MorphologyTag,progress++, 2777ec9ace44c23c302f336f6e672f6857312747d29bcristy image->rows); 2778780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (proceed == MagickFalse) 2779780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy status=MagickFalse; 2780780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 2781780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 2782780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy morphology_image->type=image->type; 2783780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy morphology_view=DestroyCacheView(morphology_view); 2784780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy image_view=DestroyCacheView(image_view); 2785c5876076825b539bd230ddadab1d876805c18291cristy for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++) 2786c5876076825b539bd230ddadab1d876805c18291cristy changed+=changes[i]; 2787306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy changes=(size_t *) RelinquishMagickMemory(changes); 2788780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy return(status ? (ssize_t) changed : 0); 2789780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 27908d18850dee4bed193a64866a6d2353eeeb73e145anthony /* 2791780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy Normal handling of horizontal or rectangular kernels (row by row). 27928d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 2793602ab9b30b644a78a4057da93d838a77391ec0acanthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 2794c5876076825b539bd230ddadab1d876805c18291cristy #pragma omp parallel for schedule(static,4) shared(progress,status) \ 27955e6b259130f9dbe0da4666f734937017babe573acristy magick_threads(image,morphology_image,image->rows,1) 2796602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 2797bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (y=0; y < (ssize_t) image->rows; y++) 2798602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2799c5876076825b539bd230ddadab1d876805c18291cristy const int 2800c5876076825b539bd230ddadab1d876805c18291cristy id = GetOpenMPThreadId(); 2801c5876076825b539bd230ddadab1d876805c18291cristy 28024c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 2803602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict p; 2804602ab9b30b644a78a4057da93d838a77391ec0acanthony 28054c08aed51c5899665ade97263692328eea4af106cristy register Quantum 2806602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict q; 2807602ab9b30b644a78a4057da93d838a77391ec0acanthony 2808bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 2809602ab9b30b644a78a4057da93d838a77391ec0acanthony x; 2810602ab9b30b644a78a4057da93d838a77391ec0acanthony 2811ec9ace44c23c302f336f6e672f6857312747d29bcristy ssize_t 2812ec9ace44c23c302f336f6e672f6857312747d29bcristy center; 2813602ab9b30b644a78a4057da93d838a77391ec0acanthony 2814602ab9b30b644a78a4057da93d838a77391ec0acanthony if (status == MagickFalse) 2815602ab9b30b644a78a4057da93d838a77391ec0acanthony continue; 2816ec9ace44c23c302f336f6e672f6857312747d29bcristy p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width, 2817af43471dfedff5d1314cd674fac6508d230df1bccristy kernel->height,exception); 2818af43471dfedff5d1314cd674fac6508d230df1bccristy q=GetCacheViewAuthenticPixels(morphology_view,0,y,morphology_image->columns, 2819af43471dfedff5d1314cd674fac6508d230df1bccristy 1,exception); 28204c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 2821602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2822602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 2823602ab9b30b644a78a4057da93d838a77391ec0acanthony continue; 2824602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2825ec9ace44c23c302f336f6e672f6857312747d29bcristy center=(ssize_t) (GetPixelChannels(image)*width*offset.y+ 2826ec9ace44c23c302f336f6e672f6857312747d29bcristy GetPixelChannels(image)*offset.x); 2827bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (x=0; x < (ssize_t) image->columns; x++) 2828602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2829ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 2830ec9ace44c23c302f336f6e672f6857312747d29bcristy i; 2831602ab9b30b644a78a4057da93d838a77391ec0acanthony 2832ec9ace44c23c302f336f6e672f6857312747d29bcristy for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 2833ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2834ec9ace44c23c302f336f6e672f6857312747d29bcristy double 2835ec9ace44c23c302f336f6e672f6857312747d29bcristy alpha, 2836e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy gamma, 2837ec9ace44c23c302f336f6e672f6857312747d29bcristy maximum, 2838ec9ace44c23c302f336f6e672f6857312747d29bcristy minimum, 2839ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel; 2840602ab9b30b644a78a4057da93d838a77391ec0acanthony 2841ec9ace44c23c302f336f6e672f6857312747d29bcristy PixelChannel 2842ec9ace44c23c302f336f6e672f6857312747d29bcristy channel; 2843602ab9b30b644a78a4057da93d838a77391ec0acanthony 2844ec9ace44c23c302f336f6e672f6857312747d29bcristy PixelTrait 2845ec9ace44c23c302f336f6e672f6857312747d29bcristy morphology_traits, 2846ec9ace44c23c302f336f6e672f6857312747d29bcristy traits; 2847ec9ace44c23c302f336f6e672f6857312747d29bcristy 2848ec9ace44c23c302f336f6e672f6857312747d29bcristy register const MagickRealType 2849ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict k; 2850ec9ace44c23c302f336f6e672f6857312747d29bcristy 2851ec9ace44c23c302f336f6e672f6857312747d29bcristy register const Quantum 2852ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict pixels; 2853ec9ace44c23c302f336f6e672f6857312747d29bcristy 2854ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 2855ec9ace44c23c302f336f6e672f6857312747d29bcristy u; 2856602ab9b30b644a78a4057da93d838a77391ec0acanthony 2857e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy size_t 2858e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count; 2859e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy 2860ec9ace44c23c302f336f6e672f6857312747d29bcristy ssize_t 2861ec9ace44c23c302f336f6e672f6857312747d29bcristy v; 2862ec9ace44c23c302f336f6e672f6857312747d29bcristy 2863ec9ace44c23c302f336f6e672f6857312747d29bcristy channel=GetPixelChannelChannel(image,i); 2864ec9ace44c23c302f336f6e672f6857312747d29bcristy traits=GetPixelChannelTraits(image,channel); 2865ec9ace44c23c302f336f6e672f6857312747d29bcristy morphology_traits=GetPixelChannelTraits(morphology_image,channel); 2866ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((traits == UndefinedPixelTrait) || 2867ec9ace44c23c302f336f6e672f6857312747d29bcristy (morphology_traits == UndefinedPixelTrait)) 2868ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 28696aeeb023536796b4af0b5f5ea370df33953a750ecristy if (((traits & CopyPixelTrait) != 0) || 28706aeeb023536796b4af0b5f5ea370df33953a750ecristy (GetPixelReadMask(image,p+center) == 0)) 2871ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2872ec9ace44c23c302f336f6e672f6857312747d29bcristy SetPixelChannel(morphology_image,channel,p[center+i],q); 2873ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 2874ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2875ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=p; 2876ec9ace44c23c302f336f6e672f6857312747d29bcristy maximum=0.0; 2877ec9ace44c23c302f336f6e672f6857312747d29bcristy minimum=(double) QuantumRange; 2878e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count=kernel->width*kernel->height; 2879ec9ace44c23c302f336f6e672f6857312747d29bcristy switch (method) 2880ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2881ec9ace44c23c302f336f6e672f6857312747d29bcristy case ConvolveMorphology: pixel=bias; break; 2882ec9ace44c23c302f336f6e672f6857312747d29bcristy case HitAndMissMorphology: pixel=(double) QuantumRange; break; 2883ec9ace44c23c302f336f6e672f6857312747d29bcristy case ThinningMorphology: pixel=(double) QuantumRange; break; 2884ec9ace44c23c302f336f6e672f6857312747d29bcristy case ThickenMorphology: pixel=(double) QuantumRange; break; 2885ec9ace44c23c302f336f6e672f6857312747d29bcristy case ErodeMorphology: pixel=(double) QuantumRange; break; 2886ec9ace44c23c302f336f6e672f6857312747d29bcristy case DilateMorphology: pixel=0.0; break; 2887ec9ace44c23c302f336f6e672f6857312747d29bcristy case ErodeIntensityMorphology: 2888ec9ace44c23c302f336f6e672f6857312747d29bcristy case DilateIntensityMorphology: 2889ec9ace44c23c302f336f6e672f6857312747d29bcristy case IterativeDistanceMorphology: 2890ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2891ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) p[center+i]; 2892ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 2893ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2894ec9ace44c23c302f336f6e672f6857312747d29bcristy default: pixel=0; break; 2895ec9ace44c23c302f336f6e672f6857312747d29bcristy } 28968e6e9602b3a7805e8093f3e54cfc2f02fb89a4f1cristy gamma=1.0; 2897ec9ace44c23c302f336f6e672f6857312747d29bcristy switch (method) 2898ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2899ec9ace44c23c302f336f6e672f6857312747d29bcristy case ConvolveMorphology: 2900ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2901ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 2902ec9ace44c23c302f336f6e672f6857312747d29bcristy Weighted Average of pixels using reflected kernel 2903ec9ace44c23c302f336f6e672f6857312747d29bcristy 2904d9435776384a479c2f0d621b4bef12a35592fd5dcristy For correct working of this operation for asymetrical kernels, 2905d9435776384a479c2f0d621b4bef12a35592fd5dcristy the kernel needs to be applied in its reflected form. That is 2906d9435776384a479c2f0d621b4bef12a35592fd5dcristy its values needs to be reversed. 2907ec9ace44c23c302f336f6e672f6857312747d29bcristy 2908ec9ace44c23c302f336f6e672f6857312747d29bcristy Correlation is actually the same as this but without reflecting 2909d9435776384a479c2f0d621b4bef12a35592fd5dcristy the kernel, and thus 'lower-level' that Convolution. However as 2910d9435776384a479c2f0d621b4bef12a35592fd5dcristy Convolution is the more common method used, and it does not 2911ec9ace44c23c302f336f6e672f6857312747d29bcristy really cost us much in terms of processing to use a reflected 2912ec9ace44c23c302f336f6e672f6857312747d29bcristy kernel, so it is Convolution that is implemented. 2913ec9ace44c23c302f336f6e672f6857312747d29bcristy 2914d9435776384a479c2f0d621b4bef12a35592fd5dcristy Correlation will have its kernel reflected before calling this 2915d9435776384a479c2f0d621b4bef12a35592fd5dcristy function to do a Convolve. 2916ec9ace44c23c302f336f6e672f6857312747d29bcristy 2917ec9ace44c23c302f336f6e672f6857312747d29bcristy For more details of Correlation vs Convolution see 2918ec9ace44c23c302f336f6e672f6857312747d29bcristy http://www.cs.umd.edu/~djacobs/CMSC426/Convolution.pdf 2919930be614b4595b97cd79ee864a394796740f76adanthony */ 2920ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 2921d9435776384a479c2f0d621b4bef12a35592fd5dcristy count=0; 2922d9435776384a479c2f0d621b4bef12a35592fd5dcristy gamma=0.0; 292309347642526e7e61646b7c549e410d21790e5e50cristy if ((morphology_traits & BlendPixelTrait) == 0) 292409347642526e7e61646b7c549e410d21790e5e50cristy { 292509347642526e7e61646b7c549e410d21790e5e50cristy /* 292609347642526e7e61646b7c549e410d21790e5e50cristy No alpha blending. 292709347642526e7e61646b7c549e410d21790e5e50cristy */ 292809347642526e7e61646b7c549e410d21790e5e50cristy for (v=0; v < (ssize_t) kernel->height; v++) 292909347642526e7e61646b7c549e410d21790e5e50cristy { 293009347642526e7e61646b7c549e410d21790e5e50cristy for (u=0; u < (ssize_t) kernel->width; u++) 293109347642526e7e61646b7c549e410d21790e5e50cristy { 293209347642526e7e61646b7c549e410d21790e5e50cristy if (IfNaN(*k) == MagickFalse) 2933d9435776384a479c2f0d621b4bef12a35592fd5dcristy { 2934d9435776384a479c2f0d621b4bef12a35592fd5dcristy pixel+=(*k)*pixels[i]; 2935d9435776384a479c2f0d621b4bef12a35592fd5dcristy gamma+=(*k); 2936d9435776384a479c2f0d621b4bef12a35592fd5dcristy count++; 2937d9435776384a479c2f0d621b4bef12a35592fd5dcristy } 293809347642526e7e61646b7c549e410d21790e5e50cristy k--; 293909347642526e7e61646b7c549e410d21790e5e50cristy pixels+=GetPixelChannels(image); 294009347642526e7e61646b7c549e410d21790e5e50cristy } 294109347642526e7e61646b7c549e410d21790e5e50cristy pixels+=(image->columns-1)*GetPixelChannels(image); 294209347642526e7e61646b7c549e410d21790e5e50cristy } 294309347642526e7e61646b7c549e410d21790e5e50cristy break; 294409347642526e7e61646b7c549e410d21790e5e50cristy } 294509347642526e7e61646b7c549e410d21790e5e50cristy /* 294609347642526e7e61646b7c549e410d21790e5e50cristy Alpha blending. 294709347642526e7e61646b7c549e410d21790e5e50cristy */ 294833c51e0d3335ba3b35248454fe61c1805f65a115cristy for (v=0; v < (ssize_t) kernel->height; v++) 2949ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2950ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 2951ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2952a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 2953ec9ace44c23c302f336f6e672f6857312747d29bcristy { 295409347642526e7e61646b7c549e410d21790e5e50cristy alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels)); 2955cb228bb3ff8da73ec82aa72dee9d4a6309bc7eedcristy pixel+=alpha*(*k)*pixels[i]; 2956cb228bb3ff8da73ec82aa72dee9d4a6309bc7eedcristy gamma+=alpha*(*k); 2957e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count++; 2958602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2959ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 2960ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 2961602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2962b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 2963ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2964602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2965ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2966ec9ace44c23c302f336f6e672f6857312747d29bcristy case ErodeMorphology: 2967ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2968ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 2969ec9ace44c23c302f336f6e672f6857312747d29bcristy Minimum value within kernel neighbourhood. 2970602ab9b30b644a78a4057da93d838a77391ec0acanthony 2971ec9ace44c23c302f336f6e672f6857312747d29bcristy The kernel is not reflected for this operation. In normal 2972ec9ace44c23c302f336f6e672f6857312747d29bcristy Greyscale Morphology, the kernel value should be added 2973ec9ace44c23c302f336f6e672f6857312747d29bcristy to the real value, this is currently not done, due to the 2974ec9ace44c23c302f336f6e672f6857312747d29bcristy nature of the boolean kernels being used. 2975930be614b4595b97cd79ee864a394796740f76adanthony */ 2976ec9ace44c23c302f336f6e672f6857312747d29bcristy k=kernel->values; 2977ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 2978ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2979ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 2980ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2981a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && (*k >= 0.5)) 2982ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2983ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((double) pixels[i] < pixel) 2984ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]; 2985ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2986ec9ace44c23c302f336f6e672f6857312747d29bcristy k++; 2987ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 2988602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2989b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 2990602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2991602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2992ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2993ec9ace44c23c302f336f6e672f6857312747d29bcristy case DilateMorphology: 2994ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2995ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 2996ec9ace44c23c302f336f6e672f6857312747d29bcristy Maximum value within kernel neighbourhood. 2997ec9ace44c23c302f336f6e672f6857312747d29bcristy 2998ec9ace44c23c302f336f6e672f6857312747d29bcristy For correct working of this operation for asymetrical kernels, 2999ec9ace44c23c302f336f6e672f6857312747d29bcristy the kernel needs to be applied in its reflected form. That is 3000ec9ace44c23c302f336f6e672f6857312747d29bcristy its values needs to be reversed. 3001602ab9b30b644a78a4057da93d838a77391ec0acanthony 3002ec9ace44c23c302f336f6e672f6857312747d29bcristy In normal Greyscale Morphology, the kernel value should be 3003ec9ace44c23c302f336f6e672f6857312747d29bcristy added to the real value, this is currently not done, due to the 3004ec9ace44c23c302f336f6e672f6857312747d29bcristy nature of the boolean kernels being used. 3005930be614b4595b97cd79ee864a394796740f76adanthony */ 3006e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count=0; 3007ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 3008ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 3009ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3010ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3011ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3012a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && (*k > 0.5)) 3013ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3014ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((double) pixels[i] > pixel) 3015ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]; 3016e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count++; 3017ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3018ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3019ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3020602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3021b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3022602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3023602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3024ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3025ec9ace44c23c302f336f6e672f6857312747d29bcristy case HitAndMissMorphology: 3026ec9ace44c23c302f336f6e672f6857312747d29bcristy case ThinningMorphology: 3027ec9ace44c23c302f336f6e672f6857312747d29bcristy case ThickenMorphology: 3028ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3029ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3030ec9ace44c23c302f336f6e672f6857312747d29bcristy Minimum of foreground pixel minus maxumum of background pixels. 3031602ab9b30b644a78a4057da93d838a77391ec0acanthony 3032ec9ace44c23c302f336f6e672f6857312747d29bcristy The kernel is not reflected for this operation, and consists 3033ec9ace44c23c302f336f6e672f6857312747d29bcristy of both foreground and background pixel neighbourhoods, 0.0 for 3034ec9ace44c23c302f336f6e672f6857312747d29bcristy background, and 1.0 for foreground with either Nan or 0.5 values 3035ec9ace44c23c302f336f6e672f6857312747d29bcristy for don't care. 3036ec9ace44c23c302f336f6e672f6857312747d29bcristy 3037ec9ace44c23c302f336f6e672f6857312747d29bcristy This never produces a meaningless negative result. Such results 3038ec9ace44c23c302f336f6e672f6857312747d29bcristy cause Thinning/Thicken to not work correctly when used against a 3039ec9ace44c23c302f336f6e672f6857312747d29bcristy greyscale image. 30405ef8e94ff55717be2387d537bd49025780a1a558anthony */ 3041e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count=0; 3042ec9ace44c23c302f336f6e672f6857312747d29bcristy k=kernel->values; 3043ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 3044ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3045ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3046ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3047a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3048ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3049ec9ace44c23c302f336f6e672f6857312747d29bcristy if (*k > 0.7) 3050ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3051ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((double) pixels[i] < pixel) 3052ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]; 3053ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3054ec9ace44c23c302f336f6e672f6857312747d29bcristy else 3055ec9ace44c23c302f336f6e672f6857312747d29bcristy if (*k < 0.3) 3056ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3057ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((double) pixels[i] > maximum) 3058ec9ace44c23c302f336f6e672f6857312747d29bcristy maximum=(double) pixels[i]; 3059ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3060e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count++; 3061ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3062ec9ace44c23c302f336f6e672f6857312747d29bcristy k++; 3063ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 30645ef8e94ff55717be2387d537bd49025780a1a558anthony } 3065b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 30665ef8e94ff55717be2387d537bd49025780a1a558anthony } 3067ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel-=maximum; 3068ec9ace44c23c302f336f6e672f6857312747d29bcristy if (pixel < 0.0) 3069ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=0.0; 3070ec9ace44c23c302f336f6e672f6857312747d29bcristy if (method == ThinningMorphology) 3071ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) p[center+i]-pixel; 3072ec9ace44c23c302f336f6e672f6857312747d29bcristy else 3073ec9ace44c23c302f336f6e672f6857312747d29bcristy if (method == ThickenMorphology) 3074ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel+=(double) p[center+i]+pixel; 30755ef8e94ff55717be2387d537bd49025780a1a558anthony break; 3076ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3077ec9ace44c23c302f336f6e672f6857312747d29bcristy case ErodeIntensityMorphology: 3078ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3079ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3080ec9ace44c23c302f336f6e672f6857312747d29bcristy Select pixel with minimum intensity within kernel neighbourhood. 30816fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3082ec9ace44c23c302f336f6e672f6857312747d29bcristy The kernel is not reflected for this operation. 3083930be614b4595b97cd79ee864a394796740f76adanthony */ 3084e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count=0; 3085ec9ace44c23c302f336f6e672f6857312747d29bcristy k=kernel->values; 3086ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 3087ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3088ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3089ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3090a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && (*k >= 0.5)) 3091ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3092ec9ace44c23c302f336f6e672f6857312747d29bcristy if (GetPixelIntensity(image,pixels) < minimum) 3093ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3094ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]; 3095ec9ace44c23c302f336f6e672f6857312747d29bcristy minimum=GetPixelIntensity(image,pixels); 3096ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3097e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count++; 3098ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3099ec9ace44c23c302f336f6e672f6857312747d29bcristy k++; 3100ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3101602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3102b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3103602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3104602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3105ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3106ec9ace44c23c302f336f6e672f6857312747d29bcristy case DilateIntensityMorphology: 3107ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3108ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3109ec9ace44c23c302f336f6e672f6857312747d29bcristy Select pixel with maximum intensity within kernel neighbourhood. 31106fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3111ec9ace44c23c302f336f6e672f6857312747d29bcristy The kernel is not reflected for this operation. 3112930be614b4595b97cd79ee864a394796740f76adanthony */ 3113e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count=0; 3114ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 3115ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 3116ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3117ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3118ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3119a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && (*k >= 0.5)) 3120ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3121ec9ace44c23c302f336f6e672f6857312747d29bcristy if (GetPixelIntensity(image,pixels) > maximum) 3122ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3123ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]; 3124ec9ace44c23c302f336f6e672f6857312747d29bcristy maximum=GetPixelIntensity(image,pixels); 3125ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3126e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count++; 3127ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3128ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3129ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3130602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3131b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3132602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3133602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3134ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3135ec9ace44c23c302f336f6e672f6857312747d29bcristy case IterativeDistanceMorphology: 3136ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3137ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3138ec9ace44c23c302f336f6e672f6857312747d29bcristy Compute th iterative distance from black edge of a white image 3139ec9ace44c23c302f336f6e672f6857312747d29bcristy shape. Essentually white values are decreased to the smallest 3140ec9ace44c23c302f336f6e672f6857312747d29bcristy 'distance from edge' it can find. 31416fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3142ec9ace44c23c302f336f6e672f6857312747d29bcristy It works by adding kernel values to the neighbourhood, and and 3143ec9ace44c23c302f336f6e672f6857312747d29bcristy select the minimum value found. The kernel is rotated before 3144ec9ace44c23c302f336f6e672f6857312747d29bcristy use, so kernel distances match resulting distances, when a user 3145ec9ace44c23c302f336f6e672f6857312747d29bcristy provided asymmetric kernel is applied. 31466fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3147ec9ace44c23c302f336f6e672f6857312747d29bcristy This code is nearly identical to True GrayScale Morphology but 3148ec9ace44c23c302f336f6e672f6857312747d29bcristy not quite. 31496fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3150ec9ace44c23c302f336f6e672f6857312747d29bcristy GreyDilate Kernel values added, maximum value found Kernel is 3151ec9ace44c23c302f336f6e672f6857312747d29bcristy rotated before use. 31526fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3153ec9ace44c23c302f336f6e672f6857312747d29bcristy GrayErode: Kernel values subtracted and minimum value found No 3154ec9ace44c23c302f336f6e672f6857312747d29bcristy kernel rotation used. 31556fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3156ec9ace44c23c302f336f6e672f6857312747d29bcristy Note the the Iterative Distance method is essentially a 3157ec9ace44c23c302f336f6e672f6857312747d29bcristy GrayErode, but with negative kernel values, and kernel rotation 3158ec9ace44c23c302f336f6e672f6857312747d29bcristy applied. 3159930be614b4595b97cd79ee864a394796740f76adanthony */ 3160e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count=0; 3161ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 3162ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 3163ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3164ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3165ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3166a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3167ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3168ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3169ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3170e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy count++; 3171ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3172ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3173ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3174602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3175b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3176602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3177602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3178ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3179ec9ace44c23c302f336f6e672f6857312747d29bcristy case UndefinedMorphology: 3180ec9ace44c23c302f336f6e672f6857312747d29bcristy default: 3181ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 3182ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3183ec9ace44c23c302f336f6e672f6857312747d29bcristy if (fabs(pixel-p[center+i]) > MagickEpsilon) 3184c5876076825b539bd230ddadab1d876805c18291cristy changes[id]++; 31858e6e9602b3a7805e8093f3e54cfc2f02fb89a4f1cristy gamma=PerceptibleReciprocal(gamma); 3186a8fe15914fb2ad831f8f62c65f82150d53481eddcristy if (count != 0) 3187a8fe15914fb2ad831f8f62c65f82150d53481eddcristy gamma*=(double) kernel->height*kernel->width/count; 3188e6e92c4a3b6e06f6557d710e85a41baa3f9389b9cristy SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*pixel),q); 318983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 3190ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p+=GetPixelChannels(image); 3191ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(morphology_image); 3192ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3193cb228bb3ff8da73ec82aa72dee9d4a6309bc7eedcristy if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 3194602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 3195602ab9b30b644a78a4057da93d838a77391ec0acanthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 3196602ab9b30b644a78a4057da93d838a77391ec0acanthony { 3197602ab9b30b644a78a4057da93d838a77391ec0acanthony MagickBooleanType 3198602ab9b30b644a78a4057da93d838a77391ec0acanthony proceed; 3199602ab9b30b644a78a4057da93d838a77391ec0acanthony 3200602ab9b30b644a78a4057da93d838a77391ec0acanthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 3201954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy #pragma omp critical (MagickCore_MorphologyPrimitive) 3202602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 3203602ab9b30b644a78a4057da93d838a77391ec0acanthony proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows); 3204602ab9b30b644a78a4057da93d838a77391ec0acanthony if (proceed == MagickFalse) 3205602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 3206602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3207ec9ace44c23c302f336f6e672f6857312747d29bcristy } 32084c08aed51c5899665ade97263692328eea4af106cristy morphology_view=DestroyCacheView(morphology_view); 32094c08aed51c5899665ade97263692328eea4af106cristy image_view=DestroyCacheView(image_view); 3210c5876076825b539bd230ddadab1d876805c18291cristy for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++) 3211c5876076825b539bd230ddadab1d876805c18291cristy changed+=changes[i]; 3212306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy changes=(size_t *) RelinquishMagickMemory(changes); 3213c5876076825b539bd230ddadab1d876805c18291cristy return(status ? (ssize_t) changed : -1); 3214602ab9b30b644a78a4057da93d838a77391ec0acanthony} 3215602ab9b30b644a78a4057da93d838a77391ec0acanthony 3216ec9ace44c23c302f336f6e672f6857312747d29bcristy/* 3217ec9ace44c23c302f336f6e672f6857312747d29bcristy This is almost identical to the MorphologyPrimative() function above, but 3218ec9ace44c23c302f336f6e672f6857312747d29bcristy applies the primitive directly to the actual image using two passes, once in 3219ec9ace44c23c302f336f6e672f6857312747d29bcristy each direction, with the results of the previous (and current) row being 3220ec9ace44c23c302f336f6e672f6857312747d29bcristy re-used. 3221ec9ace44c23c302f336f6e672f6857312747d29bcristy 3222ec9ace44c23c302f336f6e672f6857312747d29bcristy That is after each row is 'Sync'ed' into the image, the next row makes use of 3223ec9ace44c23c302f336f6e672f6857312747d29bcristy those values as part of the calculation of the next row. It repeats, but 3224ec9ace44c23c302f336f6e672f6857312747d29bcristy going in the oppisite (bottom-up) direction. 3225ec9ace44c23c302f336f6e672f6857312747d29bcristy 3226ec9ace44c23c302f336f6e672f6857312747d29bcristy Because of this 're-use of results' this function can not make use of multi- 3227ec9ace44c23c302f336f6e672f6857312747d29bcristy threaded, parellel processing. 3228a8843c1f815ffad2568ec592d5b446cb1476aab5anthony*/ 3229e698a255629ba03cd125572de7b35b5e21c4ee5danthonystatic ssize_t MorphologyPrimitiveDirect(Image *image, 3230f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method,const KernelInfo *kernel, 3231f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 3232a8843c1f815ffad2568ec592d5b446cb1476aab5anthony{ 3233a8843c1f815ffad2568ec592d5b446cb1476aab5anthony CacheView 3234ec9ace44c23c302f336f6e672f6857312747d29bcristy *morphology_view, 3235ec9ace44c23c302f336f6e672f6857312747d29bcristy *image_view; 3236a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3237a8843c1f815ffad2568ec592d5b446cb1476aab5anthony MagickBooleanType 3238a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status; 3239a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3240a8843c1f815ffad2568ec592d5b446cb1476aab5anthony MagickOffsetType 3241a8843c1f815ffad2568ec592d5b446cb1476aab5anthony progress; 3242a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3243ec9ace44c23c302f336f6e672f6857312747d29bcristy OffsetInfo 3244ec9ace44c23c302f336f6e672f6857312747d29bcristy offset; 3245a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3246a8843c1f815ffad2568ec592d5b446cb1476aab5anthony size_t 3247ec9ace44c23c302f336f6e672f6857312747d29bcristy width, 3248a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed; 3249a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3250ec9ace44c23c302f336f6e672f6857312747d29bcristy ssize_t 3251ec9ace44c23c302f336f6e672f6857312747d29bcristy y; 3252a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3253a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(image != (Image *) NULL); 3254a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(image->signature == MagickSignature); 3255a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(kernel != (KernelInfo *) NULL); 3256a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(kernel->signature == MagickSignature); 3257a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(exception != (ExceptionInfo *) NULL); 3258a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(exception->signature == MagickSignature); 3259ec9ace44c23c302f336f6e672f6857312747d29bcristy status=MagickTrue; 3260ec9ace44c23c302f336f6e672f6857312747d29bcristy changed=0; 3261ec9ace44c23c302f336f6e672f6857312747d29bcristy progress=0; 3262ec9ace44c23c302f336f6e672f6857312747d29bcristy switch(method) 3263ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3264a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3265e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3266ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3267ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3268ec9ace44c23c302f336f6e672f6857312747d29bcristy Kernel reflected about origin. 3269ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 3270ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.x=(ssize_t) kernel->width-kernel->x-1; 3271ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.y=(ssize_t) kernel->height-kernel->y-1; 3272a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3273ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3274a8843c1f815ffad2568ec592d5b446cb1476aab5anthony default: 3275ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3276ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.x=kernel->x; 3277ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.y=kernel->y; 3278a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3279ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3280a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3281ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3282ec9ace44c23c302f336f6e672f6857312747d29bcristy Two views into same image, do not thread. 3283ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 3284ec9ace44c23c302f336f6e672f6857312747d29bcristy image_view=AcquireVirtualCacheView(image,exception); 3285ec9ace44c23c302f336f6e672f6857312747d29bcristy morphology_view=AcquireAuthenticCacheView(image,exception); 3286ec9ace44c23c302f336f6e672f6857312747d29bcristy width=image->columns+kernel->width-1; 3287a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (y=0; y < (ssize_t) image->rows; y++) 3288a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 32894c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3290a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict p; 3291a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 32924c08aed51c5899665ade97263692328eea4af106cristy register Quantum 3293a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict q; 3294a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3295a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register ssize_t 3296a8843c1f815ffad2568ec592d5b446cb1476aab5anthony x; 3297a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 329827be28f6ee6dcb0c20268851b6359b50fbee71fbcristy ssize_t 329927be28f6ee6dcb0c20268851b6359b50fbee71fbcristy center; 330027be28f6ee6dcb0c20268851b6359b50fbee71fbcristy 3301ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3302ec9ace44c23c302f336f6e672f6857312747d29bcristy Read virtual pixels, and authentic pixels, from the same image! We read 3303ec9ace44c23c302f336f6e672f6857312747d29bcristy using virtual to get virtual pixel handling, but write back into the same 3304ec9ace44c23c302f336f6e672f6857312747d29bcristy image. 3305ec9ace44c23c302f336f6e672f6857312747d29bcristy 3306ec9ace44c23c302f336f6e672f6857312747d29bcristy Only top half of kernel is processed as we do a single pass downward 3307ec9ace44c23c302f336f6e672f6857312747d29bcristy through the image iterating the distance function as we go. 3308a8843c1f815ffad2568ec592d5b446cb1476aab5anthony */ 3309a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (status == MagickFalse) 3310954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy continue; 3311ec9ace44c23c302f336f6e672f6857312747d29bcristy p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width,(size_t) 3312ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.y+1,exception); 33136fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1, 33144c08aed51c5899665ade97263692328eea4af106cristy exception); 33154c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 3316954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy { 3317954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy status=MagickFalse; 3318954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy continue; 3319954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy } 332027be28f6ee6dcb0c20268851b6359b50fbee71fbcristy center=(ssize_t) (GetPixelChannels(image)*width*offset.y+ 332127be28f6ee6dcb0c20268851b6359b50fbee71fbcristy GetPixelChannels(image)*offset.x); 3322a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (x=0; x < (ssize_t) image->columns; x++) 3323a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 3324ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 3325ec9ace44c23c302f336f6e672f6857312747d29bcristy i; 3326a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3327ec9ace44c23c302f336f6e672f6857312747d29bcristy for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 3328ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3329ec9ace44c23c302f336f6e672f6857312747d29bcristy double 3330ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel; 3331a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3332ec9ace44c23c302f336f6e672f6857312747d29bcristy PixelTrait 3333ec9ace44c23c302f336f6e672f6857312747d29bcristy traits; 3334ec9ace44c23c302f336f6e672f6857312747d29bcristy 3335ec9ace44c23c302f336f6e672f6857312747d29bcristy register const MagickRealType 3336ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict k; 3337ec9ace44c23c302f336f6e672f6857312747d29bcristy 3338ec9ace44c23c302f336f6e672f6857312747d29bcristy register const Quantum 3339ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict pixels; 3340ec9ace44c23c302f336f6e672f6857312747d29bcristy 3341ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 3342ec9ace44c23c302f336f6e672f6857312747d29bcristy u; 3343ec9ace44c23c302f336f6e672f6857312747d29bcristy 3344ec9ace44c23c302f336f6e672f6857312747d29bcristy ssize_t 3345ec9ace44c23c302f336f6e672f6857312747d29bcristy v; 3346ec9ace44c23c302f336f6e672f6857312747d29bcristy 3347ee1bdaac725f5188c568ab27f07917156b98081ccristy traits=GetPixelChannelTraits(image,(PixelChannel) i); 3348ec9ace44c23c302f336f6e672f6857312747d29bcristy if (traits == UndefinedPixelTrait) 3349ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 335027be28f6ee6dcb0c20268851b6359b50fbee71fbcristy if (((traits & CopyPixelTrait) != 0) || 3351883fde11debec15cedb05dc5d7228d8588066bc0cristy (GetPixelReadMask(image,p+center) == 0)) 3352ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 3353ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=p; 335427be28f6ee6dcb0c20268851b6359b50fbee71fbcristy pixel=(double) QuantumRange; 3355ec9ace44c23c302f336f6e672f6857312747d29bcristy switch (method) 3356ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3357ec9ace44c23c302f336f6e672f6857312747d29bcristy case DistanceMorphology: 3358ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3359ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 3360ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v <= offset.y; v++) 3361ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3362ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3363ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3364a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3365e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3366ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3367ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3368e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3369ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3370ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3371e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3372cfb71b157cd8f18b2e595d0a4a7c3c9403d8014dcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3373ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3374ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*(kernel->y+1)-1]); 3375ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=q-offset.x*GetPixelChannels(image); 3376ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < offset.x; u++) 3377ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3378a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && ((x+u-offset.x) >= 0)) 3379ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3380ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3381ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3382ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3383ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3384ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3385e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3386ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 3387ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3388ec9ace44c23c302f336f6e672f6857312747d29bcristy case VoronoiMorphology: 3389ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3390ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 3391ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < offset.y; v++) 3392ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3393ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3394ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3395a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3396e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3397ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3398ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3399e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3400ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3401ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3402e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3403cfb71b157cd8f18b2e595d0a4a7c3c9403d8014dcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3404ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3405ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*(kernel->y+1)-1]); 3406ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=q-offset.x*GetPixelChannels(image); 3407ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < offset.x; u++) 3408ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3409a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && ((x+u-offset.x) >= 0)) 3410ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3411ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3412ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3413ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3414ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3415ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3416ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3417e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3418ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3419ec9ace44c23c302f336f6e672f6857312747d29bcristy default: 3420ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 3421ec9ace44c23c302f336f6e672f6857312747d29bcristy } 34226fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (fabs(pixel-q[i]) > MagickEpsilon) 3423ec9ace44c23c302f336f6e672f6857312747d29bcristy changed++; 34246fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy q[i]=ClampToQuantum(pixel); 3425e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3426ec9ace44c23c302f336f6e672f6857312747d29bcristy p+=GetPixelChannels(image); 3427ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(image); 3428ec9ace44c23c302f336f6e672f6857312747d29bcristy } 34296fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 3430a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3431a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 3432ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3433ec9ace44c23c302f336f6e672f6857312747d29bcristy MagickBooleanType 3434ec9ace44c23c302f336f6e672f6857312747d29bcristy proceed; 3435a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 34366fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy proceed=SetImageProgress(image,MorphologyTag,progress++,2*image->rows); 3437ec9ace44c23c302f336f6e672f6857312747d29bcristy if (proceed == MagickFalse) 3438ec9ace44c23c302f336f6e672f6857312747d29bcristy status=MagickFalse; 3439ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3440ec9ace44c23c302f336f6e672f6857312747d29bcristy } 34416fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy morphology_view=DestroyCacheView(morphology_view); 34426fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy image_view=DestroyCacheView(image_view); 3443ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3444ec9ace44c23c302f336f6e672f6857312747d29bcristy Do the reverse pass through the image. 3445ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 34466fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy image_view=AcquireVirtualCacheView(image,exception); 34476fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy morphology_view=AcquireAuthenticCacheView(image,exception); 3448ec9ace44c23c302f336f6e672f6857312747d29bcristy for (y=(ssize_t) image->rows-1; y >= 0; y--) 3449a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 34504c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3451a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict p; 3452a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 34534c08aed51c5899665ade97263692328eea4af106cristy register Quantum 3454a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict q; 3455a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3456a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register ssize_t 3457a8843c1f815ffad2568ec592d5b446cb1476aab5anthony x; 3458a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 345927be28f6ee6dcb0c20268851b6359b50fbee71fbcristy ssize_t 346027be28f6ee6dcb0c20268851b6359b50fbee71fbcristy center; 346127be28f6ee6dcb0c20268851b6359b50fbee71fbcristy 3462ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3463ec9ace44c23c302f336f6e672f6857312747d29bcristy Read virtual pixels, and authentic pixels, from the same image. We 3464ec9ace44c23c302f336f6e672f6857312747d29bcristy read using virtual to get virtual pixel handling, but write back 3465ec9ace44c23c302f336f6e672f6857312747d29bcristy into the same image. 3466a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3467ec9ace44c23c302f336f6e672f6857312747d29bcristy Only the bottom half of the kernel is processed as we up the image. 3468ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 3469db60568e12574785101a4ae8d8da076227a0a889anthony if (status == MagickFalse) 3470954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy continue; 3471ec9ace44c23c302f336f6e672f6857312747d29bcristy p=GetCacheViewVirtualPixels(image_view,-offset.x,y,width,(size_t) 34724c08aed51c5899665ade97263692328eea4af106cristy kernel->y+1,exception); 34736fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1, 34744c08aed51c5899665ade97263692328eea4af106cristy exception); 34754c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 3476954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy { 3477954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy status=MagickFalse; 3478954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy continue; 3479954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy } 3480ec9ace44c23c302f336f6e672f6857312747d29bcristy p+=(image->columns-1)*GetPixelChannels(image); 3481ec9ace44c23c302f336f6e672f6857312747d29bcristy q+=(image->columns-1)*GetPixelChannels(image); 348227be28f6ee6dcb0c20268851b6359b50fbee71fbcristy center=(ssize_t) (offset.x*GetPixelChannels(image)); 34836fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy for (x=(ssize_t) image->columns-1; x >= 0; x--) 3484ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3485ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 3486ec9ace44c23c302f336f6e672f6857312747d29bcristy i; 3487a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3488ec9ace44c23c302f336f6e672f6857312747d29bcristy for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 3489ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3490ec9ace44c23c302f336f6e672f6857312747d29bcristy double 3491ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel; 3492a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3493ec9ace44c23c302f336f6e672f6857312747d29bcristy PixelTrait 3494ec9ace44c23c302f336f6e672f6857312747d29bcristy traits; 3495a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3496ec9ace44c23c302f336f6e672f6857312747d29bcristy register const MagickRealType 3497ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict k; 3498a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3499ec9ace44c23c302f336f6e672f6857312747d29bcristy register const Quantum 3500ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict pixels; 3501a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3502ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 3503ec9ace44c23c302f336f6e672f6857312747d29bcristy u; 3504ec9ace44c23c302f336f6e672f6857312747d29bcristy 3505ec9ace44c23c302f336f6e672f6857312747d29bcristy ssize_t 3506ec9ace44c23c302f336f6e672f6857312747d29bcristy v; 3507ec9ace44c23c302f336f6e672f6857312747d29bcristy 3508ee1bdaac725f5188c568ab27f07917156b98081ccristy traits=GetPixelChannelTraits(image,(PixelChannel) i); 3509ec9ace44c23c302f336f6e672f6857312747d29bcristy if (traits == UndefinedPixelTrait) 3510ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 351127be28f6ee6dcb0c20268851b6359b50fbee71fbcristy if (((traits & CopyPixelTrait) != 0) || 3512c3a5802c0bea29c2a308d441dfa233b3059938c1cristy (GetPixelReadMask(image,p+center) == 0)) 3513ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 3514ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=p; 351527be28f6ee6dcb0c20268851b6359b50fbee71fbcristy pixel=(double) QuantumRange; 3516ec9ace44c23c302f336f6e672f6857312747d29bcristy switch (method) 3517ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3518ec9ace44c23c302f336f6e672f6857312747d29bcristy case DistanceMorphology: 3519ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3520ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*(kernel->y+1)-1]); 3521ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=offset.y; v < (ssize_t) kernel->height; v++) 3522ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3523ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3524ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3525a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3526e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3527ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3528ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3529e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3530ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3531ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3532e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 353327be28f6ee6dcb0c20268851b6359b50fbee71fbcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3534e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3535ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->y+kernel->x-1]); 3536ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=q-offset.x*GetPixelChannels(image); 3537ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=offset.x+1; u < (ssize_t) kernel->width; u++) 3538ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3539a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && 35406fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy ((x+u-offset.x) < (ssize_t) image->columns)) 3541ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3542ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3543ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3544ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3545ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3546ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3547ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3548ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 3549ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3550ec9ace44c23c302f336f6e672f6857312747d29bcristy case VoronoiMorphology: 3551ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3552ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*(kernel->y+1)-1]); 3553ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=offset.y; v < (ssize_t) kernel->height; v++) 3554ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3555ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3556ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3557a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3558e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3559ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3560ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3561e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3562ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3563ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3564e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 356527be28f6ee6dcb0c20268851b6359b50fbee71fbcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3566ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3567ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*(kernel->y+1)-1]); 3568ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=q-offset.x*GetPixelChannels(image); 3569ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=offset.x+1; u < (ssize_t) kernel->width; u++) 3570ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3571a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && 35726fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy ((x+u-offset.x) < (ssize_t) image->columns)) 3573ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3574ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3575ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3576ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3577ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3578ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3579ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3580e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3581ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3582ec9ace44c23c302f336f6e672f6857312747d29bcristy default: 3583ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 3584ec9ace44c23c302f336f6e672f6857312747d29bcristy } 35856fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (fabs(pixel-q[i]) > MagickEpsilon) 3586ec9ace44c23c302f336f6e672f6857312747d29bcristy changed++; 35876fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy q[i]=ClampToQuantum(pixel); 3588e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 35896fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy p-=GetPixelChannels(image); 35906fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy q-=GetPixelChannels(image); 3591ec9ace44c23c302f336f6e672f6857312747d29bcristy } 35926fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 35936fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy status=MagickFalse; 35946fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (image->progress_monitor != (MagickProgressMonitor) NULL) 35956fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy { 35966fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy MagickBooleanType 35976fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy proceed; 35986fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 35996fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy proceed=SetImageProgress(image,MorphologyTag,progress++,2*image->rows); 36006fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (proceed == MagickFalse) 36016fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy status=MagickFalse; 36026fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy } 3603ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3604ec9ace44c23c302f336f6e672f6857312747d29bcristy morphology_view=DestroyCacheView(morphology_view); 3605ec9ace44c23c302f336f6e672f6857312747d29bcristy image_view=DestroyCacheView(image_view); 3606aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy return(status ? (ssize_t) changed : -1); 3607a8843c1f815ffad2568ec592d5b446cb1476aab5anthony} 3608a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3609ec9ace44c23c302f336f6e672f6857312747d29bcristy/* 3610ec9ace44c23c302f336f6e672f6857312747d29bcristy Apply a Morphology by calling one of the above low level primitive 3611ec9ace44c23c302f336f6e672f6857312747d29bcristy application functions. This function handles any iteration loops, 3612ec9ace44c23c302f336f6e672f6857312747d29bcristy composition or re-iteration of results, and compound morphology methods that 3613ec9ace44c23c302f336f6e672f6857312747d29bcristy is based on multiple low-level (staged) morphology methods. 3614ec9ace44c23c302f336f6e672f6857312747d29bcristy 3615ec9ace44c23c302f336f6e672f6857312747d29bcristy Basically this provides the complex glue between the requested morphology 3616ec9ace44c23c302f336f6e672f6857312747d29bcristy method and raw low-level implementation (above). 3617a8843c1f815ffad2568ec592d5b446cb1476aab5anthony*/ 3618cf592636b16d028b14c5fa9dffdc3a94eae7c2f3cristyMagickPrivate Image *MorphologyApply(const Image *image, 3619f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method, const ssize_t iterations, 3620f46d42620631d2581e0b6a56456e203e17c427c8anthony const KernelInfo *kernel, const CompositeOperator compose,const double bias, 3621f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 3622602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 36231cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy CompositeOperator 36241cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy curr_compose; 36251cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy 3626602ab9b30b644a78a4057da93d838a77391ec0acanthony Image 362747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *curr_image, /* Image we are working with or iterating */ 3628a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *work_image, /* secondary image for primitive iteration */ 362947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *save_image, /* saved image - for 'edge' method only */ 363047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *rslt_image; /* resultant image - after multi-kernel handling */ 3631602ab9b30b644a78a4057da93d838a77391ec0acanthony 36324fd27e21043be809d66c8202e779255e5b660d2danthony KernelInfo 363347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *reflected_kernel, /* A reflected copy of the kernel (if needed) */ 363447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *norm_kernel, /* the current normal un-reflected kernel */ 363547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *rflt_kernel, /* the current reflected kernel (if needed) */ 363647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *this_kernel; /* the kernel being applied */ 36374fd27e21043be809d66c8202e779255e5b660d2danthony 36384fd27e21043be809d66c8202e779255e5b660d2danthony MorphologyMethod 3639a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive; /* the current morphology primitive being applied */ 36409eb4f74649b23c053b308ce1152dce51239450baanthony 36419eb4f74649b23c053b308ce1152dce51239450baanthony CompositeOperator 364247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose; /* multi-kernel compose method for results to use */ 364347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 364447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony MagickBooleanType 3645e698a255629ba03cd125572de7b35b5e21c4ee5danthony special, /* do we use a direct modify function? */ 364647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony verbose; /* verbose output of results */ 36474fd27e21043be809d66c8202e779255e5b660d2danthony 3648bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 3649a8843c1f815ffad2568ec592d5b446cb1476aab5anthony method_loop, /* Loop 1: number of compound method iterations (norm 1) */ 365047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_limit, /* maximum number of compound method iterations */ 365147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number, /* Loop 2: the kernel number being applied */ 3652a8843c1f815ffad2568ec592d5b446cb1476aab5anthony stage_loop, /* Loop 3: primitive loop for compound morphology */ 3653a8843c1f815ffad2568ec592d5b446cb1476aab5anthony stage_limit, /* how many primitives are in this compound */ 3654a8843c1f815ffad2568ec592d5b446cb1476aab5anthony kernel_loop, /* Loop 4: iterate the kernel over image */ 365547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_limit, /* number of times to iterate kernel */ 3656a8843c1f815ffad2568ec592d5b446cb1476aab5anthony count, /* total count of primitive steps applied */ 365747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_changed, /* total count of changed using iterated kernel */ 365847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed; /* total count of changed over method iteration */ 365947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 3660a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3661a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed; /* number pixels changed by last primitive operation */ 3662a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 366347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony char 3664100a056069d5718f995e95a77950dcae6f412ff4cristy v_info[MaxTextExtent]; 36651b2bc0a7da432e6e1cc0480280402df213faa940anthony 3666602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(image != (Image *) NULL); 3667602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(image->signature == MagickSignature); 36684fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel != (KernelInfo *) NULL); 36694fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel->signature == MagickSignature); 3670602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(exception != (ExceptionInfo *) NULL); 3671602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(exception->signature == MagickSignature); 3672602ab9b30b644a78a4057da93d838a77391ec0acanthony 3673a8843c1f815ffad2568ec592d5b446cb1476aab5anthony count = 0; /* number of low-level morphology primitives performed */ 3674602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( iterations == 0 ) 367547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return((Image *)NULL); /* null operation - nothing to do! */ 3676602ab9b30b644a78a4057da93d838a77391ec0acanthony 3677bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel_limit = (size_t) iterations; 367847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( iterations < 0 ) /* negative interations = infinite (well alomst) */ 3679e698a255629ba03cd125572de7b35b5e21c4ee5danthony kernel_limit = image->columns>image->rows ? image->columns : image->rows; 368028ad1d779b6ca95852e860514185a7a97e06af77anthony 36818b520b45d3002ab6d4e6127172b080119137fb65cristy verbose = IsStringTrue(GetImageArtifact(image,"debug")); 36824f1dcb76c95ef6410f2957ca9e7e1d391cee0d02anthony 36839eb4f74649b23c053b308ce1152dce51239450baanthony /* initialise for cleanup */ 368447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; 36851cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy curr_compose = image->compose; 3686aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy (void) curr_compose; 368747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = save_image = rslt_image = (Image *) NULL; 368847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = (KernelInfo *) NULL; 36894fd27e21043be809d66c8202e779255e5b660d2danthony 369047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Initialize specific methods 369147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony * + which loop should use the given iteratations 3692a8843c1f815ffad2568ec592d5b446cb1476aab5anthony * + how many primitives make up the compound morphology 369347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony * + multi-kernel compose method to use (by default) 369447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 369547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_limit = 1; /* just do method once, unless otherwise set */ 3696ea61f01656bb0f9074677452017cc559e54093faanthony stage_limit = 1; /* assume method is not a compound */ 36974ee950098ad0166bbbc85c3a59bc079cd321384aglennrp special = MagickFalse; /* assume it is NOT a direct modify primitive */ 369847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = compose; /* and we are composing multi-kernels as given */ 36999eb4f74649b23c053b308ce1152dce51239450baanthony switch( method ) { 3700a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case SmoothMorphology: /* 4 primitive compound morphology */ 370147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_limit = 4; 3702602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3703a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case OpenMorphology: /* 2 primitive compound morphology */ 3704930be614b4595b97cd79ee864a394796740f76adanthony case OpenIntensityMorphology: 370547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: 370647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: 37074fd27e21043be809d66c8202e779255e5b660d2danthony case CloseIntensityMorphology: 370847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 370947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: 371047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_limit = 2; 3711602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 37129eb4f74649b23c053b308ce1152dce51239450baanthony case HitAndMissMorphology: 371347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = LightenCompositeOp; /* Union of multi-kernel results */ 37143ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony /* FALL THUR */ 3715c3e48258f3253188894e783dcdfd03562f7ab2c5anthony case ThinningMorphology: 37169eb4f74649b23c053b308ce1152dce51239450baanthony case ThickenMorphology: 37173ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony method_limit = kernel_limit; /* iterate the whole method */ 3718c3e48258f3253188894e783dcdfd03562f7ab2c5anthony kernel_limit = 1; /* do not do kernel iteration */ 371947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 3720a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3721e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3722f34d9b2df49a407af764c79e07d587af0600983aanthony special = MagickTrue; /* use special direct primative */ 3723a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 372447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 37259eb4f74649b23c053b308ce1152dce51239450baanthony break; 37269eb4f74649b23c053b308ce1152dce51239450baanthony } 3727602ab9b30b644a78a4057da93d838a77391ec0acanthony 3728e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Apply special methods with special requirments 3729e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** For example, single run only, or post-processing requirements 3730e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 3731cd8b331760407523f2a59cc65c1cd9c3d4422bafcristy if ( special != MagickFalse ) 3732e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3733e698a255629ba03cd125572de7b35b5e21c4ee5danthony rslt_image=CloneImage(image,0,0,MagickTrue,exception); 3734e698a255629ba03cd125572de7b35b5e21c4ee5danthony if (rslt_image == (Image *) NULL) 3735e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto error_cleanup; 3736574cc26500992189f637cd1cdf93d0654e7df7aecristy if (SetImageStorageClass(rslt_image,DirectClass,exception) == MagickFalse) 3737574cc26500992189f637cd1cdf93d0654e7df7aecristy goto error_cleanup; 3738e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3739a325e90b7583eab5e70f0ceebb8257670e652f0fcristy changed=MorphologyPrimitiveDirect(rslt_image,method,kernel,exception); 3740e698a255629ba03cd125572de7b35b5e21c4ee5danthony 37417bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 37425acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) (void) FormatLocaleFile(stderr, 37431e604812fad85bb96f757a2393015ae3d061c39acristy "%s:%.20g.%.20g #%.20g => Changed %.20g\n", 37441e604812fad85bb96f757a2393015ae3d061c39acristy CommandOptionToMnemonic(MagickMorphologyOptions, method), 37451e604812fad85bb96f757a2393015ae3d061c39acristy 1.0,0.0,1.0, (double) changed); 3746e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3747e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( changed < 0 ) 3748e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto error_cleanup; 3749e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3750e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( method == VoronoiMorphology ) { 3751a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony /* Preserve the alpha channel of input image - but turned it off */ 375263240888c3975789a09c2494a4654b523931df96cristy (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel, 375363240888c3975789a09c2494a4654b523931df96cristy exception); 3754feb3e9695150978a5d2372d3fe2f60466a7c8066cristy (void) CompositeImage(rslt_image,image,CopyAlphaCompositeOp, 375539172408bad7ef2ef00a815fa9abf9979e7857cbcristy MagickTrue,0,0,exception); 375663240888c3975789a09c2494a4654b523931df96cristy (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel, 375763240888c3975789a09c2494a4654b523931df96cristy exception); 3758e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3759e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto exit_cleanup; 3760e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3761e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3762c3e48258f3253188894e783dcdfd03562f7ab2c5anthony /* Handle user (caller) specified multi-kernel composition method */ 376347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( compose != UndefinedCompositeOp ) 376447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = compose; /* override default composition for method */ 376547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rslt_compose == UndefinedCompositeOp ) 376647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = NoCompositeOp; /* still not defined! Then re-iterate */ 37674fd27e21043be809d66c8202e779255e5b660d2danthony 3768a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Some methods require a reflected kernel to use with primitives. 3769c3e48258f3253188894e783dcdfd03562f7ab2c5anthony * Create the reflected kernel for those methods. */ 377047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch ( method ) { 377147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CorrelateMorphology: 377247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: 377347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseIntensityMorphology: 377447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 377547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case SmoothMorphology: 377647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = CloneKernelInfo(kernel); 377747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if (reflected_kernel == (KernelInfo *) NULL) 377847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony goto error_cleanup; 377947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony RotateKernelInfo(reflected_kernel,180); 378047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 378147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 378247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 378347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 3784602ab9b30b644a78a4057da93d838a77391ec0acanthony 3785e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Loops around more primitive morpholgy methods 3786e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** erose, dilate, open, close, smooth, edge, etc... 3787e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 378847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 1: iterate the compound method */ 378947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_loop = 0; 379047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed = 1; 379147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( method_loop < method_limit && method_changed > 0 ) { 379247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_loop++; 379347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed = 0; 379447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 379547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 2: iterate over each kernel in a multi-kernel list */ 379647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony norm_kernel = (KernelInfo *) kernel; 3797f2faecf9facdbbb14fcba373365f9f691a9658e0cristy this_kernel = (KernelInfo *) kernel; 379847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rflt_kernel = reflected_kernel; 3799e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony 380047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number = 0; 380147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( norm_kernel != NULL ) { 380247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 380347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 3: Compound Morphology Staging - Select Primative to apply */ 380447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_loop = 0; /* the compound morphology stage number */ 380547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( stage_loop < stage_limit ) { 380647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_loop++; /* The stage of the compound morphology */ 380747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 3808a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Select primitive morphology for this stage of compound method */ 380947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = norm_kernel; /* default use unreflected kernel */ 3810a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = method; /* Assume method is a primitive */ 381147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch( method ) { 381247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case ErodeMorphology: /* just erode */ 381347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeInMorphology: /* erode and image difference */ 3814a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 381547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 381647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case DilateMorphology: /* just dilate */ 381747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeOutMorphology: /* dilate and image difference */ 3818a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 381947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 382047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case OpenMorphology: /* erode then dialate */ 382147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: /* open and image difference */ 3822a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 382347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3824a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 382547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 382647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case OpenIntensityMorphology: 3827a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeIntensityMorphology; 382847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3829a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateIntensityMorphology; 3830e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony break; 383147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: /* dilate, then erode */ 383247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: /* close and image difference */ 383347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3834a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 383547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3836a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 383747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 383847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseIntensityMorphology: 383947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3840a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateIntensityMorphology; 384147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3842a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeIntensityMorphology; 384347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 384447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case SmoothMorphology: /* open, close */ 384547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch ( stage_loop ) { 384647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 1: /* start an open method, which starts with Erode */ 3847a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 384847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 384947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 2: /* now Dilate the Erode */ 3850a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 385147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 385247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 3: /* Reflect kernel a close */ 385347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3854a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 385547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 385647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 4: /* Finish the Close */ 385747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3858a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 385947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 386047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 386147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 386247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: /* dilate and erode difference */ 3863a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 386447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) { 386547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = curr_image; /* save the image difference */ 386647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; 3867a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 386847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 386947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 387047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CorrelateMorphology: 387147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* A Correlation is a Convolution with a reflected kernel. 387247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** However a Convolution is a weighted sum using a reflected 387347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** kernel. It may seem stange to convert a Correlation into a 387447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Convolution as the Correlation is the simplier method, but 387547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Convolution is much more commonly used, and it makes sense to 387647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** implement it directly so as to avoid the need to duplicate the 387747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** kernel when it is not required (which is typically the 387847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** default). 387947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 388047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3881a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ConvolveMorphology; 388247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 388347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 388447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 388547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 3886e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert( this_kernel != (KernelInfo *) NULL ); 38877a01dcf50ce12cb2a789bedff51e9345f022432eanthony 388847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Extra information for debugging compound operations */ 38897bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) { 389047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_limit > 1 ) 3891b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy (void) FormatLocaleString(v_info,MaxTextExtent,"%s:%.20g.%.20g -> ", 3892042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickMorphologyOptions,method),(double) 3893e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy method_loop,(double) stage_loop); 3894a8843c1f815ffad2568ec592d5b446cb1476aab5anthony else if ( primitive != method ) 3895b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy (void) FormatLocaleString(v_info, MaxTextExtent, "%s:%.20g -> ", 3896042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickMorphologyOptions, method),(double) 3897e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy method_loop); 389847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else 389947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony v_info[0] = '\0'; 390047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 39019eb4f74649b23c053b308ce1152dce51239450baanthony 3902a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Loop 4: Iterate the kernel with primitive */ 390347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_loop = 0; 390447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_changed = 0; 390547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony changed = 1; 390647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( kernel_loop < kernel_limit && changed > 0 ) { 390747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_loop++; /* the iteration of this kernel */ 39089eb4f74649b23c053b308ce1152dce51239450baanthony 3909a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Create a clone as the destination image, if not yet defined */ 39109eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image == (Image *) NULL ) 39119eb4f74649b23c053b308ce1152dce51239450baanthony { 39129eb4f74649b23c053b308ce1152dce51239450baanthony work_image=CloneImage(image,0,0,MagickTrue,exception); 39139eb4f74649b23c053b308ce1152dce51239450baanthony if (work_image == (Image *) NULL) 39149eb4f74649b23c053b308ce1152dce51239450baanthony goto error_cleanup; 3915574cc26500992189f637cd1cdf93d0654e7df7aecristy if (SetImageStorageClass(work_image,DirectClass,exception) == MagickFalse) 3916574cc26500992189f637cd1cdf93d0654e7df7aecristy goto error_cleanup; 39179eb4f74649b23c053b308ce1152dce51239450baanthony } 39189eb4f74649b23c053b308ce1152dce51239450baanthony 3919501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* APPLY THE MORPHOLOGICAL PRIMITIVE (curr -> work) */ 39209eb4f74649b23c053b308ce1152dce51239450baanthony count++; 3921e698a255629ba03cd125572de7b35b5e21c4ee5danthony changed = MorphologyPrimitive(curr_image, work_image, primitive, 3922f46d42620631d2581e0b6a56456e203e17c427c8anthony this_kernel, bias, exception); 39237bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) { 392447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( kernel_loop > 1 ) 39255acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line from previous */ 39265acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) (void) FormatLocaleFile(stderr, 39271e604812fad85bb96f757a2393015ae3d061c39acristy "%s%s%s:%.20g.%.20g #%.20g => Changed %.20g", 3928042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy v_info,CommandOptionToMnemonic(MagickMorphologyOptions, 3929a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive),(this_kernel == rflt_kernel ) ? "*" : "", 3930e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy (double) (method_loop+kernel_loop-1),(double) kernel_number, 3931e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy (double) count,(double) changed); 393247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 3933a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( changed < 0 ) 3934a8843c1f815ffad2568ec592d5b446cb1476aab5anthony goto error_cleanup; 3935a8843c1f815ffad2568ec592d5b446cb1476aab5anthony kernel_changed += changed; 3936a8843c1f815ffad2568ec592d5b446cb1476aab5anthony method_changed += changed; 3937a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 39389eb4f74649b23c053b308ce1152dce51239450baanthony /* prepare next loop */ 39399eb4f74649b23c053b308ce1152dce51239450baanthony { Image *tmp = work_image; /* swap images for iteration */ 39409eb4f74649b23c053b308ce1152dce51239450baanthony work_image = curr_image; 39419eb4f74649b23c053b308ce1152dce51239450baanthony curr_image = tmp; 39429eb4f74649b23c053b308ce1152dce51239450baanthony } 39439eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image == image ) 394447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = (Image *) NULL; /* replace input 'image' */ 39459eb4f74649b23c053b308ce1152dce51239450baanthony 3946a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* End Loop 4: Iterate the kernel with primitive */ 39477a01dcf50ce12cb2a789bedff51e9345f022432eanthony 39487bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) && kernel_changed != (size_t)changed ) 39495acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " Total %.20g",(double) kernel_changed); 39507bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) && stage_loop < stage_limit ) 39515acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line before looping */ 39529eb4f74649b23c053b308ce1152dce51239450baanthony 395347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony#if 0 39545acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "--E-- image=0x%lx\n", (unsigned long)image); 39555acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " curr =0x%lx\n", (unsigned long)curr_image); 39565acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " work =0x%lx\n", (unsigned long)work_image); 39575acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " save =0x%lx\n", (unsigned long)save_image); 39585acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " union=0x%lx\n", (unsigned long)rslt_image); 395947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony#endif 39601b2bc0a7da432e6e1cc0480280402df213faa940anthony 396147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 3: Primative (staging) Loop for Coumpound Methods */ 39621b2bc0a7da432e6e1cc0480280402df213faa940anthony 396347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Final Post-processing for some Compound Methods 396447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** 396547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** The removal of any 'Sync' channel flag in the Image Compositon 396647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** below ensures the methematical compose method is applied in a 396747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** purely mathematical way, and only to the selected channels. 396847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Turn off SVG composition 'alpha blending'. 396947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 397047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch( method ) { 397147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeOutMorphology: 397247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeInMorphology: 397347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: 397447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 39757bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 3976e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy (void) FormatLocaleFile(stderr, 3977e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy "\n%s: Difference with original image",CommandOptionToMnemonic( 3978e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy MagickMorphologyOptions, method) ); 3979feb3e9695150978a5d2372d3fe2f60466a7c8066cristy (void) CompositeImage(curr_image,image,DifferenceCompositeOp, 398039172408bad7ef2ef00a815fa9abf9979e7857cbcristy MagickTrue,0,0,exception); 398147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 398247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: 39837bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 3984e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy (void) FormatLocaleFile(stderr, 3985e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy "\n%s: Difference of Dilate and Erode",CommandOptionToMnemonic( 3986e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy MagickMorphologyOptions, method) ); 3987feb3e9695150978a5d2372d3fe2f60466a7c8066cristy (void) CompositeImage(curr_image,save_image,DifferenceCompositeOp, 398839172408bad7ef2ef00a815fa9abf9979e7857cbcristy MagickTrue,0,0,exception); 398947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = DestroyImage(save_image); /* finished with save image */ 399047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 399147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 399247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 3993602ab9b30b644a78a4057da93d838a77391ec0acanthony } 39949eb4f74649b23c053b308ce1152dce51239450baanthony 399547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* multi-kernel handling: re-iterate, or compose results */ 399647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( kernel->next == (KernelInfo *) NULL ) 3997c3e48258f3253188894e783dcdfd03562f7ab2c5anthony rslt_image = curr_image; /* just return the resulting image */ 399847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else if ( rslt_compose == NoCompositeOp ) 39997bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony { if ( IfMagickTrue(verbose) ) { 4000c3e48258f3253188894e783dcdfd03562f7ab2c5anthony if ( this_kernel->next != (KernelInfo *) NULL ) 40015acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (re-iterate)"); 4002c3e48258f3253188894e783dcdfd03562f7ab2c5anthony else 40035acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (done)"); 4004c3e48258f3253188894e783dcdfd03562f7ab2c5anthony } 4005c3e48258f3253188894e783dcdfd03562f7ab2c5anthony rslt_image = curr_image; /* return result, and re-iterate */ 40069eb4f74649b23c053b308ce1152dce51239450baanthony } 400747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else if ( rslt_image == (Image *) NULL) 40087bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony { if ( IfMagickTrue(verbose) ) 40095acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (save for compose)"); 401047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_image = curr_image; 401147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; /* continue with original image */ 40129eb4f74649b23c053b308ce1152dce51239450baanthony } 401347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else 4014ea61f01656bb0f9074677452017cc559e54093faanthony { /* Add the new 'current' result to the composition 401547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** 401647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** The removal of any 'Sync' channel flag in the Image Compositon 401747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** below ensures the methematical compose method is applied in a 401847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** purely mathematical way, and only to the selected channels. 4019ea61f01656bb0f9074677452017cc559e54093faanthony ** IE: Turn off SVG composition 'alpha blending'. 402047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 40217bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 40225acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (compose \"%s\")", 4023feb3e9695150978a5d2372d3fe2f60466a7c8066cristy CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) ); 402439172408bad7ef2ef00a815fa9abf9979e7857cbcristy (void) CompositeImage(rslt_image,curr_image,rslt_compose,MagickTrue, 4025feb3e9695150978a5d2372d3fe2f60466a7c8066cristy 0,0,exception); 40260bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony curr_image = DestroyImage(curr_image); 402747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; /* continue with original image */ 402847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 40297bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 40305acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); 40314fd27e21043be809d66c8202e779255e5b660d2danthony 403247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* loop to the next kernel in a multi-kernel list */ 403347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony norm_kernel = norm_kernel->next; 403447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rflt_kernel != (KernelInfo *) NULL ) 403547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rflt_kernel = rflt_kernel->next; 403647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number++; 403747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 2: Loop over each kernel */ 40389eb4f74649b23c053b308ce1152dce51239450baanthony 403947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 1: compound method interation */ 4040602ab9b30b644a78a4057da93d838a77391ec0acanthony 40419eb4f74649b23c053b308ce1152dce51239450baanthony goto exit_cleanup; 40421b2bc0a7da432e6e1cc0480280402df213faa940anthony 404347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Yes goto's are bad, but it makes cleanup lot more efficient */ 40441b2bc0a7da432e6e1cc0480280402df213faa940anthonyerror_cleanup: 4045ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image == rslt_image ) 4046ea61f01656bb0f9074677452017cc559e54093faanthony curr_image = (Image *) NULL; 404747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rslt_image != (Image *) NULL ) 404847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_image = DestroyImage(rslt_image); 40491b2bc0a7da432e6e1cc0480280402df213faa940anthonyexit_cleanup: 4050ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image == rslt_image || curr_image == image ) 4051ea61f01656bb0f9074677452017cc559e54093faanthony curr_image = (Image *) NULL; 4052ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image != (Image *) NULL ) 405347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = DestroyImage(curr_image); 40549eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image != (Image *) NULL ) 405547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = DestroyImage(work_image); 40569eb4f74649b23c053b308ce1152dce51239450baanthony if ( save_image != (Image *) NULL ) 405747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = DestroyImage(save_image); 405847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( reflected_kernel != (KernelInfo *) NULL ) 405947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = DestroyKernelInfo(reflected_kernel); 406047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return(rslt_image); 40619eb4f74649b23c053b308ce1152dce51239450baanthony} 4062a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 40639eb4f74649b23c053b308ce1152dce51239450baanthony 40649eb4f74649b23c053b308ce1152dce51239450baanthony/* 40659eb4f74649b23c053b308ce1152dce51239450baanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 40669eb4f74649b23c053b308ce1152dce51239450baanthony% % 40679eb4f74649b23c053b308ce1152dce51239450baanthony% % 40689eb4f74649b23c053b308ce1152dce51239450baanthony% % 4069f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% M o r p h o l o g y I m a g e % 40709eb4f74649b23c053b308ce1152dce51239450baanthony% % 40719eb4f74649b23c053b308ce1152dce51239450baanthony% % 40729eb4f74649b23c053b308ce1152dce51239450baanthony% % 40739eb4f74649b23c053b308ce1152dce51239450baanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 40749eb4f74649b23c053b308ce1152dce51239450baanthony% 4075a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony% MorphologyImage() applies a user supplied kernel to the image according to 4076a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony% the given mophology method. 40779eb4f74649b23c053b308ce1152dce51239450baanthony% 40789eb4f74649b23c053b308ce1152dce51239450baanthony% This function applies any and all user defined settings before calling 40799eb4f74649b23c053b308ce1152dce51239450baanthony% the above internal function MorphologyApply(). 40809eb4f74649b23c053b308ce1152dce51239450baanthony% 40819eb4f74649b23c053b308ce1152dce51239450baanthony% User defined settings include... 408222de2722b682eb405b60ec6022a7546df994674eanthony% * Output Bias for Convolution and correlation ("-define convolve:bias=??") 408322de2722b682eb405b60ec6022a7546df994674eanthony% * Kernel Scale/normalize settings ("-define convolve:scale=??") 408446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This can also includes the addition of a scaled unity kernel. 408522de2722b682eb405b60ec6022a7546df994674eanthony% * Show Kernel being applied ("-define showkernel=1") 408622de2722b682eb405b60ec6022a7546df994674eanthony% 408722de2722b682eb405b60ec6022a7546df994674eanthony% Other operators that do not want user supplied options interfering, 408822de2722b682eb405b60ec6022a7546df994674eanthony% especially "convolve:bias" and "showkernel" should use MorphologyApply() 408922de2722b682eb405b60ec6022a7546df994674eanthony% directly. 40909eb4f74649b23c053b308ce1152dce51239450baanthony% 40919eb4f74649b23c053b308ce1152dce51239450baanthony% The format of the MorphologyImage method is: 40929eb4f74649b23c053b308ce1152dce51239450baanthony% 40939eb4f74649b23c053b308ce1152dce51239450baanthony% Image *MorphologyImage(const Image *image,MorphologyMethod method, 4094bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% const ssize_t iterations,KernelInfo *kernel,ExceptionInfo *exception) 40959eb4f74649b23c053b308ce1152dce51239450baanthony% 40969eb4f74649b23c053b308ce1152dce51239450baanthony% A description of each parameter follows: 40979eb4f74649b23c053b308ce1152dce51239450baanthony% 40989eb4f74649b23c053b308ce1152dce51239450baanthony% o image: the image. 40999eb4f74649b23c053b308ce1152dce51239450baanthony% 41009eb4f74649b23c053b308ce1152dce51239450baanthony% o method: the morphology method to be applied. 41019eb4f74649b23c053b308ce1152dce51239450baanthony% 41029eb4f74649b23c053b308ce1152dce51239450baanthony% o iterations: apply the operation this many times (or no change). 41039eb4f74649b23c053b308ce1152dce51239450baanthony% A value of -1 means loop until no change found. 41049eb4f74649b23c053b308ce1152dce51239450baanthony% How this is applied may depend on the morphology method. 41059eb4f74649b23c053b308ce1152dce51239450baanthony% Typically this is a value of 1. 41069eb4f74649b23c053b308ce1152dce51239450baanthony% 41079eb4f74649b23c053b308ce1152dce51239450baanthony% o kernel: An array of double representing the morphology kernel. 41089eb4f74649b23c053b308ce1152dce51239450baanthony% Warning: kernel may be normalized for the Convolve method. 41099eb4f74649b23c053b308ce1152dce51239450baanthony% 41109eb4f74649b23c053b308ce1152dce51239450baanthony% o exception: return any errors or warnings in this structure. 41119eb4f74649b23c053b308ce1152dce51239450baanthony% 41129eb4f74649b23c053b308ce1152dce51239450baanthony*/ 4113f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristyMagickExport Image *MorphologyImage(const Image *image, 4114f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method,const ssize_t iterations, 4115f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const KernelInfo *kernel,ExceptionInfo *exception) 41169eb4f74649b23c053b308ce1152dce51239450baanthony{ 41179eb4f74649b23c053b308ce1152dce51239450baanthony KernelInfo 41189eb4f74649b23c053b308ce1152dce51239450baanthony *curr_kernel; 41199eb4f74649b23c053b308ce1152dce51239450baanthony 412047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony CompositeOperator 412147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony compose; 412247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 41239eb4f74649b23c053b308ce1152dce51239450baanthony Image 41249eb4f74649b23c053b308ce1152dce51239450baanthony *morphology_image; 41259eb4f74649b23c053b308ce1152dce51239450baanthony 4126f46d42620631d2581e0b6a56456e203e17c427c8anthony double 4127f46d42620631d2581e0b6a56456e203e17c427c8anthony bias; 41289eb4f74649b23c053b308ce1152dce51239450baanthony 412922de2722b682eb405b60ec6022a7546df994674eanthony curr_kernel = (KernelInfo *) kernel; 413022de2722b682eb405b60ec6022a7546df994674eanthony bias=0.0; 4131d228c03fa334bae897eee6c2d8721fa48e1577bacristy compose = UndefinedCompositeOp; /* use default for method */ 413222de2722b682eb405b60ec6022a7546df994674eanthony 413346a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Apply Convolve/Correlate Normalization and Scaling Factors. 413446a369d839971ab627bdb31a93d8bd63e81b65a3anthony * This is done BEFORE the ShowKernelInfo() function is called so that 413546a369d839971ab627bdb31a93d8bd63e81b65a3anthony * users can see the results of the 'option:convolve:scale' option. 41369eb4f74649b23c053b308ce1152dce51239450baanthony */ 4137d9435776384a479c2f0d621b4bef12a35592fd5dcristy if ( method == ConvolveMorphology || method == CorrelateMorphology ) { 413828ad1d779b6ca95852e860514185a7a97e06af77anthony const char 413928ad1d779b6ca95852e860514185a7a97e06af77anthony *artifact; 4140f46d42620631d2581e0b6a56456e203e17c427c8anthony 414122de2722b682eb405b60ec6022a7546df994674eanthony /* Get the bias value as it will be needed */ 414222de2722b682eb405b60ec6022a7546df994674eanthony artifact = GetImageArtifact(image,"convolve:bias"); 414322de2722b682eb405b60ec6022a7546df994674eanthony if ( artifact != (const char *) NULL) { 414422de2722b682eb405b60ec6022a7546df994674eanthony if (IfMagickFalse(IsGeometry(artifact))) 414522de2722b682eb405b60ec6022a7546df994674eanthony (void) ThrowMagickException(exception,GetMagickModule(), 414622de2722b682eb405b60ec6022a7546df994674eanthony OptionWarning,"InvalidSetting","'%s' '%s'", 414722de2722b682eb405b60ec6022a7546df994674eanthony "convolve:bias",artifact); 414822de2722b682eb405b60ec6022a7546df994674eanthony else 414922de2722b682eb405b60ec6022a7546df994674eanthony bias=StringToDoubleInterval(artifact,(double) QuantumRange+1.0); 415022de2722b682eb405b60ec6022a7546df994674eanthony } 415122de2722b682eb405b60ec6022a7546df994674eanthony 415222de2722b682eb405b60ec6022a7546df994674eanthony /* Scale kernel according to user wishes */ 41539eb4f74649b23c053b308ce1152dce51239450baanthony artifact = GetImageArtifact(image,"convolve:scale"); 4154e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony if ( artifact != (const char *)NULL ) { 415522de2722b682eb405b60ec6022a7546df994674eanthony if (IfMagickFalse(IsGeometry(artifact))) 415622de2722b682eb405b60ec6022a7546df994674eanthony (void) ThrowMagickException(exception,GetMagickModule(), 415722de2722b682eb405b60ec6022a7546df994674eanthony OptionWarning,"InvalidSetting","'%s' '%s'", 415822de2722b682eb405b60ec6022a7546df994674eanthony "convolve:scale",artifact); 415922de2722b682eb405b60ec6022a7546df994674eanthony else { 416022de2722b682eb405b60ec6022a7546df994674eanthony if ( curr_kernel == kernel ) 416122de2722b682eb405b60ec6022a7546df994674eanthony curr_kernel = CloneKernelInfo(kernel); 416222de2722b682eb405b60ec6022a7546df994674eanthony if (curr_kernel == (KernelInfo *) NULL) 416322de2722b682eb405b60ec6022a7546df994674eanthony return((Image *) NULL); 416422de2722b682eb405b60ec6022a7546df994674eanthony ScaleGeometryKernelInfo(curr_kernel, artifact); 41659eb4f74649b23c053b308ce1152dce51239450baanthony } 41669eb4f74649b23c053b308ce1152dce51239450baanthony } 41679eb4f74649b23c053b308ce1152dce51239450baanthony } 41689eb4f74649b23c053b308ce1152dce51239450baanthony 41699eb4f74649b23c053b308ce1152dce51239450baanthony /* display the (normalized) kernel via stderr */ 417048656f2d1ca9ac9979eac32052e4cdc4958c9010cristy if ( IfStringTrue(GetImageArtifact(image,"showkernel")) 417148656f2d1ca9ac9979eac32052e4cdc4958c9010cristy || IfStringTrue(GetImageArtifact(image,"convolve:showkernel")) 417248656f2d1ca9ac9979eac32052e4cdc4958c9010cristy || IfStringTrue(GetImageArtifact(image,"morphology:showkernel")) ) 41739eb4f74649b23c053b308ce1152dce51239450baanthony ShowKernelInfo(curr_kernel); 41749eb4f74649b23c053b308ce1152dce51239450baanthony 41753206678d008425bc56dd2dbad002f2bb26299dc2anthony /* Override the default handling of multi-kernel morphology results 41763206678d008425bc56dd2dbad002f2bb26299dc2anthony * If 'Undefined' use the default method 41773206678d008425bc56dd2dbad002f2bb26299dc2anthony * If 'None' (default for 'Convolve') re-iterate previous result 41783206678d008425bc56dd2dbad002f2bb26299dc2anthony * Otherwise merge resulting images using compose method given. 41793206678d008425bc56dd2dbad002f2bb26299dc2anthony * Default for 'HitAndMiss' is 'Lighten'. 418047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 418128ad1d779b6ca95852e860514185a7a97e06af77anthony { const char 418228ad1d779b6ca95852e860514185a7a97e06af77anthony *artifact; 418322de2722b682eb405b60ec6022a7546df994674eanthony ssize_t 418422de2722b682eb405b60ec6022a7546df994674eanthony parse; 418522de2722b682eb405b60ec6022a7546df994674eanthony 4186f46d42620631d2581e0b6a56456e203e17c427c8anthony artifact = GetImageArtifact(image,"morphology:compose"); 418722de2722b682eb405b60ec6022a7546df994674eanthony if ( artifact != (const char *) NULL) { 418822de2722b682eb405b60ec6022a7546df994674eanthony parse=ParseCommandOption(MagickComposeOptions, 418970b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy MagickFalse,artifact); 419022de2722b682eb405b60ec6022a7546df994674eanthony if ( parse < 0 ) 419122de2722b682eb405b60ec6022a7546df994674eanthony (void) ThrowMagickException(exception,GetMagickModule(), 419222de2722b682eb405b60ec6022a7546df994674eanthony OptionWarning,"UnrecognizedComposeOperator","'%s' '%s'", 419322de2722b682eb405b60ec6022a7546df994674eanthony "morphology:compose",artifact); 419422de2722b682eb405b60ec6022a7546df994674eanthony else 419522de2722b682eb405b60ec6022a7546df994674eanthony compose=(CompositeOperator)parse; 419622de2722b682eb405b60ec6022a7546df994674eanthony } 419728ad1d779b6ca95852e860514185a7a97e06af77anthony } 41989eb4f74649b23c053b308ce1152dce51239450baanthony /* Apply the Morphology */ 4199f46d42620631d2581e0b6a56456e203e17c427c8anthony morphology_image = MorphologyApply(image,method,iterations, 4200f46d42620631d2581e0b6a56456e203e17c427c8anthony curr_kernel,compose,bias,exception); 42019eb4f74649b23c053b308ce1152dce51239450baanthony 42029eb4f74649b23c053b308ce1152dce51239450baanthony /* Cleanup and Exit */ 42039eb4f74649b23c053b308ce1152dce51239450baanthony if ( curr_kernel != kernel ) 42041b2bc0a7da432e6e1cc0480280402df213faa940anthony curr_kernel=DestroyKernelInfo(curr_kernel); 42059eb4f74649b23c053b308ce1152dce51239450baanthony return(morphology_image); 42069eb4f74649b23c053b308ce1152dce51239450baanthony} 420783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 420883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony/* 420983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 421083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 421183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 421283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 42134fd27e21043be809d66c8202e779255e5b660d2danthony+ R o t a t e K e r n e l I n f o % 421483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 421583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 421683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 421783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 421883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 421946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% RotateKernelInfo() rotates the kernel by the angle given. 422046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 422146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Currently it is restricted to 90 degree angles, of either 1D kernels 422246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% or square kernels. And 'circular' rotations of 45 degrees for 3x3 kernels. 422346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% It will ignore usless rotations for specific 'named' built-in kernels. 422483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 42254fd27e21043be809d66c8202e779255e5b660d2danthony% The format of the RotateKernelInfo method is: 422683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 42274fd27e21043be809d66c8202e779255e5b660d2danthony% void RotateKernelInfo(KernelInfo *kernel, double angle) 422883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 422983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A description of each parameter follows: 423083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 423183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o kernel: the Morphology/Convolution kernel 423283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 423383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o angle: angle to rotate in degrees 423483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 423546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This function is currently internal to this module only, but can be exported 423646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% to other modules if needed. 423783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony*/ 42384fd27e21043be809d66c8202e779255e5b660d2danthonystatic void RotateKernelInfo(KernelInfo *kernel, double angle) 423983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony{ 42401b2bc0a7da432e6e1cc0480280402df213faa940anthony /* angle the lower kernels first */ 42411b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 42421b2bc0a7da432e6e1cc0480280402df213faa940anthony RotateKernelInfo(kernel->next, angle); 42431b2bc0a7da432e6e1cc0480280402df213faa940anthony 424483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* WARNING: Currently assumes the kernel (rightly) is horizontally symetrical 424583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony ** 424683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony ** TODO: expand beyond simple 90 degree rotates, flips and flops 424783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony */ 424883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 424983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* Modulus the angle */ 425083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle = fmod(angle, 360.0); 425183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( angle < 0 ) 425283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle += 360.0; 425383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 42543c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 337.5 < angle || angle <= 22.5 ) 425543c4925e5305a26e48d68f7893e94f55d0831c39anthony return; /* Near zero angle - no change! - At least not at this time */ 425683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 42573dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* Handle special cases */ 425883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony switch (kernel->type) { 425983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These built-in kernels are cylindrical kernels, rotating is useless */ 426083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case GaussianKernel: 4261501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 4262501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 426383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case DiskKernel: 42643dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case PeaksKernel: 42653dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case LaplacianKernel: 426683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case ChebyshevKernel: 4267bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 426883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case EuclideanKernel: 426983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 427083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 427183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These may be rotatable at non-90 angles in the future */ 427283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* but simply rotating them in multiples of 90 degrees is useless */ 427383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case SquareKernel: 427483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case DiamondKernel: 427583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case PlusKernel: 42763dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case CrossKernel: 427783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 427883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 427983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These only allows a +/-90 degree rotation (by transpose) */ 428083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* A 180 degree rotation is useless */ 428183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case BlurKernel: 428283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 135.0 < angle && angle <= 225.0 ) 428383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 428483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 225.0 < angle && angle <= 315.0 ) 428583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle -= 180; 428683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony break; 428783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 42883dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony default: 428983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony break; 429083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 429157fe7a498c1302232dac8466864e84b12fad0807anthony /* Attempt rotations by 45 degrees -- 3x3 kernels only */ 42923c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 ) 42933c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { 42943c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( kernel->width == 3 && kernel->height == 3 ) 42953c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { /* Rotate a 3x3 square by 45 degree angle */ 4296a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy double t = kernel->values[0]; 429743c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[0] = kernel->values[3]; 429843c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[3] = kernel->values[6]; 429943c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[6] = kernel->values[7]; 430043c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[7] = kernel->values[8]; 430143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[8] = kernel->values[5]; 430243c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[5] = kernel->values[2]; 430343c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[2] = kernel->values[1]; 430443c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[1] = t; 43051d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* rotate non-centered origin */ 43061d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( kernel->x != 1 || kernel->y != 1 ) { 4307bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t x,y; 4308bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy x = (ssize_t) kernel->x-1; 4309bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy y = (ssize_t) kernel->y-1; 43101d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( x == y ) x = 0; 43111d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( x == 0 ) x = -y; 43121d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( x == -y ) y = 0; 43131d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( y == 0 ) y = x; 4314ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->x = (ssize_t) x+1; 4315ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->y = (ssize_t) y+1; 43161d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 431743c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+315.0, 360.0); /* angle reduced 45 degrees */ 431843c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+45.0, 360.0); 43193c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 43203c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else 43213c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony perror("Unable to rotate non-3x3 kernel by 45 degrees"); 43223c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 43233c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 45.0 < fmod(angle, 180.0) && fmod(angle,180.0) <= 135.0 ) 43243c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { 43253c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( kernel->width == 1 || kernel->height == 1 ) 43264c08aed51c5899665ade97263692328eea4af106cristy { /* Do a transpose of a 1 dimensional kernel, 4327bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ** which results in a fast 90 degree rotation of some type. 43283c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony */ 4329bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t 43303c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony t; 4331bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy t = (ssize_t) kernel->width; 43323c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->width = kernel->height; 4333bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t) t; 43343c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony t = kernel->x; 43353c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->x = kernel->y; 43363c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->y = t; 433743c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( kernel->width == 1 ) { 433843c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+270.0, 360.0); /* angle reduced 90 degrees */ 433943c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+90.0, 360.0); 434043c4925e5305a26e48d68f7893e94f55d0831c39anthony } else { 434143c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+90.0, 360.0); /* angle increased 90 degrees */ 434243c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+270.0, 360.0); 434343c4925e5305a26e48d68f7893e94f55d0831c39anthony } 43443c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 43453c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else if ( kernel->width == kernel->height ) 43463c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { /* Rotate a square array of values by 90 degrees */ 4347d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy { register ssize_t 43481d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony i,j,x,y; 4349d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 4350d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register MagickRealType 43511d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony *k,t; 4352d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 43531d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k=kernel->values; 4354d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy for( i=0, x=(ssize_t) kernel->width-1; i<=x; i++, x--) 4355d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy for( j=0, y=(ssize_t) kernel->height-1; j<y; j++, y--) 43561d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony { t = k[i+j*kernel->width]; 43571d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[i+j*kernel->width] = k[j+x*kernel->width]; 43581d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[j+x*kernel->width] = k[x+y*kernel->width]; 43591d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[x+y*kernel->width] = k[y+i*kernel->width]; 43601d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[y+i*kernel->width] = t; 43611d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 43621d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 43631d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* rotate the origin - relative to center of array */ 4364bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy { register ssize_t x,y; 4365eaedf06777741da32408da72c1e512975c600c48cristy x = (ssize_t) (kernel->x*2-kernel->width+1); 4366eaedf06777741da32408da72c1e512975c600c48cristy y = (ssize_t) (kernel->y*2-kernel->height+1); 4367ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->x = (ssize_t) ( -y +(ssize_t) kernel->width-1)/2; 4368ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->y = (ssize_t) ( +x +(ssize_t) kernel->height-1)/2; 43691d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 437043c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+270.0, 360.0); /* angle reduced 90 degrees */ 437143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+90.0, 360.0); 43723c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 43733c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else 43743c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony perror("Unable to rotate a non-square, non-linear kernel 90 degrees"); 43753c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 437683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 135.0 < angle && angle <= 225.0 ) 437783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony { 437843c4925e5305a26e48d68f7893e94f55d0831c39anthony /* For a 180 degree rotation - also know as a reflection 437943c4925e5305a26e48d68f7893e94f55d0831c39anthony * This is actually a very very common operation! 438043c4925e5305a26e48d68f7893e94f55d0831c39anthony * Basically all that is needed is a reversal of the kernel data! 438143c4925e5305a26e48d68f7893e94f55d0831c39anthony * And a reflection of the origon 438243c4925e5305a26e48d68f7893e94f55d0831c39anthony */ 4383a23c649213358645994ad489b8c9a317c60111afcristy MagickRealType 4384a96f2494a8e79144a225056be9545cc75e868137cristy t; 4385a96f2494a8e79144a225056be9545cc75e868137cristy 4386d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register MagickRealType 4387a96f2494a8e79144a225056be9545cc75e868137cristy *k; 4388a96f2494a8e79144a225056be9545cc75e868137cristy 4389a96f2494a8e79144a225056be9545cc75e868137cristy ssize_t 4390a96f2494a8e79144a225056be9545cc75e868137cristy i, 4391a96f2494a8e79144a225056be9545cc75e868137cristy j; 439283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 439383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony k=kernel->values; 4394e42f658533644aecb733785ffd91b286d6778deacristy j=(ssize_t) (kernel->width*kernel->height-1); 4395e42f658533644aecb733785ffd91b286d6778deacristy for (i=0; i < j; i++, j--) 439683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony t=k[i], k[i]=k[j], k[j]=t; 439783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 4398bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) kernel->width - kernel->x - 1; 4399bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = (ssize_t) kernel->height - kernel->y - 1; 440043c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle-180.0, 360.0); /* angle+180 degrees */ 440143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+180.0, 360.0); 440283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 44033c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony /* At this point angle should at least between -45 (315) and +45 degrees 440483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony * In the future some form of non-orthogonal angled rotates could be 440583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony * performed here, posibily with a linear kernel restriction. 440683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony */ 440783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 440883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 440983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony} 441083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 441183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony/* 441283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 441383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 441483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 441583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 441646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% S c a l e G e o m e t r y K e r n e l I n f o % 441746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 441846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 441946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 442046a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 442146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 442246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% ScaleGeometryKernelInfo() takes a geometry argument string, typically 442346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% provided as a "-set option:convolve:scale {geometry}" user setting, 442446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% and modifies the kernel according to the parsed arguments of that setting. 442546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 442646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The first argument (and any normalization flags) are passed to 442746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% ScaleKernelInfo() to scale/normalize the kernel. The second argument 442846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% is then passed to UnityAddKernelInfo() to add a scled unity kernel 442946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% into the scaled/normalized kernel. 443046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 4431ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% The format of the ScaleGeometryKernelInfo method is: 443246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 4433ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% void ScaleGeometryKernelInfo(KernelInfo *kernel, 4434ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% const double scaling_factor,const MagickStatusType normalize_flags) 443546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 443646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% A description of each parameter follows: 443746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 443846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o kernel: the Morphology/Convolution kernel to modify 443946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 444046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o geometry: 444146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The geometry string to parse, typically from the user provided 444246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% "-set option:convolve:scale {geometry}" setting. 444346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 444446a369d839971ab627bdb31a93d8bd63e81b65a3anthony*/ 444546a369d839971ab627bdb31a93d8bd63e81b65a3anthonyMagickExport void ScaleGeometryKernelInfo (KernelInfo *kernel, 4446954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy const char *geometry) 444746a369d839971ab627bdb31a93d8bd63e81b65a3anthony{ 4448ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy MagickStatusType 444946a369d839971ab627bdb31a93d8bd63e81b65a3anthony flags; 4450ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy 445146a369d839971ab627bdb31a93d8bd63e81b65a3anthony GeometryInfo 445246a369d839971ab627bdb31a93d8bd63e81b65a3anthony args; 445346a369d839971ab627bdb31a93d8bd63e81b65a3anthony 445446a369d839971ab627bdb31a93d8bd63e81b65a3anthony SetGeometryInfo(&args); 445522de2722b682eb405b60ec6022a7546df994674eanthony flags = ParseGeometry(geometry, &args); 445646a369d839971ab627bdb31a93d8bd63e81b65a3anthony 445746a369d839971ab627bdb31a93d8bd63e81b65a3anthony#if 0 445846a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* For Debugging Geometry Input */ 44595acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", 446046a369d839971ab627bdb31a93d8bd63e81b65a3anthony flags, args.rho, args.sigma, args.xi, args.psi ); 446146a369d839971ab627bdb31a93d8bd63e81b65a3anthony#endif 446246a369d839971ab627bdb31a93d8bd63e81b65a3anthony 446346a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & PercentValue) != 0 ) /* Handle Percentage flag*/ 446446a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.rho *= 0.01, args.sigma *= 0.01; 446546a369d839971ab627bdb31a93d8bd63e81b65a3anthony 446646a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & RhoValue) == 0 ) /* Set Defaults for missing args */ 446746a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.rho = 1.0; 446846a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & SigmaValue) == 0 ) 446946a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.sigma = 0.0; 447046a369d839971ab627bdb31a93d8bd63e81b65a3anthony 447146a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Scale/Normalize the input kernel */ 4472d228c03fa334bae897eee6c2d8721fa48e1577bacristy ScaleKernelInfo(kernel, args.rho, (GeometryFlags) flags); 447346a369d839971ab627bdb31a93d8bd63e81b65a3anthony 447446a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Add Unity Kernel, for blending with original */ 447546a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & SigmaValue) != 0 ) 447646a369d839971ab627bdb31a93d8bd63e81b65a3anthony UnityAddKernelInfo(kernel, args.sigma); 447746a369d839971ab627bdb31a93d8bd63e81b65a3anthony 447846a369d839971ab627bdb31a93d8bd63e81b65a3anthony return; 447946a369d839971ab627bdb31a93d8bd63e81b65a3anthony} 448046a369d839971ab627bdb31a93d8bd63e81b65a3anthony/* 448146a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 448246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 448346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 448446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 44856771f1e8987fa49f52d4176281a2e8524b8e31cbcristy% S c a l e K e r n e l I n f o % 4486cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4487cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4488cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4489cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4490cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 44911b2bc0a7da432e6e1cc0480280402df213faa940anthony% ScaleKernelInfo() scales the given kernel list by the given amount, with or 44921b2bc0a7da432e6e1cc0480280402df213faa940anthony% without normalization of the sum of the kernel values (as per given flags). 4493999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4494999bb2c20aa9d42875bb5adba44951988d4ae354anthony% By default (no flags given) the values within the kernel is scaled 44951b2bc0a7da432e6e1cc0480280402df213faa940anthony% directly using given scaling factor without change. 4496999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 449746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% If either of the two 'normalize_flags' are given the kernel will first be 449846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% normalized and then further scaled by the scaling factor value given. 4499999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4500999bb2c20aa9d42875bb5adba44951988d4ae354anthony% Kernel normalization ('normalize_flags' given) is designed to ensure that 4501999bb2c20aa9d42875bb5adba44951988d4ae354anthony% any use of the kernel scaling factor with 'Convolve' or 'Correlate' 45021b2bc0a7da432e6e1cc0480280402df213faa940anthony% morphology methods will fall into -1.0 to +1.0 range. Note that for 45031b2bc0a7da432e6e1cc0480280402df213faa940anthony% non-HDRI versions of IM this may cause images to have any negative results 45041b2bc0a7da432e6e1cc0480280402df213faa940anthony% clipped, unless some 'bias' is used. 4505999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4506999bb2c20aa9d42875bb5adba44951988d4ae354anthony% More specifically. Kernels which only contain positive values (such as a 4507999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 'Gaussian' kernel) will be scaled so that those values sum to +1.0, 45081b2bc0a7da432e6e1cc0480280402df213faa940anthony% ensuring a 0.0 to +1.0 output range for non-HDRI images. 4509999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4510999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For Kernels that contain some negative values, (such as 'Sharpen' kernels) 4511999bb2c20aa9d42875bb5adba44951988d4ae354anthony% the kernel will be scaled by the absolute of the sum of kernel values, so 4512999bb2c20aa9d42875bb5adba44951988d4ae354anthony% that it will generally fall within the +/- 1.0 range. 4513cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4514999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For kernels whose values sum to zero, (such as 'Laplician' kernels) kernel 4515999bb2c20aa9d42875bb5adba44951988d4ae354anthony% will be scaled by just the sum of the postive values, so that its output 4516999bb2c20aa9d42875bb5adba44951988d4ae354anthony% range will again fall into the +/- 1.0 range. 4517cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4518999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For special kernels designed for locating shapes using 'Correlate', (often 4519999bb2c20aa9d42875bb5adba44951988d4ae354anthony% only containing +1 and -1 values, representing foreground/brackground 4520999bb2c20aa9d42875bb5adba44951988d4ae354anthony% matching) a special normalization method is provided to scale the positive 45211e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp% values separately to those of the negative values, so the kernel will be 4522999bb2c20aa9d42875bb5adba44951988d4ae354anthony% forced to become a zero-sum kernel better suited to such searches. 4523999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 45241b2bc0a7da432e6e1cc0480280402df213faa940anthony% WARNING: Correct normalization of the kernel assumes that the '*_range' 4525999bb2c20aa9d42875bb5adba44951988d4ae354anthony% attributes within the kernel structure have been correctly set during the 4526999bb2c20aa9d42875bb5adba44951988d4ae354anthony% kernels creation. 4527999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4528999bb2c20aa9d42875bb5adba44951988d4ae354anthony% NOTE: The values used for 'normalize_flags' have been selected specifically 452946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% to match the use of geometry options, so that '!' means NormalizeValue, '^' 453046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% means CorrelateNormalizeValue. All other GeometryFlags values are ignored. 4531cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 45324fd27e21043be809d66c8202e779255e5b660d2danthony% The format of the ScaleKernelInfo method is: 4533cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4534999bb2c20aa9d42875bb5adba44951988d4ae354anthony% void ScaleKernelInfo(KernelInfo *kernel, const double scaling_factor, 4535999bb2c20aa9d42875bb5adba44951988d4ae354anthony% const MagickStatusType normalize_flags ) 4536cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4537cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% A description of each parameter follows: 4538cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4539cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% o kernel: the Morphology/Convolution kernel 4540cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4541999bb2c20aa9d42875bb5adba44951988d4ae354anthony% o scaling_factor: 4542999bb2c20aa9d42875bb5adba44951988d4ae354anthony% multiply all values (after normalization) by this factor if not 4543999bb2c20aa9d42875bb5adba44951988d4ae354anthony% zero. If the kernel is normalized regardless of any flags. 4544999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4545999bb2c20aa9d42875bb5adba44951988d4ae354anthony% o normalize_flags: 4546999bb2c20aa9d42875bb5adba44951988d4ae354anthony% GeometryFlags defining normalization method to use. 4547999bb2c20aa9d42875bb5adba44951988d4ae354anthony% specifically: NormalizeValue, CorrelateNormalizeValue, 4548999bb2c20aa9d42875bb5adba44951988d4ae354anthony% and/or PercentValue 4549cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4550cc6c836da2a53b6023b716e4973090a6714dc3b0anthony*/ 45516771f1e8987fa49f52d4176281a2e8524b8e31cbcristyMagickExport void ScaleKernelInfo(KernelInfo *kernel, 45526771f1e8987fa49f52d4176281a2e8524b8e31cbcristy const double scaling_factor,const GeometryFlags normalize_flags) 4553cc6c836da2a53b6023b716e4973090a6714dc3b0anthony{ 4554999bb2c20aa9d42875bb5adba44951988d4ae354anthony register double 4555999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale, 4556999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale; 4557999bb2c20aa9d42875bb5adba44951988d4ae354anthony 4558954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy register ssize_t 4559954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy i; 4560954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy 456146a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 45621b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 45631b2bc0a7da432e6e1cc0480280402df213faa940anthony ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags); 45641b2bc0a7da432e6e1cc0480280402df213faa940anthony 456546a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Normalization of Kernel */ 4566999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = 1.0; 4567999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( (normalize_flags&NormalizeValue) != 0 ) { 4568b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(kernel->positive_range + kernel->negative_range) >= MagickEpsilon ) 4569f4e0031305baeb01c89cfd2842cbbec021883550anthony /* non-zero-summing kernel (generally positive) */ 4570999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = fabs(kernel->positive_range + kernel->negative_range); 4571cc6c836da2a53b6023b716e4973090a6714dc3b0anthony else 4572f4e0031305baeb01c89cfd2842cbbec021883550anthony /* zero-summing kernel */ 4573f4e0031305baeb01c89cfd2842cbbec021883550anthony pos_scale = kernel->positive_range; 4574999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 457546a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Force kernel into a normalized zero-summing kernel */ 4576999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) { 4577b978e458a8e1f210bcb580951cf623687236b2fecristy pos_scale = ( fabs(kernel->positive_range) >= MagickEpsilon ) 4578999bb2c20aa9d42875bb5adba44951988d4ae354anthony ? kernel->positive_range : 1.0; 4579b978e458a8e1f210bcb580951cf623687236b2fecristy neg_scale = ( fabs(kernel->negative_range) >= MagickEpsilon ) 4580999bb2c20aa9d42875bb5adba44951988d4ae354anthony ? -kernel->negative_range : 1.0; 4581999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 4582999bb2c20aa9d42875bb5adba44951988d4ae354anthony else 4583999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale = pos_scale; 4584999bb2c20aa9d42875bb5adba44951988d4ae354anthony 4585999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* finialize scaling_factor for positive and negative components */ 4586999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = scaling_factor/pos_scale; 4587999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale = scaling_factor/neg_scale; 4588cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4589bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++) 4590a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ( ! IfNaN(kernel->values[i]) ) 4591999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale; 4592999bb2c20aa9d42875bb5adba44951988d4ae354anthony 4593999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* convolution output range */ 4594999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->positive_range *= pos_scale; 4595999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->negative_range *= neg_scale; 4596999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* maximum and minimum values in kernel */ 4597999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale; 4598999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale; 4599999bb2c20aa9d42875bb5adba44951988d4ae354anthony 460046a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* swap kernel settings if user's scaling factor is negative */ 4601999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( scaling_factor < MagickEpsilon ) { 4602999bb2c20aa9d42875bb5adba44951988d4ae354anthony double t; 4603999bb2c20aa9d42875bb5adba44951988d4ae354anthony t = kernel->positive_range; 4604999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->positive_range = kernel->negative_range; 4605999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->negative_range = t; 4606999bb2c20aa9d42875bb5adba44951988d4ae354anthony t = kernel->maximum; 4607999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->maximum = kernel->minimum; 4608999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->minimum = 1; 4609999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 4610cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4611cc6c836da2a53b6023b716e4973090a6714dc3b0anthony return; 4612cc6c836da2a53b6023b716e4973090a6714dc3b0anthony} 4613cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4614cc6c836da2a53b6023b716e4973090a6714dc3b0anthony/* 4615cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4616cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4617cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4618cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 461946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% S h o w K e r n e l I n f o % 462083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 462183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 462283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 462383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 462483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 46254fd27e21043be809d66c8202e779255e5b660d2danthony% ShowKernelInfo() outputs the details of the given kernel defination to 46264fd27e21043be809d66c8202e779255e5b660d2danthony% standard error, generally due to a users 'showkernel' option request. 462783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 462883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% The format of the ShowKernel method is: 462983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 463057fe7a498c1302232dac8466864e84b12fad0807anthony% void ShowKernelInfo(const KernelInfo *kernel) 463183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 463283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A description of each parameter follows: 463383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 463483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o kernel: the Morphology/Convolution kernel 463583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 463683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony*/ 4637433d11887841b922ec5e6805f9fdd240c320b92ecristyMagickPrivate void ShowKernelInfo(const KernelInfo *kernel) 463883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony{ 463957fe7a498c1302232dac8466864e84b12fad0807anthony const KernelInfo 46407a01dcf50ce12cb2a789bedff51e9345f022432eanthony *k; 46417a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4642bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 46437a01dcf50ce12cb2a789bedff51e9345f022432eanthony c, i, u, v; 46447a01dcf50ce12cb2a789bedff51e9345f022432eanthony 46457a01dcf50ce12cb2a789bedff51e9345f022432eanthony for (c=0, k=kernel; k != (KernelInfo *) NULL; c++, k=k->next ) { 46467a01dcf50ce12cb2a789bedff51e9345f022432eanthony 46475acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Kernel"); 46487a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( kernel->next != (KernelInfo *) NULL ) 46495acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " #%lu", (unsigned long) c ); 46505acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " \"%s", 4651042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickKernelOptions, k->type) ); 4652b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(k->angle) >= MagickEpsilon ) 46535acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "@%lg", k->angle); 46545acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\" of size %lux%lu%+ld%+ld",(unsigned long) 46551e604812fad85bb96f757a2393015ae3d061c39acristy k->width,(unsigned long) k->height,(long) k->x,(long) k->y); 46565acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, 46577a01dcf50ce12cb2a789bedff51e9345f022432eanthony " with values from %.*lg to %.*lg\n", 46587a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->minimum, 46597a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->maximum); 46605acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Forming a output range from %.*lg to %.*lg", 46617a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->negative_range, 466246a369d839971ab627bdb31a93d8bd63e81b65a3anthony GetMagickPrecision(), k->positive_range); 466346a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( fabs(k->positive_range+k->negative_range) < MagickEpsilon ) 46645acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Zero-Summing)\n"); 466546a369d839971ab627bdb31a93d8bd63e81b65a3anthony else if ( fabs(k->positive_range+k->negative_range-1.0) < MagickEpsilon ) 46665acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Normalized)\n"); 466746a369d839971ab627bdb31a93d8bd63e81b65a3anthony else 46685acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Sum %.*lg)\n", 466946a369d839971ab627bdb31a93d8bd63e81b65a3anthony GetMagickPrecision(), k->positive_range+k->negative_range); 467043c4925e5305a26e48d68f7893e94f55d0831c39anthony for (i=v=0; v < k->height; v++) { 46715acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%2lu:", (unsigned long) v ); 467243c4925e5305a26e48d68f7893e94f55d0831c39anthony for (u=0; u < k->width; u++, i++) 4673a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ( IfNaN(k->values[i]) ) 46745acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr," %*s", GetMagickPrecision()+3, "nan"); 46757a01dcf50ce12cb2a789bedff51e9345f022432eanthony else 46765acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr," %*.*lg", GetMagickPrecision()+3, 4677d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy GetMagickPrecision(), (double) k->values[i]); 46785acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr,"\n"); 46797a01dcf50ce12cb2a789bedff51e9345f022432eanthony } 468083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 468183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony} 4682cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4683cc6c836da2a53b6023b716e4973090a6714dc3b0anthony/* 4684cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4685cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4686cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4687cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 468843c4925e5305a26e48d68f7893e94f55d0831c39anthony% U n i t y A d d K e r n a l I n f o % 468943c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 469043c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 469143c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 469243c4925e5305a26e48d68f7893e94f55d0831c39anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 469343c4925e5305a26e48d68f7893e94f55d0831c39anthony% 469443c4925e5305a26e48d68f7893e94f55d0831c39anthony% UnityAddKernelInfo() Adds a given amount of the 'Unity' Convolution Kernel 469543c4925e5305a26e48d68f7893e94f55d0831c39anthony% to the given pre-scaled and normalized Kernel. This in effect adds that 469643c4925e5305a26e48d68f7893e94f55d0831c39anthony% amount of the original image into the resulting convolution kernel. This 469743c4925e5305a26e48d68f7893e94f55d0831c39anthony% value is usually provided by the user as a percentage value in the 469843c4925e5305a26e48d68f7893e94f55d0831c39anthony% 'convolve:scale' setting. 469943c4925e5305a26e48d68f7893e94f55d0831c39anthony% 4700501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% The resulting effect is to convert the defined kernels into blended 4701501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% soft-blurs, unsharp kernels or into sharpening kernels. 470243c4925e5305a26e48d68f7893e94f55d0831c39anthony% 470346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The format of the UnityAdditionKernelInfo method is: 470443c4925e5305a26e48d68f7893e94f55d0831c39anthony% 470543c4925e5305a26e48d68f7893e94f55d0831c39anthony% void UnityAdditionKernelInfo(KernelInfo *kernel, const double scale ) 470643c4925e5305a26e48d68f7893e94f55d0831c39anthony% 470743c4925e5305a26e48d68f7893e94f55d0831c39anthony% A description of each parameter follows: 470843c4925e5305a26e48d68f7893e94f55d0831c39anthony% 470943c4925e5305a26e48d68f7893e94f55d0831c39anthony% o kernel: the Morphology/Convolution kernel 471043c4925e5305a26e48d68f7893e94f55d0831c39anthony% 471143c4925e5305a26e48d68f7893e94f55d0831c39anthony% o scale: 471243c4925e5305a26e48d68f7893e94f55d0831c39anthony% scaling factor for the unity kernel to be added to 471343c4925e5305a26e48d68f7893e94f55d0831c39anthony% the given kernel. 471443c4925e5305a26e48d68f7893e94f55d0831c39anthony% 471543c4925e5305a26e48d68f7893e94f55d0831c39anthony*/ 471643c4925e5305a26e48d68f7893e94f55d0831c39anthonyMagickExport void UnityAddKernelInfo(KernelInfo *kernel, 471743c4925e5305a26e48d68f7893e94f55d0831c39anthony const double scale) 471843c4925e5305a26e48d68f7893e94f55d0831c39anthony{ 471946a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 472046a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( kernel->next != (KernelInfo *) NULL) 472146a369d839971ab627bdb31a93d8bd63e81b65a3anthony UnityAddKernelInfo(kernel->next, scale); 472243c4925e5305a26e48d68f7893e94f55d0831c39anthony 472346a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Add the scaled unity kernel to the existing kernel */ 472443c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[kernel->x+kernel->y*kernel->width] += scale; 472546a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* recalculate the meta-data */ 472643c4925e5305a26e48d68f7893e94f55d0831c39anthony 472743c4925e5305a26e48d68f7893e94f55d0831c39anthony return; 472843c4925e5305a26e48d68f7893e94f55d0831c39anthony} 472943c4925e5305a26e48d68f7893e94f55d0831c39anthony 473043c4925e5305a26e48d68f7893e94f55d0831c39anthony/* 473143c4925e5305a26e48d68f7893e94f55d0831c39anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 473243c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 473343c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 473443c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 473543c4925e5305a26e48d68f7893e94f55d0831c39anthony% Z e r o K e r n e l N a n s % 4736cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4737cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4738cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4739cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4740cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4741cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% ZeroKernelNans() replaces any special 'nan' value that may be present in 4742cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% the kernel with a zero value. This is typically done when the kernel will 4743cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% be used in special hardware (GPU) convolution processors, to simply 4744cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% matters. 4745cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4746cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% The format of the ZeroKernelNans method is: 4747cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 474846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% void ZeroKernelNans (KernelInfo *kernel) 4749cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4750cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% A description of each parameter follows: 4751cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4752cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% o kernel: the Morphology/Convolution kernel 4753cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4754cc6c836da2a53b6023b716e4973090a6714dc3b0anthony*/ 4755cf592636b16d028b14c5fa9dffdc3a94eae7c2f3cristyMagickPrivate void ZeroKernelNans(KernelInfo *kernel) 4756cc6c836da2a53b6023b716e4973090a6714dc3b0anthony{ 4757bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 4758cc6c836da2a53b6023b716e4973090a6714dc3b0anthony i; 4759cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 476046a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 47611b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 47621b2bc0a7da432e6e1cc0480280402df213faa940anthony ZeroKernelNans(kernel->next); 47631b2bc0a7da432e6e1cc0480280402df213faa940anthony 476443c4925e5305a26e48d68f7893e94f55d0831c39anthony for (i=0; i < (kernel->width*kernel->height); i++) 4765a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ( IfNaN(kernel->values[i]) ) 4766cc6c836da2a53b6023b716e4973090a6714dc3b0anthony kernel->values[i] = 0.0; 4767cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4768cc6c836da2a53b6023b716e4973090a6714dc3b0anthony return; 4769cc6c836da2a53b6023b716e4973090a6714dc3b0anthony} 4770