morphology.c revision 306b0f1c3332736bfaddd94c5aaff078a69cbac3
1701db3105315e7d7d9cf2734ae94524c6bc38e80cristy/* 2701db3105315e7d7d9cf2734ae94524c6bc38e80cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 4701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 5701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 6701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% M M OOO RRRR PPPP H H OOO L OOO GGGG Y Y % 7701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% MM MM O O R R P P H H O O L O O G Y Y % 8701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% M M M O O RRRR PPPP HHHHH O O L O O G GGG Y % 9701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% M M O O R R P H H O O L O O G G Y % 10701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% M M OOO R R P H H OOO LLLLL OOO GGG Y % 11701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 12701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 13701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% MagickCore Morphology Methods % 14701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 15701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% Software Design % 16701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% Anthony Thyssen % 17c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% January 2010 % 18701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 19701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 2045ef08fd6a09813e4a8f5ddadf85ba9e0ec2cdc7cristy% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization % 21701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% dedicated to making software imaging solutions freely available. % 22701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 23701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% You may not use this file except in compliance with the License. You may % 24701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% obtain a copy of the License at % 25701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 26701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% http://www.imagemagick.org/script/license.php % 27701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 28701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% Unless required by applicable law or agreed to in writing, software % 29701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% distributed under the License is distributed on an "AS IS" BASIS, % 30701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% See the License for the specific language governing permissions and % 32701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% limitations under the License. % 33701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% % 34701db3105315e7d7d9cf2734ae94524c6bc38e80cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% 361b2bc0a7da432e6e1cc0480280402df213faa940anthony% Morpology is the the application of various kernels, of any size and even 37602ab9b30b644a78a4057da93d838a77391ec0acanthony% shape, to a image in various ways (typically binary, but not always). 38701db3105315e7d7d9cf2734ae94524c6bc38e80cristy% 39602ab9b30b644a78a4057da93d838a77391ec0acanthony% Convolution (weighted sum or average) is just one specific type of 40602ab9b30b644a78a4057da93d838a77391ec0acanthony% morphology. Just one that is very common for image bluring and sharpening 41602ab9b30b644a78a4057da93d838a77391ec0acanthony% effects. Not only 2D Gaussian blurring, but also 2-pass 1D Blurring. 42602ab9b30b644a78a4057da93d838a77391ec0acanthony% 43602ab9b30b644a78a4057da93d838a77391ec0acanthony% This module provides not only a general morphology function, and the ability 44602ab9b30b644a78a4057da93d838a77391ec0acanthony% to apply more advanced or iterative morphologies, but also functions for the 45602ab9b30b644a78a4057da93d838a77391ec0acanthony% generation of many different types of kernel arrays from user supplied 46602ab9b30b644a78a4057da93d838a77391ec0acanthony% arguments. Prehaps even the generation of a kernel from a small image. 47701db3105315e7d7d9cf2734ae94524c6bc38e80cristy*/ 48701db3105315e7d7d9cf2734ae94524c6bc38e80cristy 49701db3105315e7d7d9cf2734ae94524c6bc38e80cristy/* 50701db3105315e7d7d9cf2734ae94524c6bc38e80cristy Include declarations. 51701db3105315e7d7d9cf2734ae94524c6bc38e80cristy*/ 524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h" 534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/artifact.h" 544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache-view.h" 554c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color-private.h" 564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/enhance.h" 574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h" 584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h" 594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/gem.h" 608ea81224e9ff022e56eb2cddb12860a8b2e90411cristy#include "MagickCore/gem-private.h" 614c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/hashmap.h" 624c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h" 634c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h" 644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/list.h" 654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/magick.h" 664c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h" 67e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy#include "MagickCore/memory-private.h" 684c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h" 694c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/morphology.h" 704c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/morphology-private.h" 714c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/option.h" 724c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h" 73f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy#include "MagickCore/pixel-private.h" 744c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/prepress.h" 754c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantize.h" 76ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy#include "MagickCore/resource_.h" 774c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/registry.h" 784c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/semaphore.h" 794c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/splay-tree.h" 804c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/statistic.h" 814c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h" 824c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string-private.h" 8316881e68c6165c6191fc44151a8a4320e3dd1ffdcristy#include "MagickCore/thread-private.h" 844c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/token.h" 854c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/utility.h" 86d1dd6e4fefa0810b9893e6ac9418f79c97c1b39acristy#include "MagickCore/utility-private.h" 87a29d45f897949f04a47bb3da077395969f13dcbacristy 88c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony/* 89a29d45f897949f04a47bb3da077395969f13dcbacristy Other global definitions used by module. 90a29d45f897949f04a47bb3da077395969f13dcbacristy*/ 9129188a8682a98d4b7882cca434b170517555fc7danthonystatic inline double MagickMin(const double x,const double y) 9229188a8682a98d4b7882cca434b170517555fc7danthony{ 9329188a8682a98d4b7882cca434b170517555fc7danthony return( x < y ? x : y); 9429188a8682a98d4b7882cca434b170517555fc7danthony} 9529188a8682a98d4b7882cca434b170517555fc7danthonystatic inline double MagickMax(const double x,const double y) 9629188a8682a98d4b7882cca434b170517555fc7danthony{ 9729188a8682a98d4b7882cca434b170517555fc7danthony return( x > y ? x : y); 9829188a8682a98d4b7882cca434b170517555fc7danthony} 9929188a8682a98d4b7882cca434b170517555fc7danthony#define Minimize(assign,value) assign=MagickMin(assign,value) 10029188a8682a98d4b7882cca434b170517555fc7danthony#define Maximize(assign,value) assign=MagickMax(assign,value) 10129188a8682a98d4b7882cca434b170517555fc7danthony 10240ca0b982379d4ab2716435a46603d56b5b218b1anthony/* Integer Factorial Function - for a Binomial kernel */ 10340ca0b982379d4ab2716435a46603d56b5b218b1anthony#if 1 10440ca0b982379d4ab2716435a46603d56b5b218b1anthonystatic inline size_t fact(size_t n) 10540ca0b982379d4ab2716435a46603d56b5b218b1anthony{ 106f13c594b1d9509e479fd845c3b8a5bb1351c32eacristy size_t f,l; 10740ca0b982379d4ab2716435a46603d56b5b218b1anthony for(f=1, l=2; l <= n; f=f*l, l++); 10840ca0b982379d4ab2716435a46603d56b5b218b1anthony return(f); 10940ca0b982379d4ab2716435a46603d56b5b218b1anthony} 11040ca0b982379d4ab2716435a46603d56b5b218b1anthony#elif 1 /* glibc floating point alternatives */ 11140ca0b982379d4ab2716435a46603d56b5b218b1anthony#define fact(n) ((size_t)tgamma((double)n+1)) 11240ca0b982379d4ab2716435a46603d56b5b218b1anthony#else 11340ca0b982379d4ab2716435a46603d56b5b218b1anthony#define fact(n) ((size_t)lgamma((double)n+1)) 11440ca0b982379d4ab2716435a46603d56b5b218b1anthony#endif 11540ca0b982379d4ab2716435a46603d56b5b218b1anthony 11640ca0b982379d4ab2716435a46603d56b5b218b1anthony 117c4c86e0ad78bebf6b9f931a659fb82987a7042e3anthony/* Currently these are only internal to this module */ 118c4c86e0ad78bebf6b9f931a659fb82987a7042e3anthonystatic void 11946a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(KernelInfo *), 120bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(KernelInfo *), 121bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(KernelInfo *, const double), 122ef656913b0b30d713ae94c82c47693c9dc69c9f4cristy RotateKernelInfo(KernelInfo *, double); 123602ab9b30b644a78a4057da93d838a77391ec0acanthony 1243dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony 1253dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony/* Quick function to find last kernel in a kernel list */ 1263dd0f620e7a1d12f747ce167844cd7269bfa9f12anthonystatic inline KernelInfo *LastKernelInfo(KernelInfo *kernel) 1273dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony{ 1283dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony while (kernel->next != (KernelInfo *) NULL) 1293dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony kernel = kernel->next; 1303dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony return(kernel); 1313dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony} 1323dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony 133602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 134602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 135602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 136602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 137602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 13883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A c q u i r e K e r n e l I n f o % 139602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 140602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 141602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 142602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 143602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1442be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% AcquireKernelInfo() takes the given string (generally supplied by the 145602ab9b30b644a78a4057da93d838a77391ec0acanthony% user) and converts it into a Morphology/Convolution Kernel. This allows 146602ab9b30b644a78a4057da93d838a77391ec0acanthony% users to specify a kernel from a number of pre-defined kernels, or to fully 147602ab9b30b644a78a4057da93d838a77391ec0acanthony% specify their own kernel for a specific Convolution or Morphology 148602ab9b30b644a78a4057da93d838a77391ec0acanthony% Operation. 149602ab9b30b644a78a4057da93d838a77391ec0acanthony% 150602ab9b30b644a78a4057da93d838a77391ec0acanthony% The kernel so generated can be any rectangular array of floating point 151602ab9b30b644a78a4057da93d838a77391ec0acanthony% values (doubles) with the 'control point' or 'pixel being affected' 152602ab9b30b644a78a4057da93d838a77391ec0acanthony% anywhere within that array of values. 153602ab9b30b644a78a4057da93d838a77391ec0acanthony% 15483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% Previously IM was restricted to a square of odd size using the exact 15519910ef25dd3d99d1981a9e42c934133170ee714anthony% center as origin, this is no longer the case, and any rectangular kernel 15683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% with any value being declared the origin. This in turn allows the use of 15783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% highly asymmetrical kernels. 158602ab9b30b644a78a4057da93d838a77391ec0acanthony% 159602ab9b30b644a78a4057da93d838a77391ec0acanthony% The floating point values in the kernel can also include a special value 16083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% known as 'nan' or 'not a number' to indicate that this value is not part 16183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% of the kernel array. This allows you to shaped the kernel within its 16283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% rectangular area. That is 'nan' values provide a 'mask' for the kernel 16383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% shape. However at least one non-nan value must be provided for correct 16483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% working of a kernel. 165602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1667a01dcf50ce12cb2a789bedff51e9345f022432eanthony% The returned kernel should be freed using the DestroyKernelInfo() when you 1677a01dcf50ce12cb2a789bedff51e9345f022432eanthony% are finished with it. Do not free this memory yourself. 168602ab9b30b644a78a4057da93d838a77391ec0acanthony% 169602ab9b30b644a78a4057da93d838a77391ec0acanthony% Input kernel defintion strings can consist of any of three types. 170602ab9b30b644a78a4057da93d838a77391ec0acanthony% 171bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% "name:args[[@><]" 17229188a8682a98d4b7882cca434b170517555fc7danthony% Select from one of the built in kernels, using the name and 17329188a8682a98d4b7882cca434b170517555fc7danthony% geometry arguments supplied. See AcquireKernelBuiltIn() 174602ab9b30b644a78a4057da93d838a77391ec0acanthony% 175bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% "WxH[+X+Y][@><]:num, num, num ..." 1761b2bc0a7da432e6e1cc0480280402df213faa940anthony% a kernel of size W by H, with W*H floating point numbers following. 177602ab9b30b644a78a4057da93d838a77391ec0acanthony% the 'center' can be optionally be defined at +X+Y (such that +0+0 17829188a8682a98d4b7882cca434b170517555fc7danthony% is top left corner). If not defined the pixel in the center, for 17929188a8682a98d4b7882cca434b170517555fc7danthony% odd sizes, or to the immediate top or left of center for even sizes 18029188a8682a98d4b7882cca434b170517555fc7danthony% is automatically selected. 181602ab9b30b644a78a4057da93d838a77391ec0acanthony% 18229188a8682a98d4b7882cca434b170517555fc7danthony% "num, num, num, num, ..." 18329188a8682a98d4b7882cca434b170517555fc7danthony% list of floating point numbers defining an 'old style' odd sized 18429188a8682a98d4b7882cca434b170517555fc7danthony% square kernel. At least 9 values should be provided for a 3x3 18529188a8682a98d4b7882cca434b170517555fc7danthony% square kernel, 25 for a 5x5 square kernel, 49 for 7x7, etc. 18629188a8682a98d4b7882cca434b170517555fc7danthony% Values can be space or comma separated. This is not recommended. 187602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1887a01dcf50ce12cb2a789bedff51e9345f022432eanthony% You can define a 'list of kernels' which can be used by some morphology 1891e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp% operators A list is defined as a semi-colon separated list kernels. 1907a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 191dbc8989a61339951c6434d9a43e7b6fefb5da374anthony% " kernel ; kernel ; kernel ; " 1927a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 1931dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% Any extra ';' characters, at start, end or between kernel defintions are 19443c4925e5305a26e48d68f7893e94f55d0831c39anthony% simply ignored. 19543c4925e5305a26e48d68f7893e94f55d0831c39anthony% 196bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The special flags will expand a single kernel, into a list of rotated 197bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% kernels. A '@' flag will expand a 3x3 kernel into a list of 45-degree 198bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% cyclic rotations, while a '>' will generate a list of 90-degree rotations. 199bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The '<' also exands using 90-degree rotates, but giving a 180-degree 200bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% reflected kernel before the +/- 90-degree rotations, which can be important 201bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% for Thinning operations. 202bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 20343c4925e5305a26e48d68f7893e94f55d0831c39anthony% Note that 'name' kernels will start with an alphabetic character while the 20443c4925e5305a26e48d68f7893e94f55d0831c39anthony% new kernel specification has a ':' character in its specification string. 20543c4925e5305a26e48d68f7893e94f55d0831c39anthony% If neither is the case, it is assumed an old style of a simple list of 20643c4925e5305a26e48d68f7893e94f55d0831c39anthony% numbers generating a odd-sized square kernel has been given. 2077a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 208602ab9b30b644a78a4057da93d838a77391ec0acanthony% The format of the AcquireKernal method is: 209602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2102be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% KernelInfo *AcquireKernelInfo(const char *kernel_string) 211602ab9b30b644a78a4057da93d838a77391ec0acanthony% 212602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 213602ab9b30b644a78a4057da93d838a77391ec0acanthony% 214602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel_string: the Morphology/Convolution kernel wanted. 215602ab9b30b644a78a4057da93d838a77391ec0acanthony% 216602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 217602ab9b30b644a78a4057da93d838a77391ec0acanthony 218c84dce50867229e4872193e8eed5dbab58eb9f02anthony/* This was separated so that it could be used as a separate 2195ef8e94ff55717be2387d537bd49025780a1a558anthony** array input handling function, such as for -color-matrix 220c84dce50867229e4872193e8eed5dbab58eb9f02anthony*/ 2215ef8e94ff55717be2387d537bd49025780a1a558anthonystatic KernelInfo *ParseKernelArray(const char *kernel_string) 222602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 2232be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy KernelInfo 224602ab9b30b644a78a4057da93d838a77391ec0acanthony *kernel; 225602ab9b30b644a78a4057da93d838a77391ec0acanthony 226602ab9b30b644a78a4057da93d838a77391ec0acanthony char 227602ab9b30b644a78a4057da93d838a77391ec0acanthony token[MaxTextExtent]; 228602ab9b30b644a78a4057da93d838a77391ec0acanthony 229602ab9b30b644a78a4057da93d838a77391ec0acanthony const char 2305ef8e94ff55717be2387d537bd49025780a1a558anthony *p, 2315ef8e94ff55717be2387d537bd49025780a1a558anthony *end; 232602ab9b30b644a78a4057da93d838a77391ec0acanthony 233bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 234c84dce50867229e4872193e8eed5dbab58eb9f02anthony i; 235602ab9b30b644a78a4057da93d838a77391ec0acanthony 23629188a8682a98d4b7882cca434b170517555fc7danthony double 23729188a8682a98d4b7882cca434b170517555fc7danthony nan = sqrt((double)-1.0); /* Special Value : Not A Number */ 23829188a8682a98d4b7882cca434b170517555fc7danthony 23943c4925e5305a26e48d68f7893e94f55d0831c39anthony MagickStatusType 24043c4925e5305a26e48d68f7893e94f55d0831c39anthony flags; 24143c4925e5305a26e48d68f7893e94f55d0831c39anthony 24243c4925e5305a26e48d68f7893e94f55d0831c39anthony GeometryInfo 24343c4925e5305a26e48d68f7893e94f55d0831c39anthony args; 24443c4925e5305a26e48d68f7893e94f55d0831c39anthony 245a64b85d7873d5e540fe6e2941aa98ec7653a4e2dcristy kernel=(KernelInfo *) AcquireQuantumMemory(1,sizeof(*kernel)); 2462be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy if (kernel == (KernelInfo *)NULL) 247602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 248602ab9b30b644a78a4057da93d838a77391ec0acanthony (void) ResetMagickMemory(kernel,0,sizeof(*kernel)); 24943c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->minimum = kernel->maximum = kernel->angle = 0.0; 2507a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel->negative_range = kernel->positive_range = 0.0; 251602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->type = UserDefinedKernel; 2527a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel->next = (KernelInfo *) NULL; 253d43a46bc9598004091eae232bc7938e009b494a1cristy kernel->signature = MagickSignature; 2545e6be1e6a77c230e4a204fa9163d873104730c35cristy if (kernel_string == (const char *) NULL) 2555e6be1e6a77c230e4a204fa9163d873104730c35cristy return(kernel); 256602ab9b30b644a78a4057da93d838a77391ec0acanthony 2575ef8e94ff55717be2387d537bd49025780a1a558anthony /* find end of this specific kernel definition string */ 2585ef8e94ff55717be2387d537bd49025780a1a558anthony end = strchr(kernel_string, ';'); 2595ef8e94ff55717be2387d537bd49025780a1a558anthony if ( end == (char *) NULL ) 2605ef8e94ff55717be2387d537bd49025780a1a558anthony end = strchr(kernel_string, '\0'); 2615ef8e94ff55717be2387d537bd49025780a1a558anthony 262a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* clear flags - for Expanding kernel lists thorugh rotations */ 26343c4925e5305a26e48d68f7893e94f55d0831c39anthony flags = NoValue; 26443c4925e5305a26e48d68f7893e94f55d0831c39anthony 265f68116b9d5afef3c343faeb599a3c0ffc8e9b244anthony /* Has a ':' in argument - New user kernel specification 266f68116b9d5afef3c343faeb599a3c0ffc8e9b244anthony FUTURE: this split on ':' could be done by StringToken() 267f68116b9d5afef3c343faeb599a3c0ffc8e9b244anthony */ 268602ab9b30b644a78a4057da93d838a77391ec0acanthony p = strchr(kernel_string, ':'); 2695ef8e94ff55717be2387d537bd49025780a1a558anthony if ( p != (char *) NULL && p < end) 270602ab9b30b644a78a4057da93d838a77391ec0acanthony { 271602ab9b30b644a78a4057da93d838a77391ec0acanthony /* ParseGeometry() needs the geometry separated! -- Arrgghh */ 272150989ed67ef9da53141a65e5f3ebdb05dd025abcristy memcpy(token, kernel_string, (size_t) (p-kernel_string)); 273602ab9b30b644a78a4057da93d838a77391ec0acanthony token[p-kernel_string] = '\0'; 274c84dce50867229e4872193e8eed5dbab58eb9f02anthony SetGeometryInfo(&args); 275602ab9b30b644a78a4057da93d838a77391ec0acanthony flags = ParseGeometry(token, &args); 276602ab9b30b644a78a4057da93d838a77391ec0acanthony 27729188a8682a98d4b7882cca434b170517555fc7danthony /* Size handling and checks of geometry settings */ 278602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( (flags & WidthValue) == 0 ) /* if no width then */ 279602ab9b30b644a78a4057da93d838a77391ec0acanthony args.rho = args.sigma; /* then width = height */ 280602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.rho < 1.0 ) /* if width too small */ 281602ab9b30b644a78a4057da93d838a77391ec0acanthony args.rho = 1.0; /* then width = 1 */ 282602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.sigma < 1.0 ) /* if height too small */ 283602ab9b30b644a78a4057da93d838a77391ec0acanthony args.sigma = args.rho; /* then height = width */ 284bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args.rho; 285bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t)args.sigma; 286602ab9b30b644a78a4057da93d838a77391ec0acanthony 287602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Offset Handling and Checks */ 288602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.xi < 0.0 || args.psi < 0.0 ) 28983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 290bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi 291ea068a53d23d6dca08f1bce44c8937d54f83b983anthony : (ssize_t) (kernel->width-1)/2; 292bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi 293ea068a53d23d6dca08f1bce44c8937d54f83b983anthony : (ssize_t) (kernel->height-1)/2; 294bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( kernel->x >= (ssize_t) kernel->width || 295bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y >= (ssize_t) kernel->height ) 29683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 297602ab9b30b644a78a4057da93d838a77391ec0acanthony 298602ab9b30b644a78a4057da93d838a77391ec0acanthony p++; /* advance beyond the ':' */ 299602ab9b30b644a78a4057da93d838a77391ec0acanthony } 300602ab9b30b644a78a4057da93d838a77391ec0acanthony else 301c84dce50867229e4872193e8eed5dbab58eb9f02anthony { /* ELSE - Old old specification, forming odd-square kernel */ 302602ab9b30b644a78a4057da93d838a77391ec0acanthony /* count up number of values given */ 303602ab9b30b644a78a4057da93d838a77391ec0acanthony p=(const char *) kernel_string; 304a699b171eff7e0178463e8f271b35a3cbb995f0ecristy while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\'')) 30529188a8682a98d4b7882cca434b170517555fc7danthony p++; /* ignore "'" chars for convolve filter usage - Cristy */ 3065ef8e94ff55717be2387d537bd49025780a1a558anthony for (i=0; p < end; i++) 307602ab9b30b644a78a4057da93d838a77391ec0acanthony { 308602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 309602ab9b30b644a78a4057da93d838a77391ec0acanthony if (*token == ',') 310602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 311602ab9b30b644a78a4057da93d838a77391ec0acanthony } 312602ab9b30b644a78a4057da93d838a77391ec0acanthony /* set the size of the kernel - old sized square */ 313bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height= (size_t) sqrt((double) i+1.0); 314bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 315602ab9b30b644a78a4057da93d838a77391ec0acanthony p=(const char *) kernel_string; 31629188a8682a98d4b7882cca434b170517555fc7danthony while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\'')) 31729188a8682a98d4b7882cca434b170517555fc7danthony p++; /* ignore "'" chars for convolve filter usage - Cristy */ 318602ab9b30b644a78a4057da93d838a77391ec0acanthony } 319602ab9b30b644a78a4057da93d838a77391ec0acanthony 320602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Read in the kernel values from rest of input string argument */ 321e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory( 322e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->width,kernel->height*sizeof(*kernel->values))); 323d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 32483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 325c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->minimum = +MagickHuge; 326c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = -MagickHuge; 327c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 328bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++) 329602ab9b30b644a78a4057da93d838a77391ec0acanthony { 330602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 331602ab9b30b644a78a4057da93d838a77391ec0acanthony if (*token == ',') 332602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 33329188a8682a98d4b7882cca434b170517555fc7danthony if ( LocaleCompare("nan",token) == 0 334c84dce50867229e4872193e8eed5dbab58eb9f02anthony || LocaleCompare("-",token) == 0 ) { 335ea068a53d23d6dca08f1bce44c8937d54f83b983anthony kernel->values[i] = nan; /* this value is not part of neighbourhood */ 33629188a8682a98d4b7882cca434b170517555fc7danthony } 33729188a8682a98d4b7882cca434b170517555fc7danthony else { 3380ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony kernel->values[i] = StringToDouble(token,(char **) NULL); 33929188a8682a98d4b7882cca434b170517555fc7danthony ( kernel->values[i] < 0) 340c99304fe3c8d9c617da792b40b57c118bb1249afcristy ? ( kernel->negative_range += kernel->values[i] ) 341c99304fe3c8d9c617da792b40b57c118bb1249afcristy : ( kernel->positive_range += kernel->values[i] ); 342c99304fe3c8d9c617da792b40b57c118bb1249afcristy Minimize(kernel->minimum, kernel->values[i]); 343c99304fe3c8d9c617da792b40b57c118bb1249afcristy Maximize(kernel->maximum, kernel->values[i]); 34429188a8682a98d4b7882cca434b170517555fc7danthony } 34529188a8682a98d4b7882cca434b170517555fc7danthony } 34629188a8682a98d4b7882cca434b170517555fc7danthony 3475ef8e94ff55717be2387d537bd49025780a1a558anthony /* sanity check -- no more values in kernel definition */ 3485ef8e94ff55717be2387d537bd49025780a1a558anthony GetMagickToken(p,&p,token); 3495ef8e94ff55717be2387d537bd49025780a1a558anthony if ( *token != '\0' && *token != ';' && *token != '\'' ) 3505ef8e94ff55717be2387d537bd49025780a1a558anthony return(DestroyKernelInfo(kernel)); 3515ef8e94ff55717be2387d537bd49025780a1a558anthony 352c84dce50867229e4872193e8eed5dbab58eb9f02anthony#if 0 353c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* this was the old method of handling a incomplete kernel */ 354bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( i < (ssize_t) (kernel->width*kernel->height) ) { 355c99304fe3c8d9c617da792b40b57c118bb1249afcristy Minimize(kernel->minimum, kernel->values[i]); 356c99304fe3c8d9c617da792b40b57c118bb1249afcristy Maximize(kernel->maximum, kernel->values[i]); 357bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( ; i < (ssize_t) (kernel->width*kernel->height); i++) 35829188a8682a98d4b7882cca434b170517555fc7danthony kernel->values[i]=0.0; 359602ab9b30b644a78a4057da93d838a77391ec0acanthony } 360c84dce50867229e4872193e8eed5dbab58eb9f02anthony#else 361c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* Number of values for kernel was not enough - Report Error */ 362bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( i < (ssize_t) (kernel->width*kernel->height) ) 363c84dce50867229e4872193e8eed5dbab58eb9f02anthony return(DestroyKernelInfo(kernel)); 364c84dce50867229e4872193e8eed5dbab58eb9f02anthony#endif 365c84dce50867229e4872193e8eed5dbab58eb9f02anthony 366c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* check that we recieved at least one real (non-nan) value! */ 367c84dce50867229e4872193e8eed5dbab58eb9f02anthony if ( kernel->minimum == MagickHuge ) 368c84dce50867229e4872193e8eed5dbab58eb9f02anthony return(DestroyKernelInfo(kernel)); 369602ab9b30b644a78a4057da93d838a77391ec0acanthony 37043c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( (flags & AreaValue) != 0 ) /* '@' symbol in kernel size */ 371bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 45.0); /* cyclic rotate 3x3 kernels */ 372bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */ 373bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 90.0); /* 90 degree rotate of kernel */ 374bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & LessValue) != 0 ) /* '<' symbol in kernel args */ 375bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(kernel); /* 90 degree mirror rotate */ 37643c4925e5305a26e48d68f7893e94f55d0831c39anthony 377602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 378602ab9b30b644a78a4057da93d838a77391ec0acanthony} 379c84dce50867229e4872193e8eed5dbab58eb9f02anthony 38043c4925e5305a26e48d68f7893e94f55d0831c39anthonystatic KernelInfo *ParseKernelName(const char *kernel_string) 381c84dce50867229e4872193e8eed5dbab58eb9f02anthony{ 382c84dce50867229e4872193e8eed5dbab58eb9f02anthony char 383c84dce50867229e4872193e8eed5dbab58eb9f02anthony token[MaxTextExtent]; 384c84dce50867229e4872193e8eed5dbab58eb9f02anthony 385c84dce50867229e4872193e8eed5dbab58eb9f02anthony const char 3867a01dcf50ce12cb2a789bedff51e9345f022432eanthony *p, 3877a01dcf50ce12cb2a789bedff51e9345f022432eanthony *end; 388c84dce50867229e4872193e8eed5dbab58eb9f02anthony 3899d314ff2c17a77996c05413c2013880387e50f0ecristy GeometryInfo 3909d314ff2c17a77996c05413c2013880387e50f0ecristy args; 3919d314ff2c17a77996c05413c2013880387e50f0ecristy 3929d314ff2c17a77996c05413c2013880387e50f0ecristy KernelInfo 3939d314ff2c17a77996c05413c2013880387e50f0ecristy *kernel; 3949d314ff2c17a77996c05413c2013880387e50f0ecristy 395c84dce50867229e4872193e8eed5dbab58eb9f02anthony MagickStatusType 396c84dce50867229e4872193e8eed5dbab58eb9f02anthony flags; 397c84dce50867229e4872193e8eed5dbab58eb9f02anthony 3989d314ff2c17a77996c05413c2013880387e50f0ecristy ssize_t 3999d314ff2c17a77996c05413c2013880387e50f0ecristy type; 400c84dce50867229e4872193e8eed5dbab58eb9f02anthony 401c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* Parse special 'named' kernel */ 4025ef8e94ff55717be2387d537bd49025780a1a558anthony GetMagickToken(kernel_string,&p,token); 403042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy type=ParseCommandOption(MagickKernelOptions,MagickFalse,token); 404c84dce50867229e4872193e8eed5dbab58eb9f02anthony if ( type < 0 || type == UserDefinedKernel ) 4055ef8e94ff55717be2387d537bd49025780a1a558anthony return((KernelInfo *)NULL); /* not a valid named kernel */ 406c84dce50867229e4872193e8eed5dbab58eb9f02anthony 407c84dce50867229e4872193e8eed5dbab58eb9f02anthony while (((isspace((int) ((unsigned char) *p)) != 0) || 4085ef8e94ff55717be2387d537bd49025780a1a558anthony (*p == ',') || (*p == ':' )) && (*p != '\0') && (*p != ';')) 409c84dce50867229e4872193e8eed5dbab58eb9f02anthony p++; 4107a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4117a01dcf50ce12cb2a789bedff51e9345f022432eanthony end = strchr(p, ';'); /* end of this kernel defintion */ 4127a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( end == (char *) NULL ) 4137a01dcf50ce12cb2a789bedff51e9345f022432eanthony end = strchr(p, '\0'); 4147a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4157a01dcf50ce12cb2a789bedff51e9345f022432eanthony /* ParseGeometry() needs the geometry separated! -- Arrgghh */ 4167a01dcf50ce12cb2a789bedff51e9345f022432eanthony memcpy(token, p, (size_t) (end-p)); 4177a01dcf50ce12cb2a789bedff51e9345f022432eanthony token[end-p] = '\0'; 418c84dce50867229e4872193e8eed5dbab58eb9f02anthony SetGeometryInfo(&args); 4197a01dcf50ce12cb2a789bedff51e9345f022432eanthony flags = ParseGeometry(token, &args); 420c84dce50867229e4872193e8eed5dbab58eb9f02anthony 4213c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony#if 0 4223c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony /* For Debugging Geometry Input */ 4235acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", 4241e604812fad85bb96f757a2393015ae3d061c39acristy flags, args.rho, args.sigma, args.xi, args.psi ); 4253c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony#endif 4263c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony 427c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* special handling of missing values in input string */ 428c84dce50867229e4872193e8eed5dbab58eb9f02anthony switch( type ) { 429a9892d898acb81e1ec73106d892855fdc5a69427anthony /* Shape Kernel Defaults */ 430529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 431529482f4b494010a13338a74446c510712f670b3anthony if ( (flags & WidthValue) == 0 ) 432a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = 1.0; /* Default scale = 1.0, zero is valid */ 4335ef8e94ff55717be2387d537bd49025780a1a558anthony break; 4345ef8e94ff55717be2387d537bd49025780a1a558anthony case SquareKernel: 4355ef8e94ff55717be2387d537bd49025780a1a558anthony case DiamondKernel: 4361ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 4375ef8e94ff55717be2387d537bd49025780a1a558anthony case DiskKernel: 4385ef8e94ff55717be2387d537bd49025780a1a558anthony case PlusKernel: 4393dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case CrossKernel: 4405ef8e94ff55717be2387d537bd49025780a1a558anthony if ( (flags & HeightValue) == 0 ) 441a9892d898acb81e1ec73106d892855fdc5a69427anthony args.sigma = 1.0; /* Default scale = 1.0, zero is valid */ 4425ef8e94ff55717be2387d537bd49025780a1a558anthony break; 443c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RingKernel: 444c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( (flags & XValue) == 0 ) 445a9892d898acb81e1ec73106d892855fdc5a69427anthony args.xi = 1.0; /* Default scale = 1.0, zero is valid */ 446c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 447a9892d898acb81e1ec73106d892855fdc5a69427anthony case RectangleKernel: /* Rectangle - set size defaults */ 448a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & WidthValue) == 0 ) /* if no width then */ 449a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = args.sigma; /* then width = height */ 450a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( args.rho < 1.0 ) /* if width too small */ 451a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = 3; /* then width = 3 */ 452a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( args.sigma < 1.0 ) /* if height too small */ 453a9892d898acb81e1ec73106d892855fdc5a69427anthony args.sigma = args.rho; /* then height = width */ 454a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & XValue) == 0 ) /* center offset if not defined */ 455a9892d898acb81e1ec73106d892855fdc5a69427anthony args.xi = (double)(((ssize_t)args.rho-1)/2); 456a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & YValue) == 0 ) 457a9892d898acb81e1ec73106d892855fdc5a69427anthony args.psi = (double)(((ssize_t)args.sigma-1)/2); 458a9892d898acb81e1ec73106d892855fdc5a69427anthony break; 459a9892d898acb81e1ec73106d892855fdc5a69427anthony /* Distance Kernel Defaults */ 4605ef8e94ff55717be2387d537bd49025780a1a558anthony case ChebyshevKernel: 461bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 4621ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonalKernel: 4635ef8e94ff55717be2387d537bd49025780a1a558anthony case EuclideanKernel: 46443c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( (flags & HeightValue) == 0 ) /* no distance scale */ 46543c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma = 100.0; /* default distance scaling */ 46643c4925e5305a26e48d68f7893e94f55d0831c39anthony else if ( (flags & AspectValue ) != 0 ) /* '!' flag */ 46743c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma = QuantumRange/(args.sigma+1); /* maximum pixel distance */ 46843c4925e5305a26e48d68f7893e94f55d0831c39anthony else if ( (flags & PercentValue ) != 0 ) /* '%' flag */ 46943c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma *= QuantumRange/100.0; /* percentage of color range */ 4705ef8e94ff55717be2387d537bd49025780a1a558anthony break; 4715ef8e94ff55717be2387d537bd49025780a1a558anthony default: 4725ef8e94ff55717be2387d537bd49025780a1a558anthony break; 473c84dce50867229e4872193e8eed5dbab58eb9f02anthony } 474c84dce50867229e4872193e8eed5dbab58eb9f02anthony 475f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony kernel = AcquireKernelBuiltIn((KernelInfoType)type, &args); 476529482f4b494010a13338a74446c510712f670b3anthony if ( kernel == (KernelInfo *) NULL ) 477529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 478f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony 479f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony /* global expand to rotated kernel list - only for single kernels */ 480f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony if ( kernel->next == (KernelInfo *) NULL ) { 481f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony if ( (flags & AreaValue) != 0 ) /* '@' symbol in kernel args */ 482bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 45.0); 483bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */ 484bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 90.0); 485bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & LessValue) != 0 ) /* '<' symbol in kernel args */ 486bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(kernel); 487f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony } 488f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony 489f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony return(kernel); 490c84dce50867229e4872193e8eed5dbab58eb9f02anthony} 491c84dce50867229e4872193e8eed5dbab58eb9f02anthony 4925ef8e94ff55717be2387d537bd49025780a1a558anthonyMagickExport KernelInfo *AcquireKernelInfo(const char *kernel_string) 4935ef8e94ff55717be2387d537bd49025780a1a558anthony{ 4947a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4957a01dcf50ce12cb2a789bedff51e9345f022432eanthony KernelInfo 496dbc8989a61339951c6434d9a43e7b6fefb5da374anthony *kernel, 49743c4925e5305a26e48d68f7893e94f55d0831c39anthony *new_kernel; 4987a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4995ef8e94ff55717be2387d537bd49025780a1a558anthony char 5005ef8e94ff55717be2387d537bd49025780a1a558anthony token[MaxTextExtent]; 5015ef8e94ff55717be2387d537bd49025780a1a558anthony 5027a01dcf50ce12cb2a789bedff51e9345f022432eanthony const char 503dbc8989a61339951c6434d9a43e7b6fefb5da374anthony *p; 5047a01dcf50ce12cb2a789bedff51e9345f022432eanthony 505bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 506e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony kernel_number; 507e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony 5085e6be1e6a77c230e4a204fa9163d873104730c35cristy if (kernel_string == (const char *) NULL) 5095e6be1e6a77c230e4a204fa9163d873104730c35cristy return(ParseKernelArray(kernel_string)); 510dbc8989a61339951c6434d9a43e7b6fefb5da374anthony p = kernel_string; 51143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel = NULL; 512e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony kernel_number = 0; 5137a01dcf50ce12cb2a789bedff51e9345f022432eanthony 514dbc8989a61339951c6434d9a43e7b6fefb5da374anthony while ( GetMagickToken(p,NULL,token), *token != '\0' ) { 5157a01dcf50ce12cb2a789bedff51e9345f022432eanthony 5161e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp /* ignore extra or multiple ';' kernel separators */ 517dbc8989a61339951c6434d9a43e7b6fefb5da374anthony if ( *token != ';' ) { 5187a01dcf50ce12cb2a789bedff51e9345f022432eanthony 519dbc8989a61339951c6434d9a43e7b6fefb5da374anthony /* tokens starting with alpha is a Named kernel */ 52043c4925e5305a26e48d68f7893e94f55d0831c39anthony if (isalpha((int) *token) != 0) 52143c4925e5305a26e48d68f7893e94f55d0831c39anthony new_kernel = ParseKernelName(p); 522dbc8989a61339951c6434d9a43e7b6fefb5da374anthony else /* otherwise a user defined kernel array */ 52343c4925e5305a26e48d68f7893e94f55d0831c39anthony new_kernel = ParseKernelArray(p); 524dbc8989a61339951c6434d9a43e7b6fefb5da374anthony 525e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony /* Error handling -- this is not proper error handling! */ 526e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony if ( new_kernel == (KernelInfo *) NULL ) { 52775920b23a8a3883792cbb69d569c33cc789cf1b5cristy (void) FormatLocaleFile(stderr,"Failed to parse kernel number #%.20g\n", 5281e604812fad85bb96f757a2393015ae3d061c39acristy (double) kernel_number); 529e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony if ( kernel != (KernelInfo *) NULL ) 530e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony kernel=DestroyKernelInfo(kernel); 531e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony return((KernelInfo *) NULL); 532dbc8989a61339951c6434d9a43e7b6fefb5da374anthony } 533e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony 534e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony /* initialise or append the kernel list */ 5353dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony if ( kernel == (KernelInfo *) NULL ) 5363dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony kernel = new_kernel; 5373dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony else 53843c4925e5305a26e48d68f7893e94f55d0831c39anthony LastKernelInfo(kernel)->next = new_kernel; 539dbc8989a61339951c6434d9a43e7b6fefb5da374anthony } 540dbc8989a61339951c6434d9a43e7b6fefb5da374anthony 541dbc8989a61339951c6434d9a43e7b6fefb5da374anthony /* look for the next kernel in list */ 542dbc8989a61339951c6434d9a43e7b6fefb5da374anthony p = strchr(p, ';'); 543dbc8989a61339951c6434d9a43e7b6fefb5da374anthony if ( p == (char *) NULL ) 544dbc8989a61339951c6434d9a43e7b6fefb5da374anthony break; 545dbc8989a61339951c6434d9a43e7b6fefb5da374anthony p++; 5465ef8e94ff55717be2387d537bd49025780a1a558anthony 547dbc8989a61339951c6434d9a43e7b6fefb5da374anthony } 5487a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(kernel); 5495ef8e94ff55717be2387d537bd49025780a1a558anthony} 5505ef8e94ff55717be2387d537bd49025780a1a558anthony 551602ab9b30b644a78a4057da93d838a77391ec0acanthony 552602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 553602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 554602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 555602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 556602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 557602ab9b30b644a78a4057da93d838a77391ec0acanthony% A c q u i r e K e r n e l B u i l t I n % 558602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 559602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 560602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 561602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 562602ab9b30b644a78a4057da93d838a77391ec0acanthony% 563602ab9b30b644a78a4057da93d838a77391ec0acanthony% AcquireKernelBuiltIn() returned one of the 'named' built-in types of 564602ab9b30b644a78a4057da93d838a77391ec0acanthony% kernels used for special purposes such as gaussian blurring, skeleton 565602ab9b30b644a78a4057da93d838a77391ec0acanthony% pruning, and edge distance determination. 566602ab9b30b644a78a4057da93d838a77391ec0acanthony% 567602ab9b30b644a78a4057da93d838a77391ec0acanthony% They take a KernelType, and a set of geometry style arguments, which were 568602ab9b30b644a78a4057da93d838a77391ec0acanthony% typically decoded from a user supplied string, or from a more complex 569602ab9b30b644a78a4057da93d838a77391ec0acanthony% Morphology Method that was requested. 570602ab9b30b644a78a4057da93d838a77391ec0acanthony% 571602ab9b30b644a78a4057da93d838a77391ec0acanthony% The format of the AcquireKernalBuiltIn method is: 572602ab9b30b644a78a4057da93d838a77391ec0acanthony% 5732be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type, 574602ab9b30b644a78a4057da93d838a77391ec0acanthony% const GeometryInfo args) 575602ab9b30b644a78a4057da93d838a77391ec0acanthony% 576602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 577602ab9b30b644a78a4057da93d838a77391ec0acanthony% 578602ab9b30b644a78a4057da93d838a77391ec0acanthony% o type: the pre-defined type of kernel wanted 579602ab9b30b644a78a4057da93d838a77391ec0acanthony% 580602ab9b30b644a78a4057da93d838a77391ec0acanthony% o args: arguments defining or modifying the kernel 581602ab9b30b644a78a4057da93d838a77391ec0acanthony% 582602ab9b30b644a78a4057da93d838a77391ec0acanthony% Convolution Kernels 583602ab9b30b644a78a4057da93d838a77391ec0acanthony% 58446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Unity 585529482f4b494010a13338a74446c510712f670b3anthony% The a No-Op or Scaling single element kernel. 58646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 5873c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Gaussian:{radius},{sigma} 5882489f53a1153c2b619b1c9a6744602e8840bd9a9glennrp% Generate a two-dimensional gaussian kernel, as used by -gaussian. 589c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The sigma for the curve is required. The resulting kernel is 590c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% normalized, 591c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 592c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% If 'sigma' is zero, you get a single pixel on a field of zeros. 593602ab9b30b644a78a4057da93d838a77391ec0acanthony% 594602ab9b30b644a78a4057da93d838a77391ec0acanthony% NOTE: that the 'radius' is optional, but if provided can limit (clip) 595602ab9b30b644a78a4057da93d838a77391ec0acanthony% the final size of the resulting kernel to a square 2*radius+1 in size. 596602ab9b30b644a78a4057da93d838a77391ec0acanthony% The radius should be at least 2 times that of the sigma value, or 597602ab9b30b644a78a4057da93d838a77391ec0acanthony% sever clipping and aliasing may result. If not given or set to 0 the 598602ab9b30b644a78a4057da93d838a77391ec0acanthony% radius will be determined so as to produce the best minimal error 599602ab9b30b644a78a4057da93d838a77391ec0acanthony% result, which is usally much larger than is normally needed. 600602ab9b30b644a78a4057da93d838a77391ec0acanthony% 601501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% LoG:{radius},{sigma} 602501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% "Laplacian of a Gaussian" or "Mexician Hat" Kernel. 603501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% The supposed ideal edge detection, zero-summing kernel. 604501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 605501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% An alturnative to this kernel is to use a "DoG" with a sigma ratio of 606501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% approx 1.6 (according to wikipedia). 607501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 608501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% DoG:{radius},{sigma1},{sigma2} 609c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% "Difference of Gaussians" Kernel. 610c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% As "Gaussian" but with a gaussian produced by 'sigma2' subtracted 611c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% from the gaussian produced by 'sigma1'. Typically sigma2 > sigma1. 612c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The result is a zero-summing kernel. 613c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 614c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Blur:{radius},{sigma}[,{angle}] 6154c08aed51c5899665ade97263692328eea4af106cristy% Generates a 1 dimensional or linear gaussian blur, at the angle given 616c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% (current restricted to orthogonal angles). If a 'radius' is given the 617c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% kernel is clipped to a width of 2*radius+1. Kernel can be rotated 618c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% by a 90 degree angle. 619c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 620c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% If 'sigma' is zero, you get a single pixel on a field of zeros. 621c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 622c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Note that two convolutions with two "Blur" kernels perpendicular to 623f0a92fd8deb68d411304359906b12679b675691fglennrp% each other, is equivalent to a far larger "Gaussian" kernel with the 624c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% same sigma value, However it is much faster to apply. This is how the 625c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% "-blur" operator actually works. 626c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 6273c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Comet:{width},{sigma},{angle} 6283c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Blur in one direction only, much like how a bright object leaves 629602ab9b30b644a78a4057da93d838a77391ec0acanthony% a comet like trail. The Kernel is actually half a gaussian curve, 6303c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Adding two such blurs in opposite directions produces a Blur Kernel. 6313c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Angle can be rotated in multiples of 90 degrees. 632602ab9b30b644a78a4057da93d838a77391ec0acanthony% 6333c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Note that the first argument is the width of the kernel and not the 634602ab9b30b644a78a4057da93d838a77391ec0acanthony% radius of the kernel. 635602ab9b30b644a78a4057da93d838a77391ec0acanthony% 63640ca0b982379d4ab2716435a46603d56b5b218b1anthony% Binomial:[{radius}] 63740ca0b982379d4ab2716435a46603d56b5b218b1anthony% Generate a discrete kernel using a 2 dimentional Pascel's Triangle 638eef684ff80c7d5aca1493f4755426c88b3d3accdanthony% of values. Used for special forma of image filters. 63940ca0b982379d4ab2716435a46603d56b5b218b1anthony% 640602ab9b30b644a78a4057da93d838a77391ec0acanthony% # Still to be implemented... 641602ab9b30b644a78a4057da93d838a77391ec0acanthony% # 6424fd27e21043be809d66c8202e779255e5b660d2danthony% # Filter2D 6434fd27e21043be809d66c8202e779255e5b660d2danthony% # Filter1D 6444fd27e21043be809d66c8202e779255e5b660d2danthony% # Set kernel values using a resize filter, and given scale (sigma) 645dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp% # Cylindrical or Linear. Is this possible with an image? 6464fd27e21043be809d66c8202e779255e5b660d2danthony% # 647602ab9b30b644a78a4057da93d838a77391ec0acanthony% 6483c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Named Constant Convolution Kernels 6493c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 650c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% All these are unscaled, zero-summing kernels by default. As such for 651c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% non-HDRI version of ImageMagick some form of normalization, user scaling, 652c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% and biasing the results is recommended, to prevent the resulting image 653c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% being 'clipped'. 654c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 655c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The 3x3 kernels (most of these) can be circularly rotated in multiples of 656c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 45 degrees to generate the 8 angled varients of each of the kernels. 6573c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 6583c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Laplacian:{type} 65943c4925e5305a26e48d68f7893e94f55d0831c39anthony% Discrete Lapacian Kernels, (without normalization) 660c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Type 0 : 3x3 with center:8 surounded by -1 (8 neighbourhood) 661c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Type 1 : 3x3 with center:4 edge:-1 corner:0 (4 neighbourhood) 6629eb4f74649b23c053b308ce1152dce51239450baanthony% Type 2 : 3x3 with center:4 edge:1 corner:-2 6639eb4f74649b23c053b308ce1152dce51239450baanthony% Type 3 : 3x3 with center:4 edge:-2 corner:1 6649eb4f74649b23c053b308ce1152dce51239450baanthony% Type 5 : 5x5 laplacian 6659eb4f74649b23c053b308ce1152dce51239450baanthony% Type 7 : 7x7 laplacian 666501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Type 15 : 5x5 LoG (sigma approx 1.4) 667501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Type 19 : 9x9 LoG (sigma approx 1.4) 668c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 669c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Sobel:{angle} 67046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Sobel 'Edge' convolution kernel (3x3) 671c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 672c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 0,-2 | 673c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 674c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 675c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Roberts:{angle} 67646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Roberts convolution kernel (3x3) 677c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | 678c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 0 | 679c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | 680c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 681c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Prewitt:{angle} 682c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Prewitt Edge convolution kernel (3x3) 683c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 684c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 685c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 686c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 6879eb4f74649b23c053b308ce1152dce51239450baanthony% Compass:{angle} 6889eb4f74649b23c053b308ce1152dce51239450baanthony% Prewitt's "Compass" convolution kernel (3x3) 689c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 1 | 690c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1,-2, 1 | 691c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 1 | 692c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 6939eb4f74649b23c053b308ce1152dce51239450baanthony% Kirsch:{angle} 6949eb4f74649b23c053b308ce1152dce51239450baanthony% Kirsch's "Compass" convolution kernel (3x3) 695c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3,-3, 5 | 696c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3, 0, 5 | 697c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3,-3, 5 | 6983c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 699c40ac1e79923a1516075ba1197ae4ed90244af9banthony% FreiChen:{angle} 7001d5e67090dc7232b35bfcc71b31266c20838defcanthony% Frei-Chen Edge Detector is based on a kernel that is similar to 7011d5e67090dc7232b35bfcc71b31266c20838defcanthony% the Sobel Kernel, but is designed to be isotropic. That is it takes 7021d5e67090dc7232b35bfcc71b31266c20838defcanthony% into account the distance of the diagonal in the kernel. 703c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 704c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 705c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | 706c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 707c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 708c40ac1e79923a1516075ba1197ae4ed90244af9banthony% FreiChen:{type},{angle} 709c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 710c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Frei-Chen Pre-weighted kernels... 711c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 712c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 0: default un-nomalized version shown above. 713c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 714c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 1: Orthogonal Kernel (same as type 11 below) 715c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 716c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 717c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 718c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 719c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 2: Diagonal form of Kernel... 720c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, sqrt(2), 0 | 721c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 722c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, -sqrt(2) -1 | 723c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 7241d5e67090dc7232b35bfcc71b31266c20838defcanthony% However this kernel is als at the heart of the FreiChen Edge Detection 7251d5e67090dc7232b35bfcc71b31266c20838defcanthony% Process which uses a set of 9 specially weighted kernel. These 9 7261d5e67090dc7232b35bfcc71b31266c20838defcanthony% kernels not be normalized, but directly applied to the image. The 7271d5e67090dc7232b35bfcc71b31266c20838defcanthony% results is then added together, to produce the intensity of an edge in 7281d5e67090dc7232b35bfcc71b31266c20838defcanthony% a specific direction. The square root of the pixel value can then be 7291d5e67090dc7232b35bfcc71b31266c20838defcanthony% taken as the cosine of the edge, and at least 2 such runs at 90 degrees 7301d5e67090dc7232b35bfcc71b31266c20838defcanthony% from each other, both the direction and the strength of the edge can be 7311d5e67090dc7232b35bfcc71b31266c20838defcanthony% determined. 7321d5e67090dc7232b35bfcc71b31266c20838defcanthony% 733c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 10: All 9 of the following pre-weighted kernels... 734c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 735c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 11: | 1, 0, -1 | 736c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 737c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 738e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 739c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 12: | 1, sqrt(2), 1 | 740c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | / 2*sqrt(2) 741c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, sqrt(2), 1 | 742e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 743c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 13: | sqrt(2), -1, 0 | 744c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | / 2*sqrt(2) 745c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 1, -sqrt(2) | 746e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 747c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 14: | 0, 1, -sqrt(2) | 748c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | / 2*sqrt(2) 749c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), -1, 0 | 750e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 751c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 15: | 0, -1, 0 | 752c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, 1 | / 2 753c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, -1, 0 | 754e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 755c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 16: | 1, 0, -1 | 756c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | / 2 757c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 758e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 759c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 17: | 1, -2, 1 | 760c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 4, -2 | / 6 761c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, -2, 1 | 762501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 763c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 18: | -2, 1, -2 | 764c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 4, 1 | / 6 765c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 1, -2 | 766e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 767c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 19: | 1, 1, 1 | 768c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 1, 1 | / 3 769c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 1, 1 | 770e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 771e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% The first 4 are for edge detection, the next 4 are for line detection 772e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% and the last is to add a average component to the results. 773e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 774c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% Using a special type of '-1' will return all 9 pre-weighted kernels 775c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% as a multi-kernel list, so that you can use them directly (without 776c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% normalization) with the special "-set option:morphology:compose Plus" 777c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% setting to apply the full FreiChen Edge Detection Technique. 778c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 7791dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% If 'type' is large it will be taken to be an actual rotation angle for 7801dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% the default FreiChen (type 0) kernel. As such FreiChen:45 will look 7811dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% like a Sobel:45 but with 'sqrt(2)' instead of '2' values. 7821dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% 783501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% WARNING: The above was layed out as per 784501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf 785501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% But rotated 90 degrees so direction is from left rather than the top. 786501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% I have yet to find any secondary confirmation of the above. The only 787501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% other source found was actual source code at 788501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf 789501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Neigher paper defineds the kernels in a way that looks locical or 790501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% correct when taken as a whole. 791e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 792602ab9b30b644a78a4057da93d838a77391ec0acanthony% Boolean Kernels 793602ab9b30b644a78a4057da93d838a77391ec0acanthony% 7943c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Diamond:[{radius}[,{scale}]] 7951b2bc0a7da432e6e1cc0480280402df213faa940anthony% Generate a diamond shaped kernel with given radius to the points. 796602ab9b30b644a78a4057da93d838a77391ec0acanthony% Kernel size will again be radius*2+1 square and defaults to radius 1, 797602ab9b30b644a78a4057da93d838a77391ec0acanthony% generating a 3x3 kernel that is slightly larger than a square. 798602ab9b30b644a78a4057da93d838a77391ec0acanthony% 7993c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Square:[{radius}[,{scale}]] 800602ab9b30b644a78a4057da93d838a77391ec0acanthony% Generate a square shaped kernel of size radius*2+1, and defaulting 801602ab9b30b644a78a4057da93d838a77391ec0acanthony% to a 3x3 (radius 1). 802602ab9b30b644a78a4057da93d838a77391ec0acanthony% 8031ef941fea2534a0d20ba7d71307d35040247decbanthony% Octagon:[{radius}[,{scale}]] 8041ef941fea2534a0d20ba7d71307d35040247decbanthony% Generate octagonal shaped kernel of given radius and constant scale. 8050bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% Default radius is 3 producing a 7x7 kernel. A radius of 1 will result 8061ef941fea2534a0d20ba7d71307d35040247decbanthony% in "Diamond" kernel. 8071ef941fea2534a0d20ba7d71307d35040247decbanthony% 8083c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Disk:[{radius}[,{scale}]] 8091ef941fea2534a0d20ba7d71307d35040247decbanthony% Generate a binary disk, thresholded at the radius given, the radius 8101ef941fea2534a0d20ba7d71307d35040247decbanthony% may be a float-point value. Final Kernel size is floor(radius)*2+1 8110bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% square. A radius of 5.3 is the default. 8121ef941fea2534a0d20ba7d71307d35040247decbanthony% 8131ef941fea2534a0d20ba7d71307d35040247decbanthony% NOTE: That a low radii Disk kernels produce the same results as 8141ef941fea2534a0d20ba7d71307d35040247decbanthony% many of the previously defined kernels, but differ greatly at larger 8151ef941fea2534a0d20ba7d71307d35040247decbanthony% radii. Here is a table of equivalences... 8161ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:1" => "Diamond", "Octagon:1", or "Cross:1" 8171ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:1.5" => "Square" 8181ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2" => "Diamond:2" 8191ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2.5" => "Octagon" 8201ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2.9" => "Square:2" 8210bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% "Disk:3.5" => "Octagon:3" 8221ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:4.5" => "Octagon:4" 8231ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:5.4" => "Octagon:5" 8241ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:6.4" => "Octagon:6" 8251ef941fea2534a0d20ba7d71307d35040247decbanthony% All other Disk shapes are unique to this kernel, but because a "Disk" 8261ef941fea2534a0d20ba7d71307d35040247decbanthony% is more circular when using a larger radius, using a larger radius is 8271ef941fea2534a0d20ba7d71307d35040247decbanthony% preferred over iterating the morphological operation. 828602ab9b30b644a78a4057da93d838a77391ec0acanthony% 829a9892d898acb81e1ec73106d892855fdc5a69427anthony% Rectangle:{geometry} 830a9892d898acb81e1ec73106d892855fdc5a69427anthony% Simply generate a rectangle of 1's with the size given. You can also 831a9892d898acb81e1ec73106d892855fdc5a69427anthony% specify the location of the 'control point', otherwise the closest 832a9892d898acb81e1ec73106d892855fdc5a69427anthony% pixel to the center of the rectangle is selected. 833a9892d898acb81e1ec73106d892855fdc5a69427anthony% 834a9892d898acb81e1ec73106d892855fdc5a69427anthony% Properly centered and odd sized rectangles work the best. 835a9892d898acb81e1ec73106d892855fdc5a69427anthony% 836c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Symbol Dilation Kernels 837c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 838c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% These kernel is not a good general morphological kernel, but is used 839c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% more for highlighting and marking any single pixels in an image using, 840c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a "Dilate" method as appropriate. 841c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 842c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% For the same reasons iterating these kernels does not produce the 843c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% same result as using a larger radius for the symbol. 844c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 8453c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Plus:[{radius}[,{scale}]] 8463dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Cross:[{radius}[,{scale}]] 847c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Generate a kernel in the shape of a 'plus' or a 'cross' with 848c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a each arm the length of the given radius (default 2). 8493dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% 850f0a92fd8deb68d411304359906b12679b675691fglennrp% NOTE: "plus:1" is equivalent to a "Diamond" kernel. 851602ab9b30b644a78a4057da93d838a77391ec0acanthony% 852c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Ring:{radius1},{radius2}[,{scale}] 853c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% A ring of the values given that falls between the two radii. 854c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Defaults to a ring of approximataly 3 radius in a 7x7 kernel. 855c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% This is the 'edge' pixels of the default "Disk" kernel, 856c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% More specifically, "Ring" -> "Ring:2.5,3.5,1.0" 8573dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% 8583dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Hit and Miss Kernels 859602ab9b30b644a78a4057da93d838a77391ec0acanthony% 8603dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Peak:radius1,radius2 861c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Find any peak larger than the pixels the fall between the two radii. 862c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The default ring of pixels is as per "Ring". 86343c4925e5305a26e48d68f7893e94f55d0831c39anthony% Edges 864694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find flat orthogonal edges of a binary shape 8653dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Corners 866694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find 90 degree corners of a binary shape 867529482f4b494010a13338a74446c510712f670b3anthony% Diagonals:type 868529482f4b494010a13338a74446c510712f670b3anthony% A special kernel to thin the 'outside' of diagonals 869694934fa79dd310f727588b1d0a7481fa6170f1danthony% LineEnds:type 8703dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Find end points of lines (for pruning a skeletion) 871694934fa79dd310f727588b1d0a7481fa6170f1danthony% Two types of lines ends (default to both) can be searched for 872694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 0: All line ends 873694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: single kernel for 4-conneected line ends 874694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: single kernel for simple line ends 8753dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% LineJunctions 87643c4925e5305a26e48d68f7893e94f55d0831c39anthony% Find three line junctions (within a skeletion) 877694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 0: all line junctions 878694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Y Junction kernel 879694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: Diagonal T Junction kernel 880694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 3: Orthogonal T Junction kernel 881694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 4: Diagonal X Junction kernel 882694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 5: Orthogonal + Junction kernel 883694934fa79dd310f727588b1d0a7481fa6170f1danthony% Ridges:type 884694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find single pixel ridges or thin lines 885694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Fine single pixel thick lines and ridges 886694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: Find two pixel thick lines and ridges 8873dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% ConvexHull 888a9892d898acb81e1ec73106d892855fdc5a69427anthony% Octagonal Thickening Kernel, to generate convex hulls of 45 degrees 889c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Skeleton:type 890c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Traditional skeleton generating kernels. 891694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Tradional Skeleton kernel (4 connected skeleton) 892694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: HIPR2 Skeleton kernel (8 connected skeleton) 893e816a586a13717bab2d6839ced6e5c3828a37f19anthony% Type 3: Thinning skeleton based on a ressearch paper by 8942b2290b46c246ce1f14cb78f1695394e4c4a3ddfanthony% Dan S. Bloomberg (Default Type) 895e816a586a13717bab2d6839ced6e5c3828a37f19anthony% ThinSE:type 896e816a586a13717bab2d6839ced6e5c3828a37f19anthony% A huge variety of Thinning Kernels designed to preserve conectivity. 897e816a586a13717bab2d6839ced6e5c3828a37f19anthony% many other kernel sets use these kernels as source definitions. 898e816a586a13717bab2d6839ced6e5c3828a37f19anthony% Type numbers are 41-49, 81-89, 481, and 482 which are based on 899e816a586a13717bab2d6839ced6e5c3828a37f19anthony% the super and sub notations used in the source research paper. 900602ab9b30b644a78a4057da93d838a77391ec0acanthony% 901602ab9b30b644a78a4057da93d838a77391ec0acanthony% Distance Measuring Kernels 902602ab9b30b644a78a4057da93d838a77391ec0acanthony% 903c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Different types of distance measuring methods, which are used with the 904c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a 'Distance' morphology method for generating a gradient based on 905c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% distance from an edge of a binary shape, though there is a technique 906c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% for handling a anti-aliased shape. 907602ab9b30b644a78a4057da93d838a77391ec0acanthony% 908c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% See the 'Distance' Morphological Method, for information of how it is 909c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% applied. 910602ab9b30b644a78a4057da93d838a77391ec0acanthony% 911c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Chebyshev:[{radius}][x{scale}[%!]] 9121ef941fea2534a0d20ba7d71307d35040247decbanthony% Chebyshev Distance (also known as Tchebychev or Chessboard distance) 9131ef941fea2534a0d20ba7d71307d35040247decbanthony% is a value of one to any neighbour, orthogonal or diagonal. One why 9141ef941fea2534a0d20ba7d71307d35040247decbanthony% of thinking of it is the number of squares a 'King' or 'Queen' in 9151ef941fea2534a0d20ba7d71307d35040247decbanthony% chess needs to traverse reach any other position on a chess board. 9161ef941fea2534a0d20ba7d71307d35040247decbanthony% It results in a 'square' like distance function, but one where 9171ef941fea2534a0d20ba7d71307d35040247decbanthony% diagonals are given a value that is closer than expected. 918c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 919bee715c4c0fd9efe6e21d8627ae8664434df7750anthony% Manhattan:[{radius}][x{scale}[%!]] 9201ef941fea2534a0d20ba7d71307d35040247decbanthony% Manhattan Distance (also known as Rectilinear, City Block, or the Taxi 9211ef941fea2534a0d20ba7d71307d35040247decbanthony% Cab distance metric), it is the distance needed when you can only 9221ef941fea2534a0d20ba7d71307d35040247decbanthony% travel in horizontal or vertical directions only. It is the 9231ef941fea2534a0d20ba7d71307d35040247decbanthony% distance a 'Rook' in chess would have to travel, and results in a 9241ef941fea2534a0d20ba7d71307d35040247decbanthony% diamond like distances, where diagonals are further than expected. 9251ef941fea2534a0d20ba7d71307d35040247decbanthony% 9261ef941fea2534a0d20ba7d71307d35040247decbanthony% Octagonal:[{radius}][x{scale}[%!]] 9271ef941fea2534a0d20ba7d71307d35040247decbanthony% An interleving of Manhatten and Chebyshev metrics producing an 9281ef941fea2534a0d20ba7d71307d35040247decbanthony% increasing octagonally shaped distance. Distances matches those of 9291ef941fea2534a0d20ba7d71307d35040247decbanthony% the "Octagon" shaped kernel of the same radius. The minimum radius 9301ef941fea2534a0d20ba7d71307d35040247decbanthony% and default is 2, producing a 5x5 kernel. 931c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 932c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Euclidean:[{radius}][x{scale}[%!]] 9331ef941fea2534a0d20ba7d71307d35040247decbanthony% Euclidean distance is the 'direct' or 'as the crow flys' distance. 934c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% However by default the kernel size only has a radius of 1, which 935c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% limits the distance to 'Knight' like moves, with only orthogonal and 936c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% diagonal measurements being correct. As such for the default kernel 9371ef941fea2534a0d20ba7d71307d35040247decbanthony% you will get octagonal like distance function. 9381ef941fea2534a0d20ba7d71307d35040247decbanthony% 9391ef941fea2534a0d20ba7d71307d35040247decbanthony% However using a larger radius such as "Euclidean:4" you will get a 9401ef941fea2534a0d20ba7d71307d35040247decbanthony% much smoother distance gradient from the edge of the shape. Especially 9411ef941fea2534a0d20ba7d71307d35040247decbanthony% if the image is pre-processed to include any anti-aliasing pixels. 9421ef941fea2534a0d20ba7d71307d35040247decbanthony% Of course a larger kernel is slower to use, and not always needed. 9431ef941fea2534a0d20ba7d71307d35040247decbanthony% 9441ef941fea2534a0d20ba7d71307d35040247decbanthony% The first three Distance Measuring Kernels will only generate distances 9451ef941fea2534a0d20ba7d71307d35040247decbanthony% of exact multiples of {scale} in binary images. As such you can use a 9461ef941fea2534a0d20ba7d71307d35040247decbanthony% scale of 1 without loosing any information. However you also need some 9471ef941fea2534a0d20ba7d71307d35040247decbanthony% scaling when handling non-binary anti-aliased shapes. 9481ef941fea2534a0d20ba7d71307d35040247decbanthony% 9491ef941fea2534a0d20ba7d71307d35040247decbanthony% The "Euclidean" Distance Kernel however does generate a non-integer 9501ef941fea2534a0d20ba7d71307d35040247decbanthony% fractional results, and as such scaling is vital even for binary shapes. 951c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 952602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 953602ab9b30b644a78a4057da93d838a77391ec0acanthony 9542be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristyMagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type, 955602ab9b30b644a78a4057da93d838a77391ec0acanthony const GeometryInfo *args) 956602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 9572be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy KernelInfo 958602ab9b30b644a78a4057da93d838a77391ec0acanthony *kernel; 959602ab9b30b644a78a4057da93d838a77391ec0acanthony 960bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 961602ab9b30b644a78a4057da93d838a77391ec0acanthony i; 962602ab9b30b644a78a4057da93d838a77391ec0acanthony 963bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 964602ab9b30b644a78a4057da93d838a77391ec0acanthony u, 965602ab9b30b644a78a4057da93d838a77391ec0acanthony v; 966602ab9b30b644a78a4057da93d838a77391ec0acanthony 967602ab9b30b644a78a4057da93d838a77391ec0acanthony double 968602ab9b30b644a78a4057da93d838a77391ec0acanthony nan = sqrt((double)-1.0); /* Special Value : Not A Number */ 969602ab9b30b644a78a4057da93d838a77391ec0acanthony 970c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Generate a new empty kernel if needed */ 971e96405a0f45f803fb9c26f75e7bdee252437febbcristy kernel=(KernelInfo *) NULL; 972c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony switch(type) { 9731dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case UndefinedKernel: /* These should not call this function */ 9749eb4f74649b23c053b308ce1152dce51239450baanthony case UserDefinedKernel: 975529482f4b494010a13338a74446c510712f670b3anthony assert("Should not call this function" != (char *)NULL); 9769eb4f74649b23c053b308ce1152dce51239450baanthony break; 977529482f4b494010a13338a74446c510712f670b3anthony case LaplacianKernel: /* Named Descrete Convolution Kernels */ 978529482f4b494010a13338a74446c510712f670b3anthony case SobelKernel: /* these are defined using other kernels */ 9799eb4f74649b23c053b308ce1152dce51239450baanthony case RobertsKernel: 9809eb4f74649b23c053b308ce1152dce51239450baanthony case PrewittKernel: 9819eb4f74649b23c053b308ce1152dce51239450baanthony case CompassKernel: 9829eb4f74649b23c053b308ce1152dce51239450baanthony case KirschKernel: 9831dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case FreiChenKernel: 984694934fa79dd310f727588b1d0a7481fa6170f1danthony case EdgesKernel: /* Hit and Miss kernels */ 985694934fa79dd310f727588b1d0a7481fa6170f1danthony case CornersKernel: 986529482f4b494010a13338a74446c510712f670b3anthony case DiagonalsKernel: 9879eb4f74649b23c053b308ce1152dce51239450baanthony case LineEndsKernel: 9889eb4f74649b23c053b308ce1152dce51239450baanthony case LineJunctionsKernel: 9891dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case RidgesKernel: 9909eb4f74649b23c053b308ce1152dce51239450baanthony case ConvexHullKernel: 9919eb4f74649b23c053b308ce1152dce51239450baanthony case SkeletonKernel: 9929a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case ThinSEKernel: 993c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; /* A pre-generated kernel is not needed */ 994c40ac1e79923a1516075ba1197ae4ed90244af9banthony#if 0 995c40ac1e79923a1516075ba1197ae4ed90244af9banthony /* set to 1 to do a compile-time check that we haven't missed anything */ 996529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 997c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case GaussianKernel: 998501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 999501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 1000c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case BlurKernel: 1001c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CometKernel: 100240ca0b982379d4ab2716435a46603d56b5b218b1anthony case BinomialKernel: 1003c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiamondKernel: 1004c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SquareKernel: 1005c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RectangleKernel: 10061ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 1007c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiskKernel: 1008c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PlusKernel: 1009c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CrossKernel: 1010c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RingKernel: 1011c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PeaksKernel: 1012c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case ChebyshevKernel: 1013bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 10141ef941fea2534a0d20ba7d71307d35040247decbanthony case OctangonalKernel: 1015c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case EuclideanKernel: 10161dd091ae3bc17edc26c16cc47f436a24bd48412aanthony#else 10179eb4f74649b23c053b308ce1152dce51239450baanthony default: 10181dd091ae3bc17edc26c16cc47f436a24bd48412aanthony#endif 10199eb4f74649b23c053b308ce1152dce51239450baanthony /* Generate the base Kernel Structure */ 1020c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel)); 1021c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1022c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1023c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony (void) ResetMagickMemory(kernel,0,sizeof(*kernel)); 102443c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->minimum = kernel->maximum = kernel->angle = 0.0; 1025c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->negative_range = kernel->positive_range = 0.0; 1026c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 1027c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->next = (KernelInfo *) NULL; 1028c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->signature = MagickSignature; 1029c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1030c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1031602ab9b30b644a78a4057da93d838a77391ec0acanthony 1032602ab9b30b644a78a4057da93d838a77391ec0acanthony switch(type) { 1033529482f4b494010a13338a74446c510712f670b3anthony /* 1034529482f4b494010a13338a74446c510712f670b3anthony Convolution Kernels 1035529482f4b494010a13338a74446c510712f670b3anthony */ 1036529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 1037529482f4b494010a13338a74446c510712f670b3anthony { 1038529482f4b494010a13338a74446c510712f670b3anthony kernel->height = kernel->width = (size_t) 1; 1039529482f4b494010a13338a74446c510712f670b3anthony kernel->x = kernel->y = (ssize_t) 0; 1040e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1041e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(1,sizeof(*kernel->values))); 1042d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 1043529482f4b494010a13338a74446c510712f670b3anthony return(DestroyKernelInfo(kernel)); 1044529482f4b494010a13338a74446c510712f670b3anthony kernel->maximum = kernel->values[0] = args->rho; 1045529482f4b494010a13338a74446c510712f670b3anthony break; 1046529482f4b494010a13338a74446c510712f670b3anthony } 1047529482f4b494010a13338a74446c510712f670b3anthony break; 1048602ab9b30b644a78a4057da93d838a77391ec0acanthony case GaussianKernel: 1049501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 1050501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 1051602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 1052c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma = fabs(args->sigma), 1053c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma2 = fabs(args->xi), 10549eb4f74649b23c053b308ce1152dce51239450baanthony A, B, R; 1055c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1056c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( args->rho >= 1.0 ) 1057bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho*2+1; 1058501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony else if ( (type != DoGKernel) || (sigma >= sigma2) ) 1059c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = GetOptimalKernelWidth2D(args->rho,sigma); 1060c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1061c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2); 1062c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->height = kernel->width; 1063bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 1064e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1065e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1066e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1067d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 106883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1069602ab9b30b644a78a4057da93d838a77391ec0acanthony 107046a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* WARNING: The following generates a 'sampled gaussian' kernel. 10719eb4f74649b23c053b308ce1152dce51239450baanthony * What we really want is a 'discrete gaussian' kernel. 107246a369d839971ab627bdb31a93d8bd63e81b65a3anthony * 1073529482f4b494010a13338a74446c510712f670b3anthony * How to do this is I don't know, but appears to be basied on the 1074529482f4b494010a13338a74446c510712f670b3anthony * Error Function 'erf()' (intergral of a gaussian) 10759eb4f74649b23c053b308ce1152dce51239450baanthony */ 10769eb4f74649b23c053b308ce1152dce51239450baanthony 1077501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == GaussianKernel || type == DoGKernel ) 1078501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony { /* Calculate a Gaussian, OR positive half of a DoG */ 10799eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 10809eb4f74649b23c053b308ce1152dce51239450baanthony { A = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 108155a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(Magick2PI*sigma*sigma)); 1082bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1083bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 10849eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] = exp(-((double)(u*u+v*v))*A)*B; 10859eb4f74649b23c053b308ce1152dce51239450baanthony } 10869eb4f74649b23c053b308ce1152dce51239450baanthony else /* limiting case - a unity (normalized Dirac) kernel */ 10879eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 108875920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*kernel->height*sizeof(*kernel->values)); 10899eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 10909eb4f74649b23c053b308ce1152dce51239450baanthony } 1091c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 10929eb4f74649b23c053b308ce1152dce51239450baanthony 1093501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == DoGKernel ) 1094c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { /* Subtract a Negative Gaussian for "Difference of Gaussian" */ 1095c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma2 > MagickEpsilon ) 1096c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { sigma = sigma2; /* simplify loop expressions */ 10979eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); 109855a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(Magick2PI*sigma*sigma)); 1099bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1100bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 11019eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] -= exp(-((double)(u*u+v*v))*A)*B; 1102c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 11039eb4f74649b23c053b308ce1152dce51239450baanthony else /* limiting case - a unity (normalized Dirac) kernel */ 1104c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] -= 1.0; 1105c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 11069eb4f74649b23c053b308ce1152dce51239450baanthony 1107501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == LoGKernel ) 11089eb4f74649b23c053b308ce1152dce51239450baanthony { /* Calculate a Laplacian of a Gaussian - Or Mexician Hat */ 11099eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 11109eb4f74649b23c053b308ce1152dce51239450baanthony { A = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 111155a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(MagickPI*sigma*sigma*sigma*sigma)); 1112bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1113bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 11149eb4f74649b23c053b308ce1152dce51239450baanthony { R = ((double)(u*u+v*v))*A; 11159eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] = (1-R)*exp(-R)*B; 11169eb4f74649b23c053b308ce1152dce51239450baanthony } 11179eb4f74649b23c053b308ce1152dce51239450baanthony } 11189eb4f74649b23c053b308ce1152dce51239450baanthony else /* special case - generate a unity kernel */ 11199eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 112075920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*kernel->height*sizeof(*kernel->values)); 11219eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 11229eb4f74649b23c053b308ce1152dce51239450baanthony } 11239eb4f74649b23c053b308ce1152dce51239450baanthony } 11249eb4f74649b23c053b308ce1152dce51239450baanthony 11259eb4f74649b23c053b308ce1152dce51239450baanthony /* Note the above kernels may have been 'clipped' by a user defined 1126c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** radius, producing a smaller (darker) kernel. Also for very small 1127c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** sigma's (> 0.1) the central value becomes larger than one, and thus 1128c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** producing a very bright kernel. 1129c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 1130c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** Normalization will still be needed. 1131c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony */ 1132602ab9b30b644a78a4057da93d838a77391ec0acanthony 11333dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* Normalize the 2D Gaussian Kernel 11343dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** 1135c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** NB: a CorrelateNormalize performs a normal Normalize if 1136c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there are no negative values. 11373dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony */ 113846a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* the other kernel meta-data */ 1139c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue); 1140602ab9b30b644a78a4057da93d838a77391ec0acanthony 1141602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1142602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1143602ab9b30b644a78a4057da93d838a77391ec0acanthony case BlurKernel: 1144602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 1145c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma = fabs(args->sigma), 1146501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony alpha, beta; 1147602ab9b30b644a78a4057da93d838a77391ec0acanthony 1148c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( args->rho >= 1.0 ) 1149bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho*2+1; 1150c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1151501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->width = GetOptimalKernelWidth1D(args->rho,sigma); 1152602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height = 1; 1153bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) (kernel->width-1)/2; 1154c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->y = 0; 1155c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 1156e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1157e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1158e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1159d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 116083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1161602ab9b30b644a78a4057da93d838a77391ec0acanthony 1162602ab9b30b644a78a4057da93d838a77391ec0acanthony#if 1 1163602ab9b30b644a78a4057da93d838a77391ec0acanthony#define KernelRank 3 1164602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Formula derived from GetBlurKernel() in "effect.c" (plus bug fix). 1165602ab9b30b644a78a4057da93d838a77391ec0acanthony ** It generates a gaussian 3 times the width, and compresses it into 1166602ab9b30b644a78a4057da93d838a77391ec0acanthony ** the expected range. This produces a closer normalization of the 1167602ab9b30b644a78a4057da93d838a77391ec0acanthony ** resulting kernel, especially for very low sigma values. 1168602ab9b30b644a78a4057da93d838a77391ec0acanthony ** As such while wierd it is prefered. 1169602ab9b30b644a78a4057da93d838a77391ec0acanthony ** 1170602ab9b30b644a78a4057da93d838a77391ec0acanthony ** I am told this method originally came from Photoshop. 11719eb4f74649b23c053b308ce1152dce51239450baanthony ** 11729eb4f74649b23c053b308ce1152dce51239450baanthony ** A properly normalized curve is generated (apart from edge clipping) 11739eb4f74649b23c053b308ce1152dce51239450baanthony ** even though we later normalize the result (for edge clipping) 11749eb4f74649b23c053b308ce1152dce51239450baanthony ** to allow the correct generation of a "Difference of Blurs". 1175602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 1176c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1177c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* initialize */ 1178bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy v = (ssize_t) (kernel->width*KernelRank-1)/2; /* start/end points to fit range */ 11799eb4f74649b23c053b308ce1152dce51239450baanthony (void) ResetMagickMemory(kernel->values,0, (size_t) 118075920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*kernel->height*sizeof(*kernel->values)); 1181c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Calculate a Positive 1D Gaussian */ 1182c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma > MagickEpsilon ) 1183c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { sigma *= KernelRank; /* simplify loop expressions */ 1184501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony alpha = 1.0/(2.0*sigma*sigma); 118555a91cddcdea3aa002893186a773e1704884a9dfcristy beta= (double) (1.0/(MagickSQ2PI*sigma )); 1186c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony for ( u=-v; u <= v; u++) { 1187501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[(u+v)/KernelRank] += 1188501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony exp(-((double)(u*u))*alpha)*beta; 1189c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1190c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1191c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else /* special case - generate a unity kernel */ 1192c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 1193602ab9b30b644a78a4057da93d838a77391ec0acanthony#else 119453f576d128f0bb744a82e7f9c0d8f05b2923972canthony /* Direct calculation without curve averaging 119553f576d128f0bb744a82e7f9c0d8f05b2923972canthony This is equivelent to a KernelRank of 1 */ 1196c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1197c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Calculate a Positive Gaussian */ 1198c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma > MagickEpsilon ) 1199501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony { alpha = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 1200501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony beta = 1.0/(MagickSQ2PI*sigma); 1201bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 1202501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[i] = exp(-((double)(u*u))*alpha)*beta; 1203c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1204c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else /* special case - generate a unity kernel */ 1205c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 120675920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*kernel->height*sizeof(*kernel->values)); 1207c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 1208c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1209602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 1210c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Note the above kernel may have been 'clipped' by a user defined 1211cc6c836da2a53b6023b716e4973090a6714dc3b0anthony ** radius, producing a smaller (darker) kernel. Also for very small 121253f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** sigma's (> 0.1) the central value becomes larger than one, as a 121353f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** result of not generating a actual 'discrete' kernel, and thus 121453f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** producing a very bright 'impulse'. 1215c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 121653f576d128f0bb744a82e7f9c0d8f05b2923972canthony ** Becuase of these two factors Normalization is required! 1217602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 1218cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 1219602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Normalize the 1D Gaussian Kernel 1220602ab9b30b644a78a4057da93d838a77391ec0acanthony ** 1221c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** NB: a CorrelateNormalize performs a normal Normalize if 1222c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there are no negative values. 1223602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 122446a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* the other kernel meta-data */ 122546a369d839971ab627bdb31a93d8bd63e81b65a3anthony ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue); 1226cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 1227c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* rotate the 1D kernel by given angle */ 1228501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony RotateKernelInfo(kernel, args->xi ); 1229602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1230602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1231602ab9b30b644a78a4057da93d838a77391ec0acanthony case CometKernel: 1232602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 12339eb4f74649b23c053b308ce1152dce51239450baanthony sigma = fabs(args->sigma), 12349eb4f74649b23c053b308ce1152dce51239450baanthony A; 1235602ab9b30b644a78a4057da93d838a77391ec0acanthony 1236602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->rho < 1.0 ) 1237e1cf9465864144e8b8043d522906c1e47bbf6192anthony kernel->width = (GetOptimalKernelWidth1D(args->rho,sigma)-1)/2+1; 1238602ab9b30b644a78a4057da93d838a77391ec0acanthony else 1239bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho; 1240c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->x = kernel->y = 0; 1241602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height = 1; 1242c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 1243e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1244e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1245e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1246d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 124783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1248602ab9b30b644a78a4057da93d838a77391ec0acanthony 1249c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* A comet blur is half a 1D gaussian curve, so that the object is 1250602ab9b30b644a78a4057da93d838a77391ec0acanthony ** blurred in one direction only. This may not be quite the right 12513dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** curve to use so may change in the future. The function must be 12523dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** normalised after generation, which also resolves any clipping. 1253c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 1254c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** As we are normalizing and not subtracting gaussians, 1255c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there is no need for a divisor in the gaussian formula 1256c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 125743c4925e5305a26e48d68f7893e94f55d0831c39anthony ** It is less comples 1258602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 12599eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 12609eb4f74649b23c053b308ce1152dce51239450baanthony { 1261602ab9b30b644a78a4057da93d838a77391ec0acanthony#if 1 1262602ab9b30b644a78a4057da93d838a77391ec0acanthony#define KernelRank 3 1263bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy v = (ssize_t) kernel->width*KernelRank; /* start/end points */ 12649eb4f74649b23c053b308ce1152dce51239450baanthony (void) ResetMagickMemory(kernel->values,0, (size_t) 126575920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*sizeof(*kernel->values)); 12669eb4f74649b23c053b308ce1152dce51239450baanthony sigma *= KernelRank; /* simplify the loop expression */ 12679eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); 12689eb4f74649b23c053b308ce1152dce51239450baanthony /* B = 1.0/(MagickSQ2PI*sigma); */ 12699eb4f74649b23c053b308ce1152dce51239450baanthony for ( u=0; u < v; u++) { 12709eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[u/KernelRank] += 12719eb4f74649b23c053b308ce1152dce51239450baanthony exp(-((double)(u*u))*A); 12729eb4f74649b23c053b308ce1152dce51239450baanthony /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */ 12739eb4f74649b23c053b308ce1152dce51239450baanthony } 1274bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) kernel->width; i++) 12759eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range += kernel->values[i]; 1276602ab9b30b644a78a4057da93d838a77391ec0acanthony#else 12779eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); /* simplify the loop expression */ 12789eb4f74649b23c053b308ce1152dce51239450baanthony /* B = 1.0/(MagickSQ2PI*sigma); */ 1279bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0; i < (ssize_t) kernel->width; i++) 12809eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range += 128153f576d128f0bb744a82e7f9c0d8f05b2923972canthony kernel->values[i] = exp(-((double)(i*i))*A); 12829eb4f74649b23c053b308ce1152dce51239450baanthony /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */ 1283602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 12849eb4f74649b23c053b308ce1152dce51239450baanthony } 12859eb4f74649b23c053b308ce1152dce51239450baanthony else /* special case - generate a unity kernel */ 12869eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 128775920b23a8a3883792cbb69d569c33cc789cf1b5cristy kernel->width*kernel->height*sizeof(*kernel->values)); 12889eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 12899eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range = 1.0; 12909eb4f74649b23c053b308ce1152dce51239450baanthony } 129146a369d839971ab627bdb31a93d8bd63e81b65a3anthony 129246a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->minimum = 0.0; 1293c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 129446a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->negative_range = 0.0; 1295602ab9b30b644a78a4057da93d838a77391ec0acanthony 1296999bb2c20aa9d42875bb5adba44951988d4ae354anthony ScaleKernelInfo(kernel, 1.0, NormalizeValue); /* Normalize */ 1297999bb2c20aa9d42875bb5adba44951988d4ae354anthony RotateKernelInfo(kernel, args->xi); /* Rotate by angle */ 1298602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1299602ab9b30b644a78a4057da93d838a77391ec0acanthony } 130040ca0b982379d4ab2716435a46603d56b5b218b1anthony case BinomialKernel: 130140ca0b982379d4ab2716435a46603d56b5b218b1anthony { 130240ca0b982379d4ab2716435a46603d56b5b218b1anthony size_t 130340ca0b982379d4ab2716435a46603d56b5b218b1anthony order_f; 130440ca0b982379d4ab2716435a46603d56b5b218b1anthony 130540ca0b982379d4ab2716435a46603d56b5b218b1anthony if (args->rho < 1.0) 130640ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->width = kernel->height = 3; /* default radius = 1 */ 130740ca0b982379d4ab2716435a46603d56b5b218b1anthony else 130840ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 130940ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 131040ca0b982379d4ab2716435a46603d56b5b218b1anthony 131140ca0b982379d4ab2716435a46603d56b5b218b1anthony order_f = fact(kernel->width-1); 131240ca0b982379d4ab2716435a46603d56b5b218b1anthony 1313e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1314e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1315e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1316d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 131740ca0b982379d4ab2716435a46603d56b5b218b1anthony return(DestroyKernelInfo(kernel)); 131840ca0b982379d4ab2716435a46603d56b5b218b1anthony 131940ca0b982379d4ab2716435a46603d56b5b218b1anthony /* set all kernel values within diamond area to scale given */ 132040ca0b982379d4ab2716435a46603d56b5b218b1anthony for ( i=0, v=0; v < (ssize_t)kernel->height; v++) 132140ca0b982379d4ab2716435a46603d56b5b218b1anthony { size_t 1322f13c594b1d9509e479fd845c3b8a5bb1351c32eacristy alpha = order_f / ( fact((size_t) v) * fact(kernel->height-v-1) ); 132340ca0b982379d4ab2716435a46603d56b5b218b1anthony for ( u=0; u < (ssize_t)kernel->width; u++, i++) 132440ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->positive_range += kernel->values[i] = (double) 1325f13c594b1d9509e479fd845c3b8a5bb1351c32eacristy (alpha * order_f / ( fact((size_t) u) * fact(kernel->height-u-1) )); 132640ca0b982379d4ab2716435a46603d56b5b218b1anthony } 132740ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->minimum = 1.0; 132840ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->maximum = kernel->values[kernel->x+kernel->y*kernel->width]; 132940ca0b982379d4ab2716435a46603d56b5b218b1anthony kernel->negative_range = 0.0; 133040ca0b982379d4ab2716435a46603d56b5b218b1anthony break; 133140ca0b982379d4ab2716435a46603d56b5b218b1anthony } 1332c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1333529482f4b494010a13338a74446c510712f670b3anthony /* 1334529482f4b494010a13338a74446c510712f670b3anthony Convolution Kernels - Well Known Named Constant Kernels 1335529482f4b494010a13338a74446c510712f670b3anthony */ 13363c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony case LaplacianKernel: 1337e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony { switch ( (int) args->rho ) { 13383dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case 0: 13399eb4f74649b23c053b308ce1152dce51239450baanthony default: /* laplacian square filter -- default */ 1340c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: -1,-1,-1 -1,8,-1 -1,-1,-1"); 13413dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony break; 13429eb4f74649b23c053b308ce1152dce51239450baanthony case 1: /* laplacian diamond filter */ 1343c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: 0,-1,0 -1,4,-1 0,-1,0"); 13443c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13453c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony case 2: 13469eb4f74649b23c053b308ce1152dce51239450baanthony kernel=ParseKernelArray("3: -2,1,-2 1,4,1 -2,1,-2"); 13479eb4f74649b23c053b308ce1152dce51239450baanthony break; 13489eb4f74649b23c053b308ce1152dce51239450baanthony case 3: 1349c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: 1,-2,1 -2,4,-2 1,-2,1"); 13503c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13519eb4f74649b23c053b308ce1152dce51239450baanthony case 5: /* a 5x5 laplacian */ 13523c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel=ParseKernelArray( 13539eb4f74649b23c053b308ce1152dce51239450baanthony "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"); 13543c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13559eb4f74649b23c053b308ce1152dce51239450baanthony case 7: /* a 7x7 laplacian */ 13563c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel=ParseKernelArray( 1357c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony "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" ); 13583c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 1359501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case 15: /* a 5x5 LoG (sigma approx 1.4) */ 13609eb4f74649b23c053b308ce1152dce51239450baanthony kernel=ParseKernelArray( 13619eb4f74649b23c053b308ce1152dce51239450baanthony "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"); 13629eb4f74649b23c053b308ce1152dce51239450baanthony break; 1363501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case 19: /* a 9x9 LoG (sigma approx 1.4) */ 136443c4925e5305a26e48d68f7893e94f55d0831c39anthony /* http://www.cscjournals.org/csc/manuscript/Journals/IJIP/volume3/Issue1/IJIP-15.pdf */ 136543c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel=ParseKernelArray( 1366bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony "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"); 136743c4925e5305a26e48d68f7893e94f55d0831c39anthony break; 13683c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 13693c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if (kernel == (KernelInfo *) NULL) 13703c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony return(kernel); 13713c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->type = type; 13723c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13733c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 1374c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SobelKernel: 1375cceb6f05c2016ea3854b29e7770ec5ff49034ecfanthony { /* Simple Sobel Kernel */ 1376dcc2a474c98415e565434fe52f630acba36fa0c1anthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1377dcc2a474c98415e565434fe52f630acba36fa0c1anthony if (kernel == (KernelInfo *) NULL) 1378dcc2a474c98415e565434fe52f630acba36fa0c1anthony return(kernel); 1379dcc2a474c98415e565434fe52f630acba36fa0c1anthony kernel->type = type; 1380dcc2a474c98415e565434fe52f630acba36fa0c1anthony RotateKernelInfo(kernel, args->rho); 1381dcc2a474c98415e565434fe52f630acba36fa0c1anthony break; 1382dcc2a474c98415e565434fe52f630acba36fa0c1anthony } 1383c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RobertsKernel: 1384c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1385501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 0,0,0 1,-1,0 0,0,0"); 1386c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1387c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1388c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 138946a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1390c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1391c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1392c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PrewittKernel: 1393c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1394501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 1,0,-1 1,0,-1"); 1395c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1396c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1397c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 139846a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1399c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1400c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1401c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CompassKernel: 1402c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1403501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,1,-1 1,-2,-1 1,1,-1"); 1404c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1405c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1406c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 140746a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1408c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1409c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 14109eb4f74649b23c053b308ce1152dce51239450baanthony case KirschKernel: 14119eb4f74649b23c053b308ce1152dce51239450baanthony { 1412501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 5,-3,-3 5,0,-3 5,-3,-3"); 14139eb4f74649b23c053b308ce1152dce51239450baanthony if (kernel == (KernelInfo *) NULL) 14149eb4f74649b23c053b308ce1152dce51239450baanthony return(kernel); 14159eb4f74649b23c053b308ce1152dce51239450baanthony kernel->type = type; 141646a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 14179eb4f74649b23c053b308ce1152dce51239450baanthony break; 14189eb4f74649b23c053b308ce1152dce51239450baanthony } 1419e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony case FreiChenKernel: 1420501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* Direction is set to be left to right positive */ 1421501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf -- RIGHT? */ 1422501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf -- WRONG? */ 14231dd091ae3bc17edc26c16cc47f436a24bd48412aanthony { switch ( (int) args->rho ) { 1424e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony default: 1425c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony case 0: 1426501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1427c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony if (kernel == (KernelInfo *) NULL) 1428c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony return(kernel); 1429ef33d9f66f955c1f6f5f7105e164cc2d5c5e2a41anthony kernel->type = type; 1430d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[3] = +(MagickRealType) MagickSQ2; 1431d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[5] = -(MagickRealType) MagickSQ2; 1432c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 1433c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony break; 1434c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 2: 1435c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel=ParseKernelArray("3: 1,2,0 2,0,-2 0,-2,-1"); 1436c40ac1e79923a1516075ba1197ae4ed90244af9banthony if (kernel == (KernelInfo *) NULL) 1437c40ac1e79923a1516075ba1197ae4ed90244af9banthony return(kernel); 1438c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel->type = type; 1439d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[1] = kernel->values[3]= +(MagickRealType) MagickSQ2; 1440d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[5] = kernel->values[7]= -(MagickRealType) MagickSQ2; 1441c40ac1e79923a1516075ba1197ae4ed90244af9banthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 1442d4e3ffa7f64077da0f32c2d8a599737ee8d115ddcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1443c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; 1444c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 10: 1445c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel=AcquireKernelInfo("FreiChen:11;FreiChen:12;FreiChen:13;FreiChen:14;FreiChen:15;FreiChen:16;FreiChen:17;FreiChen:18;FreiChen:19"); 1446c40ac1e79923a1516075ba1197ae4ed90244af9banthony if (kernel == (KernelInfo *) NULL) 1447c40ac1e79923a1516075ba1197ae4ed90244af9banthony return(kernel); 1448c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; 1449e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony case 1: 1450c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 11: 1451501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1452e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1453e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1454c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1455d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[3] = +(MagickRealType) MagickSQ2; 1456d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[5] = -(MagickRealType) MagickSQ2; 1457e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 145855a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1459e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1460c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 12: 1461501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,2,1 0,0,0 1,2,1"); 1462e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1463e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1464c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1465d9123437a79f9d56a3e8c32aa912ae3ae1d47337cristy kernel->values[1] = +(MagickRealType) MagickSQ2; 1466d9123437a79f9d56a3e8c32aa912ae3ae1d47337cristy kernel->values[7] = +(MagickRealType) MagickSQ2; 1467e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 146855a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1469e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1470c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 13: 1471501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 2,-1,0 -1,0,1 0,1,-2"); 1472e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1473e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1474c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1475d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[0] = +(MagickRealType) MagickSQ2; 1476d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[8] = -(MagickRealType) MagickSQ2; 1477e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 147855a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1479e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1480c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 14: 14811d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel=ParseKernelArray("3: 0,1,-2 -1,0,1 2,-1,0"); 1482e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1483e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1484c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1485d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[2] = -(MagickRealType) MagickSQ2; 1486d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values[6] = +(MagickRealType) MagickSQ2; 1487e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 148855a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1489e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1490c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 15: 1491501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 0,-1,0 1,0,1 0,-1,0"); 1492e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1493e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1494c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1495e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/2.0, NoValue); 1496e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1497c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 16: 14981d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel=ParseKernelArray("3: 1,0,-1 0,0,0 -1,0,1"); 1499e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1500e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1501c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1502e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/2.0, NoValue); 1503e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1504c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 17: 1505501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,-2,1 -2,4,-2 -1,-2,1"); 1506e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1507e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1508c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1509e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/6.0, NoValue); 1510e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1511c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 18: 1512501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: -2,1,-2 1,4,1 -2,1,-2"); 1513e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1514e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1515c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1516e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/6.0, NoValue); 1517e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1518c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 19: 1519c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel=ParseKernelArray("3: 1,1,1 1,1,1 1,1,1"); 1520e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1521e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1522c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1523e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/3.0, NoValue); 1524e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1525e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony } 1526b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(args->sigma) >= MagickEpsilon ) 1527c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony /* Rotate by correctly supplied 'angle' */ 1528c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony RotateKernelInfo(kernel, args->sigma); 1529c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony else if ( args->rho > 30.0 || args->rho < -30.0 ) 1530c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony /* Rotate by out of bounds 'type' */ 1531c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony RotateKernelInfo(kernel, args->rho); 1532e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1533e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony } 1534e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony 1535529482f4b494010a13338a74446c510712f670b3anthony /* 1536529482f4b494010a13338a74446c510712f670b3anthony Boolean or Shaped Kernels 1537529482f4b494010a13338a74446c510712f670b3anthony */ 1538c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiamondKernel: 1539602ab9b30b644a78a4057da93d838a77391ec0acanthony { 1540c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (args->rho < 1.0) 1541c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = kernel->height = 3; /* default radius = 1 */ 1542c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1543bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = ((size_t)args->rho)*2+1; 1544bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 1545c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1546e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1547e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1548e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1549d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 1550c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(DestroyKernelInfo(kernel)); 1551c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1552c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* set all kernel values within diamond area to scale given */ 1553bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1554bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 15551d5e67090dc7232b35bfcc71b31266c20838defcanthony if ( (labs((long) u)+labs((long) v)) <= (long) kernel->x) 1556c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->positive_range += kernel->values[i] = args->sigma; 1557c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1558c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[i] = nan; 1559c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 1560c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1561c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1562c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SquareKernel: 1563c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RectangleKernel: 1564c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { double 1565c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony scale; 1566602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( type == SquareKernel ) 1567602ab9b30b644a78a4057da93d838a77391ec0acanthony { 1568602ab9b30b644a78a4057da93d838a77391ec0acanthony if (args->rho < 1.0) 1569c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 1570602ab9b30b644a78a4057da93d838a77391ec0acanthony else 1571bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = (size_t) (2*args->rho+1); 1572bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 15734fd27e21043be809d66c8202e779255e5b660d2danthony scale = args->sigma; 1574602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1575602ab9b30b644a78a4057da93d838a77391ec0acanthony else { 15762be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy /* NOTE: user defaults set in "AcquireKernelInfo()" */ 1577602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->rho < 1.0 || args->sigma < 1.0 ) 157883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); /* invalid args given */ 1579bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho; 1580bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t)args->sigma; 1581602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->xi < 0.0 || args->xi > (double)kernel->width || 1582602ab9b30b644a78a4057da93d838a77391ec0acanthony args->psi < 0.0 || args->psi > (double)kernel->height ) 158383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); /* invalid args given */ 1584bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) args->xi; 1585bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = (ssize_t) args->psi; 15864fd27e21043be809d66c8202e779255e5b660d2danthony scale = 1.0; 1587602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1588e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1589e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1590e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1591d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 159283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1593602ab9b30b644a78a4057da93d838a77391ec0acanthony 15943dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* set all kernel values to scale given */ 1595eaedf06777741da32408da72c1e512975c600c48cristy u=(ssize_t) (kernel->width*kernel->height); 1596150989ed67ef9da53141a65e5f3ebdb05dd025abcristy for ( i=0; i < u; i++) 15974fd27e21043be809d66c8202e779255e5b660d2danthony kernel->values[i] = scale; 15984fd27e21043be809d66c8202e779255e5b660d2danthony kernel->minimum = kernel->maximum = scale; /* a flat shape */ 15994fd27e21043be809d66c8202e779255e5b660d2danthony kernel->positive_range = scale*u; 1600cc6c836da2a53b6023b716e4973090a6714dc3b0anthony break; 1601602ab9b30b644a78a4057da93d838a77391ec0acanthony } 16021ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 16031ef941fea2534a0d20ba7d71307d35040247decbanthony { 16041ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 1605a9892d898acb81e1ec73106d892855fdc5a69427anthony kernel->width = kernel->height = 5; /* default radius = 2 */ 16061ef941fea2534a0d20ba7d71307d35040247decbanthony else 16071ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 16081ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16091ef941fea2534a0d20ba7d71307d35040247decbanthony 1610e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1611e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1612e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1613d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 16141ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16151ef941fea2534a0d20ba7d71307d35040247decbanthony 16161ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16171ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16181ef941fea2534a0d20ba7d71307d35040247decbanthony if ( (labs((long) u)+labs((long) v)) <= 16191ef941fea2534a0d20ba7d71307d35040247decbanthony ((long)kernel->x + (long)(kernel->x/2)) ) 16201ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = args->sigma; 16211ef941fea2534a0d20ba7d71307d35040247decbanthony else 16221ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = nan; 1623a9892d898acb81e1ec73106d892855fdc5a69427anthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16241ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16251ef941fea2534a0d20ba7d71307d35040247decbanthony } 16261ef941fea2534a0d20ba7d71307d35040247decbanthony case DiskKernel: 16271ef941fea2534a0d20ba7d71307d35040247decbanthony { 16281ef941fea2534a0d20ba7d71307d35040247decbanthony ssize_t 16290bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony limit = (ssize_t)(args->rho*args->rho); 16301ef941fea2534a0d20ba7d71307d35040247decbanthony 16319bf68d590429a72aa70894f6aea7fc3c94876e54anthony if (args->rho < 0.4) /* default radius approx 4.3 */ 16329bf68d590429a72aa70894f6aea7fc3c94876e54anthony kernel->width = kernel->height = 9L, limit = 18L; 16331ef941fea2534a0d20ba7d71307d35040247decbanthony else 16341ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = (size_t)fabs(args->rho)*2+1; 16351ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16361ef941fea2534a0d20ba7d71307d35040247decbanthony 1637e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1638e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1639e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1640d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 16411ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16421ef941fea2534a0d20ba7d71307d35040247decbanthony 16431ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16441ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16451ef941fea2534a0d20ba7d71307d35040247decbanthony if ((u*u+v*v) <= limit) 16461ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = args->sigma; 16473dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony else 16483dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony kernel->values[i] = nan; 16491ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16501ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16511ef941fea2534a0d20ba7d71307d35040247decbanthony } 16521ef941fea2534a0d20ba7d71307d35040247decbanthony case PlusKernel: 16531ef941fea2534a0d20ba7d71307d35040247decbanthony { 16541ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 16551ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default radius 2 */ 16561ef941fea2534a0d20ba7d71307d35040247decbanthony else 16571ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 16581ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16591ef941fea2534a0d20ba7d71307d35040247decbanthony 1660e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1661e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1662e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1663d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 16641ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16651ef941fea2534a0d20ba7d71307d35040247decbanthony 16661ef941fea2534a0d20ba7d71307d35040247decbanthony /* set all kernel values along axises to given scale */ 16671ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16681ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16691ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan; 16701ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16711ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0); 16721ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16731ef941fea2534a0d20ba7d71307d35040247decbanthony } 16741ef941fea2534a0d20ba7d71307d35040247decbanthony case CrossKernel: 16751ef941fea2534a0d20ba7d71307d35040247decbanthony { 16761ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 16771ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default radius 2 */ 16781ef941fea2534a0d20ba7d71307d35040247decbanthony else 16791ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 16801ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16811ef941fea2534a0d20ba7d71307d35040247decbanthony 1682e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1683e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1684e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1685d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 16861ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16871ef941fea2534a0d20ba7d71307d35040247decbanthony 16881ef941fea2534a0d20ba7d71307d35040247decbanthony /* set all kernel values along axises to given scale */ 16891ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16901ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16911ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = (u == v || u == -v) ? args->sigma : nan; 16921ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16931ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0); 16941ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16951ef941fea2534a0d20ba7d71307d35040247decbanthony } 1696529482f4b494010a13338a74446c510712f670b3anthony /* 1697529482f4b494010a13338a74446c510712f670b3anthony HitAndMiss Kernels 1698529482f4b494010a13338a74446c510712f670b3anthony */ 16991ef941fea2534a0d20ba7d71307d35040247decbanthony case RingKernel: 17001ef941fea2534a0d20ba7d71307d35040247decbanthony case PeaksKernel: 17011ef941fea2534a0d20ba7d71307d35040247decbanthony { 17021ef941fea2534a0d20ba7d71307d35040247decbanthony ssize_t 17031ef941fea2534a0d20ba7d71307d35040247decbanthony limit1, 17041ef941fea2534a0d20ba7d71307d35040247decbanthony limit2, 17051ef941fea2534a0d20ba7d71307d35040247decbanthony scale; 17061ef941fea2534a0d20ba7d71307d35040247decbanthony 17071ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < args->sigma) 17081ef941fea2534a0d20ba7d71307d35040247decbanthony { 17091ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = ((size_t)args->sigma)*2+1; 17101ef941fea2534a0d20ba7d71307d35040247decbanthony limit1 = (ssize_t)(args->rho*args->rho); 17111ef941fea2534a0d20ba7d71307d35040247decbanthony limit2 = (ssize_t)(args->sigma*args->sigma); 17123dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony } 17131ef941fea2534a0d20ba7d71307d35040247decbanthony else 17141ef941fea2534a0d20ba7d71307d35040247decbanthony { 17151ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = ((size_t)args->rho)*2+1; 17161ef941fea2534a0d20ba7d71307d35040247decbanthony limit1 = (ssize_t)(args->sigma*args->sigma); 17171ef941fea2534a0d20ba7d71307d35040247decbanthony limit2 = (ssize_t)(args->rho*args->rho); 17181ef941fea2534a0d20ba7d71307d35040247decbanthony } 17191ef941fea2534a0d20ba7d71307d35040247decbanthony if ( limit2 <= 0 ) 17201ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = 7L, limit1 = 7L, limit2 = 11L; 17211ef941fea2534a0d20ba7d71307d35040247decbanthony 17221ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height = kernel->width; 17231ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 1724e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 1725e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 1726e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 1727d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 17281ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 17291ef941fea2534a0d20ba7d71307d35040247decbanthony 17301ef941fea2534a0d20ba7d71307d35040247decbanthony /* set a ring of points of 'scale' ( 0.0 for PeaksKernel ) */ 17311ef941fea2534a0d20ba7d71307d35040247decbanthony scale = (ssize_t) (( type == PeaksKernel) ? 0.0 : args->xi); 17321ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v= -kernel->y; v <= (ssize_t)kernel->y; v++) 17331ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 17341ef941fea2534a0d20ba7d71307d35040247decbanthony { ssize_t radius=u*u+v*v; 17351ef941fea2534a0d20ba7d71307d35040247decbanthony if (limit1 < radius && radius <= limit2) 17361ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = (double) scale; 17371ef941fea2534a0d20ba7d71307d35040247decbanthony else 17381ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = nan; 17391ef941fea2534a0d20ba7d71307d35040247decbanthony } 17401ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = (double) scale; 17411ef941fea2534a0d20ba7d71307d35040247decbanthony if ( type == PeaksKernel ) { 17421ef941fea2534a0d20ba7d71307d35040247decbanthony /* set the central point in the middle */ 17431ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 17441ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = 1.0; 17451ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = 1.0; 17461ef941fea2534a0d20ba7d71307d35040247decbanthony } 17471ef941fea2534a0d20ba7d71307d35040247decbanthony break; 1748c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 17491ef941fea2534a0d20ba7d71307d35040247decbanthony case EdgesKernel: 17501ef941fea2534a0d20ba7d71307d35040247decbanthony { 1751529482f4b494010a13338a74446c510712f670b3anthony kernel=AcquireKernelInfo("ThinSE:482"); 17521ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17531ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17541ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 1755529482f4b494010a13338a74446c510712f670b3anthony ExpandMirrorKernelInfo(kernel); /* mirror expansion of kernels */ 17561ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17571ef941fea2534a0d20ba7d71307d35040247decbanthony } 17581ef941fea2534a0d20ba7d71307d35040247decbanthony case CornersKernel: 17591ef941fea2534a0d20ba7d71307d35040247decbanthony { 1760529482f4b494010a13338a74446c510712f670b3anthony kernel=AcquireKernelInfo("ThinSE:87"); 17611ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17621ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17631ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 17641ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* Expand 90 degree rotations */ 17651ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17661ef941fea2534a0d20ba7d71307d35040247decbanthony } 1767529482f4b494010a13338a74446c510712f670b3anthony case DiagonalsKernel: 17681ef941fea2534a0d20ba7d71307d35040247decbanthony { 17691ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 17701ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 17711ef941fea2534a0d20ba7d71307d35040247decbanthony default: 17721ef941fea2534a0d20ba7d71307d35040247decbanthony { KernelInfo 17731ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 1774529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,0 0,-,1 1,1,-"); 17751ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17761ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17771ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 1778529482f4b494010a13338a74446c510712f670b3anthony new_kernel=ParseKernelArray("3: 0,0,1 0,-,1 0,1,-"); 17791ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 17801ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 17811ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 17821ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 17831ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandMirrorKernelInfo(kernel); 1784529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 17851ef941fea2534a0d20ba7d71307d35040247decbanthony } 17861ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 1787529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,0 0,-,1 1,1,-"); 17881ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17891ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 1790529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,1 0,-,1 0,1,-"); 17911ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17921ef941fea2534a0d20ba7d71307d35040247decbanthony } 1793529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1794529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1795529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1796529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 17971ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17981ef941fea2534a0d20ba7d71307d35040247decbanthony } 17991ef941fea2534a0d20ba7d71307d35040247decbanthony case LineEndsKernel: 18001ef941fea2534a0d20ba7d71307d35040247decbanthony { /* Kernels for finding the end of thin lines */ 18011ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 18021ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 18031ef941fea2534a0d20ba7d71307d35040247decbanthony default: 18041ef941fea2534a0d20ba7d71307d35040247decbanthony /* set of kernels to find all end of lines */ 1805529482f4b494010a13338a74446c510712f670b3anthony return(AcquireKernelInfo("LineEnds:1>;LineEnds:2>")); 18061ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 18071ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel for 4-connected line ends - no rotation */ 18081ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,- 0,1,1 0,0,-"); 18091ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18101ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 18111ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel to add for 8-connected lines - no rotation */ 18121ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,0 0,0,1"); 18131ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18141ef941fea2534a0d20ba7d71307d35040247decbanthony case 3: 18151ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel to add for orthogonal line ends - does not find corners */ 18161ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,1 0,0,0"); 18171ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18181ef941fea2534a0d20ba7d71307d35040247decbanthony case 4: 18191ef941fea2534a0d20ba7d71307d35040247decbanthony /* traditional line end - fails on last T end */ 18201ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,- 0,0,-"); 18211ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18221ef941fea2534a0d20ba7d71307d35040247decbanthony } 1823529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1824529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1825529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1826529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 18271ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18281ef941fea2534a0d20ba7d71307d35040247decbanthony } 18291ef941fea2534a0d20ba7d71307d35040247decbanthony case LineJunctionsKernel: 18301ef941fea2534a0d20ba7d71307d35040247decbanthony { /* kernels for finding the junctions of multiple lines */ 18311ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 18321ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 18331ef941fea2534a0d20ba7d71307d35040247decbanthony default: 18341ef941fea2534a0d20ba7d71307d35040247decbanthony /* set of kernels to find all line junctions */ 1835529482f4b494010a13338a74446c510712f670b3anthony return(AcquireKernelInfo("LineJunctions:1@;LineJunctions:2>")); 18361ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 18371ef941fea2534a0d20ba7d71307d35040247decbanthony /* Y Junction */ 18381ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,1 -,1,- -,1,-"); 18391ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18401ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 18411ef941fea2534a0d20ba7d71307d35040247decbanthony /* Diagonal T Junctions */ 18421ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,- -,1,- 1,-,1"); 18431ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18441ef941fea2534a0d20ba7d71307d35040247decbanthony case 3: 18451ef941fea2534a0d20ba7d71307d35040247decbanthony /* Orthogonal T Junctions */ 18461ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: -,-,- 1,1,1 -,1,-"); 18471ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18481ef941fea2534a0d20ba7d71307d35040247decbanthony case 4: 18491ef941fea2534a0d20ba7d71307d35040247decbanthony /* Diagonal X Junctions */ 18501ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,1 -,1,- 1,-,1"); 18511ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18521ef941fea2534a0d20ba7d71307d35040247decbanthony case 5: 18531ef941fea2534a0d20ba7d71307d35040247decbanthony /* Orthogonal X Junctions - minimal diamond kernel */ 18541ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: -,1,- 1,1,1 -,1,-"); 18551ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18561ef941fea2534a0d20ba7d71307d35040247decbanthony } 1857529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1858529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1859529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1860529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 18611ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18621ef941fea2534a0d20ba7d71307d35040247decbanthony } 18631ef941fea2534a0d20ba7d71307d35040247decbanthony case RidgesKernel: 18641ef941fea2534a0d20ba7d71307d35040247decbanthony { /* Ridges - Ridge finding kernels */ 18651ef941fea2534a0d20ba7d71307d35040247decbanthony KernelInfo 18661ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 18671ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 18681ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 18691ef941fea2534a0d20ba7d71307d35040247decbanthony default: 18701ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3x1:0,1,0"); 18711ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 18721ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 18731ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 18741ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* 2 rotated kernels (symmetrical) */ 18751ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18761ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 18771ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("4x1:0,1,1,0"); 18781ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 18791ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 18801ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 18811ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotated kernels */ 18821ef941fea2534a0d20ba7d71307d35040247decbanthony 18831ef941fea2534a0d20ba7d71307d35040247decbanthony /* Kernels to find a stepped 'thick' line, 4 rotates + mirrors */ 18841ef941fea2534a0d20ba7d71307d35040247decbanthony /* Unfortunatally we can not yet rotate a non-square kernel */ 18851ef941fea2534a0d20ba7d71307d35040247decbanthony /* But then we can't flip a non-symetrical kernel either */ 18861ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+1+1:0,1,1,- -,1,1,- -,1,1,0"); 18871ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18881ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18891ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18901ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18911ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+2+1:0,1,1,- -,1,1,- -,1,1,0"); 18921ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18931ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18941ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18951ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18961ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+1+1:-,1,1,0 -,1,1,- 0,1,1,-"); 18971ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18981ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18991ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19001ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19011ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+2+1:-,1,1,0 -,1,1,- 0,1,1,-"); 19021ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19031ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19041ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19051ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19061ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+1:0,-,- 1,1,1 1,1,1 -,-,0"); 19071ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19081ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19091ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19101ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19111ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+2:0,-,- 1,1,1 1,1,1 -,-,0"); 19121ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19131ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19141ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19151ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19161ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+1:-,-,0 1,1,1 1,1,1 0,-,-"); 19171ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19181ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19191ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19201ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19211ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+2:-,-,0 1,1,1 1,1,1 0,-,-"); 192268cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony if (new_kernel == (KernelInfo *) NULL) 192368cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony return(DestroyKernelInfo(kernel)); 192468cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony new_kernel->type = type; 192568cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony LastKernelInfo(kernel)->next = new_kernel; 192668cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony break; 19271ef941fea2534a0d20ba7d71307d35040247decbanthony } 19281ef941fea2534a0d20ba7d71307d35040247decbanthony break; 192968cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony } 19301ef941fea2534a0d20ba7d71307d35040247decbanthony case ConvexHullKernel: 19311ef941fea2534a0d20ba7d71307d35040247decbanthony { 19321ef941fea2534a0d20ba7d71307d35040247decbanthony KernelInfo 19331ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 19341ef941fea2534a0d20ba7d71307d35040247decbanthony /* first set of 8 kernels */ 19351ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,1,- 1,0,- 1,-,0"); 19361ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 19371ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 19381ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 19391ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); 19401ef941fea2534a0d20ba7d71307d35040247decbanthony /* append the mirror versions too - no flip function yet */ 19411ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3: 1,1,1 1,0,- -,-,0"); 19421ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 19431ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 19441ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 19451ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(new_kernel, 90.0); 19461ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 19471ef941fea2534a0d20ba7d71307d35040247decbanthony break; 1948694934fa79dd310f727588b1d0a7481fa6170f1danthony } 19499a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case SkeletonKernel: 19509a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony { 19519a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony switch ( (int) args->rho ) { 19529a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 1: 19539a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony default: 19549a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* Traditional Skeleton... 19559a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** A cyclically rotated single kernel 19569a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19579a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo("ThinSE:482"); 19589a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19599a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19609a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19619a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandRotateKernelInfo(kernel, 45.0); /* 8 rotations */ 19629a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19639a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 2: 19649a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* HIPR Variation of the cyclic skeleton 19659a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** Corners of the traditional method made more forgiving, 19669a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** but the retain the same cyclic order. 19679a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19689a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo("ThinSE:482; ThinSE:87x90;"); 19699a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19709a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19719a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel->next == (KernelInfo *) NULL) 19729a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(DestroyKernelInfo(kernel)); 19739a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19749a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->type = type; 19759a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotations of the 2 kernels */ 19769a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19779a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 3: 19789a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* Dan Bloomberg Skeleton, from his paper on 3x3 thinning SE's 19799a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** "Connectivity-Preserving Morphological Image Thransformations" 19809a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** by Dan S. Bloomberg, available on Leptonica, Selected Papers, 19819a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** http://www.leptonica.com/papers/conn.pdf 19829a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19839a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo( 19849a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony "ThinSE:41; ThinSE:42; ThinSE:43"); 19859a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19869a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19879a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19889a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->type = type; 19899a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->next->type = type; 19909a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandMirrorKernelInfo(kernel); /* 12 kernels total */ 19919a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19929a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony } 19939a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19949a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony } 1995529482f4b494010a13338a74446c510712f670b3anthony case ThinSEKernel: 1996529482f4b494010a13338a74446c510712f670b3anthony { /* Special kernels for general thinning, while preserving connections 1997529482f4b494010a13338a74446c510712f670b3anthony ** "Connectivity-Preserving Morphological Image Thransformations" 1998529482f4b494010a13338a74446c510712f670b3anthony ** by Dan S. Bloomberg, available on Leptonica, Selected Papers, 1999529482f4b494010a13338a74446c510712f670b3anthony ** http://www.leptonica.com/papers/conn.pdf 2000529482f4b494010a13338a74446c510712f670b3anthony ** And 2001529482f4b494010a13338a74446c510712f670b3anthony ** http://tpgit.github.com/Leptonica/ccthin_8c_source.html 2002529482f4b494010a13338a74446c510712f670b3anthony ** 2003529482f4b494010a13338a74446c510712f670b3anthony ** Note kernels do not specify the origin pixel, allowing them 2004529482f4b494010a13338a74446c510712f670b3anthony ** to be used for both thickening and thinning operations. 2005529482f4b494010a13338a74446c510712f670b3anthony */ 2006529482f4b494010a13338a74446c510712f670b3anthony switch ( (int) args->rho ) { 2007529482f4b494010a13338a74446c510712f670b3anthony /* SE for 4-connected thinning */ 2008529482f4b494010a13338a74446c510712f670b3anthony case 41: /* SE_4_1 */ 2009529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 -,-,1"); 2010529482f4b494010a13338a74446c510712f670b3anthony break; 2011529482f4b494010a13338a74446c510712f670b3anthony case 42: /* SE_4_2 */ 2012529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 -,0,-"); 2013529482f4b494010a13338a74446c510712f670b3anthony break; 2014529482f4b494010a13338a74446c510712f670b3anthony case 43: /* SE_4_3 */ 2015529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,-,1"); 2016529482f4b494010a13338a74446c510712f670b3anthony break; 2017529482f4b494010a13338a74446c510712f670b3anthony case 44: /* SE_4_4 */ 2018529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,0,-"); 2019529482f4b494010a13338a74446c510712f670b3anthony break; 2020529482f4b494010a13338a74446c510712f670b3anthony case 45: /* SE_4_5 */ 2021529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,1 0,-,1 -,0,-"); 2022529482f4b494010a13338a74446c510712f670b3anthony break; 2023529482f4b494010a13338a74446c510712f670b3anthony case 46: /* SE_4_6 */ 2024529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,0,1"); 2025529482f4b494010a13338a74446c510712f670b3anthony break; 2026529482f4b494010a13338a74446c510712f670b3anthony case 47: /* SE_4_7 */ 2027529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,1 0,-,1 -,0,-"); 2028529482f4b494010a13338a74446c510712f670b3anthony break; 2029529482f4b494010a13338a74446c510712f670b3anthony case 48: /* SE_4_8 */ 2030529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 0,-,1"); 2031529482f4b494010a13338a74446c510712f670b3anthony break; 2032529482f4b494010a13338a74446c510712f670b3anthony case 49: /* SE_4_9 */ 2033529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 -,-,1"); 2034529482f4b494010a13338a74446c510712f670b3anthony break; 2035529482f4b494010a13338a74446c510712f670b3anthony /* SE for 8-connected thinning - negatives of the above */ 2036529482f4b494010a13338a74446c510712f670b3anthony case 81: /* SE_8_0 */ 2037529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 -,1,-"); 2038529482f4b494010a13338a74446c510712f670b3anthony break; 2039529482f4b494010a13338a74446c510712f670b3anthony case 82: /* SE_8_2 */ 2040529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,-,-"); 2041529482f4b494010a13338a74446c510712f670b3anthony break; 2042529482f4b494010a13338a74446c510712f670b3anthony case 83: /* SE_8_3 */ 2043529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 -,1,-"); 2044529482f4b494010a13338a74446c510712f670b3anthony break; 2045529482f4b494010a13338a74446c510712f670b3anthony case 84: /* SE_8_4 */ 2046529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 0,-,-"); 2047529482f4b494010a13338a74446c510712f670b3anthony break; 2048529482f4b494010a13338a74446c510712f670b3anthony case 85: /* SE_8_5 */ 2049529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 0,-,-"); 2050529482f4b494010a13338a74446c510712f670b3anthony break; 2051529482f4b494010a13338a74446c510712f670b3anthony case 86: /* SE_8_6 */ 2052529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 0,-,1"); 2053529482f4b494010a13338a74446c510712f670b3anthony break; 2054529482f4b494010a13338a74446c510712f670b3anthony case 87: /* SE_8_7 */ 2055529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,0,-"); 2056529482f4b494010a13338a74446c510712f670b3anthony break; 2057529482f4b494010a13338a74446c510712f670b3anthony case 88: /* SE_8_8 */ 2058529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,1,-"); 2059529482f4b494010a13338a74446c510712f670b3anthony break; 2060529482f4b494010a13338a74446c510712f670b3anthony case 89: /* SE_8_9 */ 2061529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,1,- 0,-,1 -,1,-"); 2062529482f4b494010a13338a74446c510712f670b3anthony break; 2063529482f4b494010a13338a74446c510712f670b3anthony /* Special combined SE kernels */ 20649a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 423: /* SE_4_2 , SE_4_3 Combined Kernel */ 20659a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=ParseKernelArray("3: -,-,1 0,-,- -,0,-"); 20669a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 20679a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 823: /* SE_8_2 , SE_8_3 Combined Kernel */ 20689a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=ParseKernelArray("3: -,1,- -,-,1 0,-,-"); 20699a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 2070529482f4b494010a13338a74446c510712f670b3anthony case 481: /* SE_48_1 - General Connected Corner Kernel */ 2071529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,1 0,-,1 0,0,-"); 2072529482f4b494010a13338a74446c510712f670b3anthony break; 2073529482f4b494010a13338a74446c510712f670b3anthony default: 2074529482f4b494010a13338a74446c510712f670b3anthony case 482: /* SE_48_2 - General Edge Kernel */ 2075529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 0,-,1"); 2076529482f4b494010a13338a74446c510712f670b3anthony break; 2077529482f4b494010a13338a74446c510712f670b3anthony } 2078529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 2079529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 2080529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 2081529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 2082529482f4b494010a13338a74446c510712f670b3anthony break; 2083529482f4b494010a13338a74446c510712f670b3anthony } 2084529482f4b494010a13338a74446c510712f670b3anthony /* 2085529482f4b494010a13338a74446c510712f670b3anthony Distance Measuring Kernels 2086529482f4b494010a13338a74446c510712f670b3anthony */ 20871ef941fea2534a0d20ba7d71307d35040247decbanthony case ChebyshevKernel: 20881ef941fea2534a0d20ba7d71307d35040247decbanthony { 20891ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 20901ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 20911ef941fea2534a0d20ba7d71307d35040247decbanthony else 20921ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 20931ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 20941ef941fea2534a0d20ba7d71307d35040247decbanthony 2095e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2096e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2097e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2098d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 20991ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 21001ef941fea2534a0d20ba7d71307d35040247decbanthony 21011ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 21021ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 21031ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += ( kernel->values[i] = 21041ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*MagickMax(fabs((double)u),fabs((double)v)) ); 21051ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = kernel->values[0]; 21061ef941fea2534a0d20ba7d71307d35040247decbanthony break; 2107c40ac1e79923a1516075ba1197ae4ed90244af9banthony } 21081ef941fea2534a0d20ba7d71307d35040247decbanthony case ManhattanKernel: 21091ef941fea2534a0d20ba7d71307d35040247decbanthony { 21101ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 21111ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 21121ef941fea2534a0d20ba7d71307d35040247decbanthony else 21131ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 21141ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 21151ef941fea2534a0d20ba7d71307d35040247decbanthony 2116e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2117e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2118e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2119d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 21201ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 21211ef941fea2534a0d20ba7d71307d35040247decbanthony 21221ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 21231ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 21241ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += ( kernel->values[i] = 21251ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*(labs((long) u)+labs((long) v)) ); 21261ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = kernel->values[0]; 21271ef941fea2534a0d20ba7d71307d35040247decbanthony break; 2128c40ac1e79923a1516075ba1197ae4ed90244af9banthony } 21291ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonalKernel: 2130602ab9b30b644a78a4057da93d838a77391ec0acanthony { 21311ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 2.0) 21321ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default/minimum radius = 2 */ 2133602ab9b30b644a78a4057da93d838a77391ec0acanthony else 2134bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = ((size_t)args->rho)*2+1; 2135bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 2136602ab9b30b644a78a4057da93d838a77391ec0acanthony 2137e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2138e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2139e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2140d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 214183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 2142602ab9b30b644a78a4057da93d838a77391ec0acanthony 2143bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 2144bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 21451ef941fea2534a0d20ba7d71307d35040247decbanthony { 21461ef941fea2534a0d20ba7d71307d35040247decbanthony double 21471ef941fea2534a0d20ba7d71307d35040247decbanthony r1 = MagickMax(fabs((double)u),fabs((double)v)), 21481ef941fea2534a0d20ba7d71307d35040247decbanthony r2 = floor((double)(labs((long)u)+labs((long)v)+1)/1.5); 21491ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = 21501ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*MagickMax(r1,r2); 21511ef941fea2534a0d20ba7d71307d35040247decbanthony } 2152c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 2153602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2154602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2155602ab9b30b644a78a4057da93d838a77391ec0acanthony case EuclideanKernel: 2156602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2157602ab9b30b644a78a4057da93d838a77391ec0acanthony if (args->rho < 1.0) 2158c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 2159602ab9b30b644a78a4057da93d838a77391ec0acanthony else 21601ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 2161bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 2162602ab9b30b644a78a4057da93d838a77391ec0acanthony 2163e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy kernel->values=(MagickRealType *) MagickAssumeAligned( 2164e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height* 2165e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy sizeof(*kernel->values))); 2166d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (kernel->values == (MagickRealType *) NULL) 216783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 2168602ab9b30b644a78a4057da93d838a77391ec0acanthony 2169bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 2170bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 2171c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->positive_range += ( kernel->values[i] = 21720ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony args->sigma*sqrt((double)(u*u+v*v)) ); 2173c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 2174602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2175602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2176602ab9b30b644a78a4057da93d838a77391ec0acanthony default: 2177c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 2178529482f4b494010a13338a74446c510712f670b3anthony /* No-Op Kernel - Basically just a single pixel on its own */ 21793ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony kernel=ParseKernelArray("1:1"); 2180c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 2181c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 2182529482f4b494010a13338a74446c510712f670b3anthony kernel->type = UndefinedKernel; 2183c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 2184c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 2185602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2186602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2187602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 2188602ab9b30b644a78a4057da93d838a77391ec0acanthony} 2189c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony 2190602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 2191602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2192602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2193602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2194602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 21956771f1e8987fa49f52d4176281a2e8524b8e31cbcristy% C l o n e K e r n e l I n f o % 21964fd27e21043be809d66c8202e779255e5b660d2danthony% % 21974fd27e21043be809d66c8202e779255e5b660d2danthony% % 21984fd27e21043be809d66c8202e779255e5b660d2danthony% % 21994fd27e21043be809d66c8202e779255e5b660d2danthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22004fd27e21043be809d66c8202e779255e5b660d2danthony% 22011b2bc0a7da432e6e1cc0480280402df213faa940anthony% CloneKernelInfo() creates a new clone of the given Kernel List so that its 22021b2bc0a7da432e6e1cc0480280402df213faa940anthony% can be modified without effecting the original. The cloned kernel should 22030ffcd2751e5c2f2a606fa367a7fd01a424d3fdf7anthony% be destroyed using DestoryKernelInfo() when no longer needed. 22047a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 2205e636559dfadfdb115cc93f223315052a1ee89238cristy% The format of the CloneKernelInfo method is: 22064fd27e21043be809d66c8202e779255e5b660d2danthony% 2207930be614b4595b97cd79ee864a394796740f76adanthony% KernelInfo *CloneKernelInfo(const KernelInfo *kernel) 22084fd27e21043be809d66c8202e779255e5b660d2danthony% 22094fd27e21043be809d66c8202e779255e5b660d2danthony% A description of each parameter follows: 22104fd27e21043be809d66c8202e779255e5b660d2danthony% 22114fd27e21043be809d66c8202e779255e5b660d2danthony% o kernel: the Morphology/Convolution kernel to be cloned 22124fd27e21043be809d66c8202e779255e5b660d2danthony% 22134fd27e21043be809d66c8202e779255e5b660d2danthony*/ 2214ef656913b0b30d713ae94c82c47693c9dc69c9f4cristyMagickExport KernelInfo *CloneKernelInfo(const KernelInfo *kernel) 22154fd27e21043be809d66c8202e779255e5b660d2danthony{ 2216bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 22174fd27e21043be809d66c8202e779255e5b660d2danthony i; 22184fd27e21043be809d66c8202e779255e5b660d2danthony 221919eb64195ef744f61293025952df1e5e6de66524cristy KernelInfo 22207a01dcf50ce12cb2a789bedff51e9345f022432eanthony *new_kernel; 22214fd27e21043be809d66c8202e779255e5b660d2danthony 22224fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel != (KernelInfo *) NULL); 22237a01dcf50ce12cb2a789bedff51e9345f022432eanthony new_kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel)); 22247a01dcf50ce12cb2a789bedff51e9345f022432eanthony if (new_kernel == (KernelInfo *) NULL) 22257a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(new_kernel); 22267a01dcf50ce12cb2a789bedff51e9345f022432eanthony *new_kernel=(*kernel); /* copy values in structure */ 22277a01dcf50ce12cb2a789bedff51e9345f022432eanthony 22287a01dcf50ce12cb2a789bedff51e9345f022432eanthony /* replace the values with a copy of the values */ 2229e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy new_kernel->values=(MagickRealType *) MagickAssumeAligned( 2230e42639a7b750e7b86ae59f3ba8f5972fee9e85d3cristy AcquireAlignedMemory(kernel->width,kernel->height*sizeof(*kernel->values))); 2231d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy if (new_kernel->values == (MagickRealType *) NULL) 22327a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(DestroyKernelInfo(new_kernel)); 2233bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++) 22347a01dcf50ce12cb2a789bedff51e9345f022432eanthony new_kernel->values[i]=kernel->values[i]; 22351b2bc0a7da432e6e1cc0480280402df213faa940anthony 22361b2bc0a7da432e6e1cc0480280402df213faa940anthony /* Also clone the next kernel in the kernel list */ 22371b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL ) { 22381b2bc0a7da432e6e1cc0480280402df213faa940anthony new_kernel->next = CloneKernelInfo(kernel->next); 22391b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( new_kernel->next == (KernelInfo *) NULL ) 22401b2bc0a7da432e6e1cc0480280402df213faa940anthony return(DestroyKernelInfo(new_kernel)); 22411b2bc0a7da432e6e1cc0480280402df213faa940anthony } 22421b2bc0a7da432e6e1cc0480280402df213faa940anthony 22437a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(new_kernel); 22444fd27e21043be809d66c8202e779255e5b660d2danthony} 22454fd27e21043be809d66c8202e779255e5b660d2danthony 22464fd27e21043be809d66c8202e779255e5b660d2danthony/* 22474fd27e21043be809d66c8202e779255e5b660d2danthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22484fd27e21043be809d66c8202e779255e5b660d2danthony% % 22494fd27e21043be809d66c8202e779255e5b660d2danthony% % 22504fd27e21043be809d66c8202e779255e5b660d2danthony% % 225183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% D e s t r o y K e r n e l I n f o % 2252602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2253602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2254602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2255602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2256602ab9b30b644a78a4057da93d838a77391ec0acanthony% 225783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% DestroyKernelInfo() frees the memory used by a Convolution/Morphology 225883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% kernel. 2259602ab9b30b644a78a4057da93d838a77391ec0acanthony% 226083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% The format of the DestroyKernelInfo method is: 2261602ab9b30b644a78a4057da93d838a77391ec0acanthony% 226283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% KernelInfo *DestroyKernelInfo(KernelInfo *kernel) 2263602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2264602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 2265602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2266602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel: the Morphology/Convolution kernel to be destroyed 2267602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2268602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 226983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthonyMagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel) 2270602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 22712be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy assert(kernel != (KernelInfo *) NULL); 22727a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( kernel->next != (KernelInfo *) NULL ) 22739f752c092332bf2c4e599ea49e9422c13f3fb11bcristy kernel->next=DestroyKernelInfo(kernel->next); 2274d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy kernel->values=(MagickRealType *) RelinquishAlignedMemory(kernel->values); 22759f752c092332bf2c4e599ea49e9422c13f3fb11bcristy kernel=(KernelInfo *) RelinquishMagickMemory(kernel); 2276602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 2277602ab9b30b644a78a4057da93d838a77391ec0acanthony} 2278c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony 2279c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony/* 2280c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2281c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2282c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2283c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2284ce0fd95b65b90e1dc307600bb14b346b777e8137anthony+ E x p a n d M i r r o r K e r n e l I n f o % 22853c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 22863c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 22873c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 22883c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22893c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2290bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% ExpandMirrorKernelInfo() takes a single kernel, and expands it into a 2291bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% sequence of 90-degree rotated kernels but providing a reflected 180 2292bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% rotatation, before the -/+ 90-degree rotations. 2293bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2294bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% This special rotation order produces a better, more symetrical thinning of 2295bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% objects. 2296bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2297bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The format of the ExpandMirrorKernelInfo method is: 2298bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2299bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% void ExpandMirrorKernelInfo(KernelInfo *kernel) 2300bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2301bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% A description of each parameter follows: 2302bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2303bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% o kernel: the Morphology/Convolution kernel 2304bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2305bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% This function is only internel to this module, as it is not finalized, 2306bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% especially with regard to non-orthogonal angles, and rotation of larger 2307bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2D kernels. 2308bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony*/ 2309bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2310bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony#if 0 2311bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void FlopKernelInfo(KernelInfo *kernel) 2312bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony { /* Do a Flop by reversing each row. */ 2313bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony size_t 2314bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony y; 2315bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony register ssize_t 2316bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony x,r; 2317bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony register double 2318bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *k,t; 2319bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2320bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width) 2321bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--) 2322bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony t=k[x], k[x]=k[r], k[r]=t; 2323bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2324bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony kernel->x = kernel->width - kernel->x - 1; 2325bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony angle = fmod(angle+180.0, 360.0); 2326bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony } 2327bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony#endif 2328bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2329bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void ExpandMirrorKernelInfo(KernelInfo *kernel) 2330bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony{ 2331bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony KernelInfo 2332bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *clone, 2333bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *last; 2334bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2335bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = kernel; 2336bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2337bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2338bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 180); /* flip */ 2339bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2340bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = clone; 2341bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2342bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2343bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 90); /* transpose */ 2344bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2345bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = clone; 2346bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2347bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2348bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 180); /* flop */ 2349bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2350bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2351bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony return; 2352bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony} 2353bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2354bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony/* 2355bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2356bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2357bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2358bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2359ce0fd95b65b90e1dc307600bb14b346b777e8137anthony+ E x p a n d R o t a t e K e r n e l I n f o % 2360bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2361bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2362bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2363bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2364bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2365bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% ExpandRotateKernelInfo() takes a kernel list, and expands it by rotating 2366529482f4b494010a13338a74446c510712f670b3anthony% incrementally by the angle given, until the kernel repeats. 23673c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23683c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% WARNING: 45 degree rotations only works for 3x3 kernels. 23693c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% While 90 degree roatations only works for linear and square kernels 23703c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2371bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The format of the ExpandRotateKernelInfo method is: 23723c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2373bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% void ExpandRotateKernelInfo(KernelInfo *kernel, double angle) 23743c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23753c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% A description of each parameter follows: 23763c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23773c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% o kernel: the Morphology/Convolution kernel 23783c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23793c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% o angle: angle to rotate in degrees 23803c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23813c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% This function is only internel to this module, as it is not finalized, 23823c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% especially with regard to non-orthogonal angles, and rotation of larger 23833c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2D kernels. 23843c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony*/ 238547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 238647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony/* Internal Routine - Return true if two kernels are the same */ 238747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthonystatic MagickBooleanType SameKernelInfo(const KernelInfo *kernel1, 238847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony const KernelInfo *kernel2) 238947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony{ 2390bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 239147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony i; 23921d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 23931d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* check size and origin location */ 23941d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( kernel1->width != kernel2->width 23951d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->height != kernel2->height 23961d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->x != kernel2->x 23971d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->y != kernel2->y ) 239847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 23991d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 24001d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* check actual kernel values */ 240147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony for (i=0; i < (kernel1->width*kernel1->height); i++) { 2402f0a92fd8deb68d411304359906b12679b675691fglennrp /* Test for Nan equivalence */ 2403a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ( IfNaN(kernel1->values[i]) && !IfNaN(kernel2->values[i]) ) 240447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 2405a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ( IfNaN(kernel2->values[i]) && !IfNaN(kernel1->values[i]) ) 240647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 2407f0a92fd8deb68d411304359906b12679b675691fglennrp /* Test actual values are equivalent */ 2408b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(kernel1->values[i] - kernel2->values[i]) >= MagickEpsilon ) 240947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 241047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 24111d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 241247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickTrue; 241347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony} 241447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 2415bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void ExpandRotateKernelInfo(KernelInfo *kernel, const double angle) 24163c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony{ 24173c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony KernelInfo 241884d9b5596c0900609dea18795861e2b0936b21c6cristy *clone, 24193c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony *last; 2420a9a61ad96c5112acd968f97b689bd42ca392d70bcristy 24213c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony last = kernel; 242247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while(1) { 242384d9b5596c0900609dea18795861e2b0936b21c6cristy clone = CloneKernelInfo(last); 242484d9b5596c0900609dea18795861e2b0936b21c6cristy RotateKernelInfo(clone, angle); 242584d9b5596c0900609dea18795861e2b0936b21c6cristy if ( SameKernelInfo(kernel, clone) == MagickTrue ) 242647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 2427bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 242884d9b5596c0900609dea18795861e2b0936b21c6cristy last = clone; 24293c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 2430bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = DestroyKernelInfo(clone); /* kernel has repeated - junk the clone */ 243147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return; 24323c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony} 24333c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony 24343c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony/* 24353c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 24363c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 24373c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 24383c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 243946a369d839971ab627bdb31a93d8bd63e81b65a3anthony+ C a l c M e t a K e r n a l I n f o % 244046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 244146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 244246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 244346a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 244446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 244546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% CalcKernelMetaData() recalculate the KernelInfo meta-data of this kernel only, 2446dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp% using the kernel values. This should only ne used if it is not possible to 244746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% calculate that meta-data in some easier way. 244846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 244946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% It is important that the meta-data is correct before ScaleKernelInfo() is 245046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% used to perform kernel normalization. 245146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 245246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The format of the CalcKernelMetaData method is: 245346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 245446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% void CalcKernelMetaData(KernelInfo *kernel, const double scale ) 245546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 245646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% A description of each parameter follows: 245746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 245846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o kernel: the Morphology/Convolution kernel to modify 245946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 246046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% WARNING: Minimum and Maximum values are assumed to include zero, even if 246146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% zero is not part of the kernel (as in Gaussian Derived kernels). This 246246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% however is not true for flat-shaped morphological kernels. 246346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 246446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% WARNING: Only the specific kernel pointed to is modified, not a list of 246546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% multiple kernels. 246646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 246746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This is an internal function and not expected to be useful outside this 246846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% module. This could change however. 246946a369d839971ab627bdb31a93d8bd63e81b65a3anthony*/ 247046a369d839971ab627bdb31a93d8bd63e81b65a3anthonystatic void CalcKernelMetaData(KernelInfo *kernel) 247146a369d839971ab627bdb31a93d8bd63e81b65a3anthony{ 2472bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 247346a369d839971ab627bdb31a93d8bd63e81b65a3anthony i; 247446a369d839971ab627bdb31a93d8bd63e81b65a3anthony 247546a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->minimum = kernel->maximum = 0.0; 247646a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->negative_range = kernel->positive_range = 0.0; 247746a369d839971ab627bdb31a93d8bd63e81b65a3anthony for (i=0; i < (kernel->width*kernel->height); i++) 247846a369d839971ab627bdb31a93d8bd63e81b65a3anthony { 247946a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( fabs(kernel->values[i]) < MagickEpsilon ) 248046a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->values[i] = 0.0; 248146a369d839971ab627bdb31a93d8bd63e81b65a3anthony ( kernel->values[i] < 0) 248246a369d839971ab627bdb31a93d8bd63e81b65a3anthony ? ( kernel->negative_range += kernel->values[i] ) 248346a369d839971ab627bdb31a93d8bd63e81b65a3anthony : ( kernel->positive_range += kernel->values[i] ); 248446a369d839971ab627bdb31a93d8bd63e81b65a3anthony Minimize(kernel->minimum, kernel->values[i]); 248546a369d839971ab627bdb31a93d8bd63e81b65a3anthony Maximize(kernel->maximum, kernel->values[i]); 248646a369d839971ab627bdb31a93d8bd63e81b65a3anthony } 248746a369d839971ab627bdb31a93d8bd63e81b65a3anthony 248846a369d839971ab627bdb31a93d8bd63e81b65a3anthony return; 248946a369d839971ab627bdb31a93d8bd63e81b65a3anthony} 249046a369d839971ab627bdb31a93d8bd63e81b65a3anthony 249146a369d839971ab627bdb31a93d8bd63e81b65a3anthony/* 249246a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 249346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 249446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 249546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 24969eb4f74649b23c053b308ce1152dce51239450baanthony% M o r p h o l o g y A p p l y % 2497602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2498602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2499602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2500602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2501602ab9b30b644a78a4057da93d838a77391ec0acanthony% 25029eb4f74649b23c053b308ce1152dce51239450baanthony% MorphologyApply() applies a morphological method, multiple times using 250322de2722b682eb405b60ec6022a7546df994674eanthony% a list of multiple kernels. This is the method that should be called by 250422de2722b682eb405b60ec6022a7546df994674eanthony% other 'operators' that internally use morphology operations as part of 250522de2722b682eb405b60ec6022a7546df994674eanthony% their processing. 2506602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2507ec9ace44c23c302f336f6e672f6857312747d29bcristy% It is basically equivalent to as MorphologyImage() (see below) but without 2508ec9ace44c23c302f336f6e672f6857312747d29bcristy% any user controls. This allows internel programs to use this method to 2509ec9ace44c23c302f336f6e672f6857312747d29bcristy% perform a specific task without possible interference by any API user 2510ec9ace44c23c302f336f6e672f6857312747d29bcristy% supplied settings. 2511e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% 2512f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% It is MorphologyImage() task to extract any such user controls, and 2513e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% pass them to this function for processing. 25149eb4f74649b23c053b308ce1152dce51239450baanthony% 251522de2722b682eb405b60ec6022a7546df994674eanthony% More specifically all given kernels should already be scaled, normalised, 251622de2722b682eb405b60ec6022a7546df994674eanthony% and blended appropriatally before being parred to this routine. The 251722de2722b682eb405b60ec6022a7546df994674eanthony% appropriate bias, and compose (typically 'UndefinedComposeOp') given. 2518602ab9b30b644a78a4057da93d838a77391ec0acanthony% 251947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% The format of the MorphologyApply method is: 2520602ab9b30b644a78a4057da93d838a77391ec0acanthony% 25219eb4f74649b23c053b308ce1152dce51239450baanthony% Image *MorphologyApply(const Image *image,MorphologyMethod method, 2522f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% const ssize_t iterations,const KernelInfo *kernel, 2523f46d42620631d2581e0b6a56456e203e17c427c8anthony% const CompositeMethod compose,const double bias, 2524f46d42620631d2581e0b6a56456e203e17c427c8anthony% ExceptionInfo *exception) 2525602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2526602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 2527602ab9b30b644a78a4057da93d838a77391ec0acanthony% 25288d18850dee4bed193a64866a6d2353eeeb73e145anthony% o image: the source image 2529602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2530602ab9b30b644a78a4057da93d838a77391ec0acanthony% o method: the morphology method to be applied. 2531602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2532602ab9b30b644a78a4057da93d838a77391ec0acanthony% o iterations: apply the operation this many times (or no change). 2533602ab9b30b644a78a4057da93d838a77391ec0acanthony% A value of -1 means loop until no change found. 2534602ab9b30b644a78a4057da93d838a77391ec0acanthony% How this is applied may depend on the morphology method. 2535602ab9b30b644a78a4057da93d838a77391ec0acanthony% Typically this is a value of 1. 2536602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2537602ab9b30b644a78a4057da93d838a77391ec0acanthony% o channel: the channel type. 2538602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2539602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel: An array of double representing the morphology kernel. 2540602ab9b30b644a78a4057da93d838a77391ec0acanthony% 254147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% o compose: How to handle or merge multi-kernel results. 25428d18850dee4bed193a64866a6d2353eeeb73e145anthony% If 'UndefinedCompositeOp' use default for the Morphology method. 25438d18850dee4bed193a64866a6d2353eeeb73e145anthony% If 'NoCompositeOp' force image to be re-iterated by each kernel. 25448d18850dee4bed193a64866a6d2353eeeb73e145anthony% Otherwise merge the results using the compose method given. 254547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% 2546f46d42620631d2581e0b6a56456e203e17c427c8anthony% o bias: Convolution Output Bias. 2547f46d42620631d2581e0b6a56456e203e17c427c8anthony% 25489eb4f74649b23c053b308ce1152dce51239450baanthony% o exception: return any errors or warnings in this structure. 2549602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2550602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 2551f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristystatic ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image, 2552f46d42620631d2581e0b6a56456e203e17c427c8anthony const MorphologyMethod method,const KernelInfo *kernel,const double bias, 2553f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 2554602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 25552be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy#define MorphologyTag "Morphology/Image" 2556602ab9b30b644a78a4057da93d838a77391ec0acanthony 25575f959473f334e196c6bf39b740c12cb4963fceebcristy CacheView 25584c08aed51c5899665ade97263692328eea4af106cristy *image_view, 25594c08aed51c5899665ade97263692328eea4af106cristy *morphology_view; 25605f959473f334e196c6bf39b740c12cb4963fceebcristy 2561ec9ace44c23c302f336f6e672f6857312747d29bcristy OffsetInfo 2562ec9ace44c23c302f336f6e672f6857312747d29bcristy offset; 2563ec9ace44c23c302f336f6e672f6857312747d29bcristy 2564c5876076825b539bd230ddadab1d876805c18291cristy register ssize_t 2565c5876076825b539bd230ddadab1d876805c18291cristy i; 2566c5876076825b539bd230ddadab1d876805c18291cristy 2567bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t 2568ec9ace44c23c302f336f6e672f6857312747d29bcristy y; 2569a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 2570a8843c1f815ffad2568ec592d5b446cb1476aab5anthony size_t 2571306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy *changes, 2572306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy changed, 2573306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy width; 2574602ab9b30b644a78a4057da93d838a77391ec0acanthony 2575602ab9b30b644a78a4057da93d838a77391ec0acanthony MagickBooleanType 2576602ab9b30b644a78a4057da93d838a77391ec0acanthony status; 2577602ab9b30b644a78a4057da93d838a77391ec0acanthony 25785f959473f334e196c6bf39b740c12cb4963fceebcristy MagickOffsetType 25795f959473f334e196c6bf39b740c12cb4963fceebcristy progress; 2580602ab9b30b644a78a4057da93d838a77391ec0acanthony 2581e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(image != (Image *) NULL); 2582e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(image->signature == MagickSignature); 25834c08aed51c5899665ade97263692328eea4af106cristy assert(morphology_image != (Image *) NULL); 25844c08aed51c5899665ade97263692328eea4af106cristy assert(morphology_image->signature == MagickSignature); 2585e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(kernel != (KernelInfo *) NULL); 2586e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(kernel->signature == MagickSignature); 2587e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(exception != (ExceptionInfo *) NULL); 2588e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(exception->signature == MagickSignature); 2589602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickTrue; 2590602ab9b30b644a78a4057da93d838a77391ec0acanthony progress=0; 259146ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy image_view=AcquireVirtualCacheView(image,exception); 259246ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy morphology_view=AcquireAuthenticCacheView(morphology_image,exception); 2593ec9ace44c23c302f336f6e672f6857312747d29bcristy width=image->columns+kernel->width-1; 2594ec9ace44c23c302f336f6e672f6857312747d29bcristy switch (method) 2595ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2596930be614b4595b97cd79ee864a394796740f76adanthony case ConvolveMorphology: 2597930be614b4595b97cd79ee864a394796740f76adanthony case DilateMorphology: 2598930be614b4595b97cd79ee864a394796740f76adanthony case DilateIntensityMorphology: 2599f34d9b2df49a407af764c79e07d587af0600983aanthony case IterativeDistanceMorphology: 2600ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2601ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 2602ec9ace44c23c302f336f6e672f6857312747d29bcristy Kernel needs to used with reflection about origin. 2603ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 2604ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.x=(ssize_t) kernel->width-kernel->x-1; 2605ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.y=(ssize_t) kernel->height-kernel->y-1; 260629188a8682a98d4b7882cca434b170517555fc7danthony break; 2607ec9ace44c23c302f336f6e672f6857312747d29bcristy } 26085ef8e94ff55717be2387d537bd49025780a1a558anthony case ErodeMorphology: 26095ef8e94ff55717be2387d537bd49025780a1a558anthony case ErodeIntensityMorphology: 26105ef8e94ff55717be2387d537bd49025780a1a558anthony case HitAndMissMorphology: 26115ef8e94ff55717be2387d537bd49025780a1a558anthony case ThinningMorphology: 26125ef8e94ff55717be2387d537bd49025780a1a558anthony case ThickenMorphology: 2613ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2614ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.x=kernel->x; 2615ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.y=kernel->y; 26165ef8e94ff55717be2387d537bd49025780a1a558anthony break; 2617ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2618930be614b4595b97cd79ee864a394796740f76adanthony default: 2619ec9ace44c23c302f336f6e672f6857312747d29bcristy { 26209eb4f74649b23c053b308ce1152dce51239450baanthony assert("Not a Primitive Morphology Method" != (char *) NULL); 2621930be614b4595b97cd79ee864a394796740f76adanthony break; 2622ec9ace44c23c302f336f6e672f6857312747d29bcristy } 262329188a8682a98d4b7882cca434b170517555fc7danthony } 2624c5876076825b539bd230ddadab1d876805c18291cristy changed=0; 2625306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy changes=(size_t *) AcquireQuantumMemory(GetOpenMPMaximumThreads(), 2626306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy sizeof(*changes)); 2627306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy if (changes == (size_t *) NULL) 2628306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 2629c5876076825b539bd230ddadab1d876805c18291cristy for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++) 2630c5876076825b539bd230ddadab1d876805c18291cristy changes[i]=0; 2631ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((method == ConvolveMorphology) && (kernel->width == 1)) 2632780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2633c5876076825b539bd230ddadab1d876805c18291cristy const int 2634c5876076825b539bd230ddadab1d876805c18291cristy id = GetOpenMPThreadId(); 2635c5876076825b539bd230ddadab1d876805c18291cristy 2636780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register ssize_t 2637780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy x; 2638fd1175952254cf1ac848ddb441e483c5e33d517fcristy 2639780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy /* 2640ec9ace44c23c302f336f6e672f6857312747d29bcristy Special handling (for speed) of vertical (blur) kernels. This performs 2641ec9ace44c23c302f336f6e672f6857312747d29bcristy its handling in columns rather than in rows. This is only done 2642ec9ace44c23c302f336f6e672f6857312747d29bcristy for convolve as it is the only method that generates very large 1-D 2643ec9ace44c23c302f336f6e672f6857312747d29bcristy vertical kernels (such as a 'BlurKernel') 2644780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy */ 26458d18850dee4bed193a64866a6d2353eeeb73e145anthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 2646c5876076825b539bd230ddadab1d876805c18291cristy #pragma omp parallel for schedule(static,4) shared(progress,status) \ 2647780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy magick_threads(image,morphology_image,image->columns,1) 26488d18850dee4bed193a64866a6d2353eeeb73e145anthony#endif 2649780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy for (x=0; x < (ssize_t) image->columns; x++) 2650780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2651780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register const Quantum 2652780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy *restrict p; 26538d18850dee4bed193a64866a6d2353eeeb73e145anthony 2654780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register Quantum 2655780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy *restrict q; 26568d18850dee4bed193a64866a6d2353eeeb73e145anthony 2657780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register ssize_t 2658780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy y; 26598d18850dee4bed193a64866a6d2353eeeb73e145anthony 2660780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy ssize_t 2661780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy center; 26628d18850dee4bed193a64866a6d2353eeeb73e145anthony 2663780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (status == MagickFalse) 26648d18850dee4bed193a64866a6d2353eeeb73e145anthony continue; 2665ec9ace44c23c302f336f6e672f6857312747d29bcristy p=GetCacheViewVirtualPixels(image_view,x,-offset.y,1,image->rows+ 2666780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy kernel->height-1,exception); 2667780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy q=GetCacheViewAuthenticPixels(morphology_view,x,0,1, 2668780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy morphology_image->rows,exception); 2669780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 2670780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2671780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy status=MagickFalse; 2672780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy continue; 2673780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 2674ec9ace44c23c302f336f6e672f6857312747d29bcristy center=(ssize_t) GetPixelChannels(image)*offset.y; 2675780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy for (y=0; y < (ssize_t) image->rows; y++) 2676f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy { 2677780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register ssize_t 2678780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy i; 26798d18850dee4bed193a64866a6d2353eeeb73e145anthony 2680780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 2681780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2682780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy double 2683780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy alpha, 2684780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy pixel; 26858d18850dee4bed193a64866a6d2353eeeb73e145anthony 2686780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy PixelChannel 2687780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy channel; 2688d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 2689780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy PixelTrait 2690780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy morphology_traits, 2691780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy traits; 26928d18850dee4bed193a64866a6d2353eeeb73e145anthony 2693780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register const MagickRealType 2694780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy *restrict k; 26958d18850dee4bed193a64866a6d2353eeeb73e145anthony 2696780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register const Quantum 2697780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy *restrict pixels; 26988d18850dee4bed193a64866a6d2353eeeb73e145anthony 2699780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy register ssize_t 2700780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy u; 2701f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy 2702780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy ssize_t 2703780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy v; 2704780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy 2705780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy channel=GetPixelChannelChannel(image,i); 2706780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy traits=GetPixelChannelTraits(image,channel); 2707780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy morphology_traits=GetPixelChannelTraits(morphology_image,channel); 2708780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if ((traits == UndefinedPixelTrait) || 2709780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy (morphology_traits == UndefinedPixelTrait)) 2710f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy continue; 2711780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (((morphology_traits & CopyPixelTrait) != 0) || 2712883fde11debec15cedb05dc5d7228d8588066bc0cristy (GetPixelReadMask(image,p+center) == 0)) 2713f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy { 2714780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy SetPixelChannel(morphology_image,channel,p[center+i],q); 2715780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy continue; 2716780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 2717ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 2718780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy pixels=p; 2719780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy pixel=bias; 2720780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if ((morphology_traits & BlendPixelTrait) == 0) 2721780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2722780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy /* 2723780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy No alpha blending. 2724780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy */ 2725780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy for (v=0; v < (ssize_t) kernel->height; v++) 2726f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy { 2727780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy for (u=0; u < (ssize_t) kernel->width; u++) 2728780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2729a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 2730a62cd0834ed954440c88fb0772413489f1cbd0afcristy pixel+=(*k)*pixels[i]; 2731780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy k--; 2732780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy pixels+=GetPixelChannels(image); 2733780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 2734f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy } 2735780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (fabs(pixel-p[center+i]) > MagickEpsilon) 2736c5876076825b539bd230ddadab1d876805c18291cristy changes[id]++; 2737780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy SetPixelChannel(morphology_image,channel,ClampToQuantum(pixel), 2738780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy q); 2739780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy continue; 2740f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy } 2741780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy /* 2742780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy Alpha blending. 2743780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy */ 274433c51e0d3335ba3b35248454fe61c1805f65a115cristy for (v=0; v < (ssize_t) kernel->height; v++) 2745f21bb67d868cc29539071a3489e0dd5cf1d7f8c4cristy { 2746780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy for (u=0; u < (ssize_t) kernel->width; u++) 2747780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2748a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 2749a62cd0834ed954440c88fb0772413489f1cbd0afcristy { 2750a62cd0834ed954440c88fb0772413489f1cbd0afcristy alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels)); 2751a62cd0834ed954440c88fb0772413489f1cbd0afcristy pixel+=(*k)*alpha*pixels[i]; 2752a62cd0834ed954440c88fb0772413489f1cbd0afcristy } 2753780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy k--; 2754780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy pixels+=GetPixelChannels(image); 2755780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 27568d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2757780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (fabs(pixel-p[center+i]) > MagickEpsilon) 2758c5876076825b539bd230ddadab1d876805c18291cristy changes[id]++; 2759780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy SetPixelChannel(morphology_image,channel,ClampToQuantum(pixel),q); 27608d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2761780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy p+=GetPixelChannels(image); 2762780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy q+=GetPixelChannels(morphology_image); 2763ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2764780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 2765780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy status=MagickFalse; 2766780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (image->progress_monitor != (MagickProgressMonitor) NULL) 2767780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy { 2768780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy MagickBooleanType 2769780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy proceed; 27708d18850dee4bed193a64866a6d2353eeeb73e145anthony 27718d18850dee4bed193a64866a6d2353eeeb73e145anthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 2772954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy #pragma omp critical (MagickCore_MorphologyPrimitive) 27738d18850dee4bed193a64866a6d2353eeeb73e145anthony#endif 2774ec9ace44c23c302f336f6e672f6857312747d29bcristy proceed=SetImageProgress(image,MorphologyTag,progress++, 2775ec9ace44c23c302f336f6e672f6857312747d29bcristy image->rows); 2776780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy if (proceed == MagickFalse) 2777780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy status=MagickFalse; 2778780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 2779780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 2780780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy morphology_image->type=image->type; 2781780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy morphology_view=DestroyCacheView(morphology_view); 2782780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy image_view=DestroyCacheView(image_view); 2783c5876076825b539bd230ddadab1d876805c18291cristy for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++) 2784c5876076825b539bd230ddadab1d876805c18291cristy changed+=changes[i]; 2785306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy changes=(size_t *) RelinquishMagickMemory(changes); 2786780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy return(status ? (ssize_t) changed : 0); 2787780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy } 27888d18850dee4bed193a64866a6d2353eeeb73e145anthony /* 2789780ad21bc9eb5167cfdcc52daabf4d3d83b26248cristy Normal handling of horizontal or rectangular kernels (row by row). 27908d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 2791602ab9b30b644a78a4057da93d838a77391ec0acanthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 2792c5876076825b539bd230ddadab1d876805c18291cristy #pragma omp parallel for schedule(static,4) shared(progress,status) \ 27935e6b259130f9dbe0da4666f734937017babe573acristy magick_threads(image,morphology_image,image->rows,1) 2794602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 2795bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (y=0; y < (ssize_t) image->rows; y++) 2796602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2797c5876076825b539bd230ddadab1d876805c18291cristy const int 2798c5876076825b539bd230ddadab1d876805c18291cristy id = GetOpenMPThreadId(); 2799c5876076825b539bd230ddadab1d876805c18291cristy 28004c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 2801602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict p; 2802602ab9b30b644a78a4057da93d838a77391ec0acanthony 28034c08aed51c5899665ade97263692328eea4af106cristy register Quantum 2804602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict q; 2805602ab9b30b644a78a4057da93d838a77391ec0acanthony 2806bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 2807602ab9b30b644a78a4057da93d838a77391ec0acanthony x; 2808602ab9b30b644a78a4057da93d838a77391ec0acanthony 2809ec9ace44c23c302f336f6e672f6857312747d29bcristy ssize_t 2810ec9ace44c23c302f336f6e672f6857312747d29bcristy center; 2811602ab9b30b644a78a4057da93d838a77391ec0acanthony 2812602ab9b30b644a78a4057da93d838a77391ec0acanthony if (status == MagickFalse) 2813602ab9b30b644a78a4057da93d838a77391ec0acanthony continue; 2814ec9ace44c23c302f336f6e672f6857312747d29bcristy p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width, 2815af43471dfedff5d1314cd674fac6508d230df1bccristy kernel->height,exception); 2816af43471dfedff5d1314cd674fac6508d230df1bccristy q=GetCacheViewAuthenticPixels(morphology_view,0,y,morphology_image->columns, 2817af43471dfedff5d1314cd674fac6508d230df1bccristy 1,exception); 28184c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 2819602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2820602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 2821602ab9b30b644a78a4057da93d838a77391ec0acanthony continue; 2822602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2823ec9ace44c23c302f336f6e672f6857312747d29bcristy center=(ssize_t) (GetPixelChannels(image)*width*offset.y+ 2824ec9ace44c23c302f336f6e672f6857312747d29bcristy GetPixelChannels(image)*offset.x); 2825bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (x=0; x < (ssize_t) image->columns; x++) 2826602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2827ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 2828ec9ace44c23c302f336f6e672f6857312747d29bcristy i; 2829602ab9b30b644a78a4057da93d838a77391ec0acanthony 2830ec9ace44c23c302f336f6e672f6857312747d29bcristy for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 2831ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2832ec9ace44c23c302f336f6e672f6857312747d29bcristy double 2833ec9ace44c23c302f336f6e672f6857312747d29bcristy alpha, 2834ec9ace44c23c302f336f6e672f6857312747d29bcristy maximum, 2835ec9ace44c23c302f336f6e672f6857312747d29bcristy minimum, 2836ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel; 2837602ab9b30b644a78a4057da93d838a77391ec0acanthony 2838ec9ace44c23c302f336f6e672f6857312747d29bcristy PixelChannel 2839ec9ace44c23c302f336f6e672f6857312747d29bcristy channel; 2840602ab9b30b644a78a4057da93d838a77391ec0acanthony 2841ec9ace44c23c302f336f6e672f6857312747d29bcristy PixelTrait 2842ec9ace44c23c302f336f6e672f6857312747d29bcristy morphology_traits, 2843ec9ace44c23c302f336f6e672f6857312747d29bcristy traits; 2844ec9ace44c23c302f336f6e672f6857312747d29bcristy 2845ec9ace44c23c302f336f6e672f6857312747d29bcristy register const MagickRealType 2846ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict k; 2847ec9ace44c23c302f336f6e672f6857312747d29bcristy 2848ec9ace44c23c302f336f6e672f6857312747d29bcristy register const Quantum 2849ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict pixels; 2850ec9ace44c23c302f336f6e672f6857312747d29bcristy 2851ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 2852ec9ace44c23c302f336f6e672f6857312747d29bcristy u; 2853602ab9b30b644a78a4057da93d838a77391ec0acanthony 2854ec9ace44c23c302f336f6e672f6857312747d29bcristy ssize_t 2855ec9ace44c23c302f336f6e672f6857312747d29bcristy v; 2856ec9ace44c23c302f336f6e672f6857312747d29bcristy 2857ec9ace44c23c302f336f6e672f6857312747d29bcristy channel=GetPixelChannelChannel(image,i); 2858ec9ace44c23c302f336f6e672f6857312747d29bcristy traits=GetPixelChannelTraits(image,channel); 2859ec9ace44c23c302f336f6e672f6857312747d29bcristy morphology_traits=GetPixelChannelTraits(morphology_image,channel); 2860ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((traits == UndefinedPixelTrait) || 2861ec9ace44c23c302f336f6e672f6857312747d29bcristy (morphology_traits == UndefinedPixelTrait)) 2862ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 2863ec9ace44c23c302f336f6e672f6857312747d29bcristy if (((morphology_traits & CopyPixelTrait) != 0) || 2864883fde11debec15cedb05dc5d7228d8588066bc0cristy (GetPixelReadMask(image,p+center) == 0)) 2865ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2866ec9ace44c23c302f336f6e672f6857312747d29bcristy SetPixelChannel(morphology_image,channel,p[center+i],q); 2867ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 2868ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2869ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=p; 2870ec9ace44c23c302f336f6e672f6857312747d29bcristy maximum=0.0; 2871ec9ace44c23c302f336f6e672f6857312747d29bcristy minimum=(double) QuantumRange; 2872ec9ace44c23c302f336f6e672f6857312747d29bcristy switch (method) 2873ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2874ec9ace44c23c302f336f6e672f6857312747d29bcristy case ConvolveMorphology: pixel=bias; break; 2875ec9ace44c23c302f336f6e672f6857312747d29bcristy case HitAndMissMorphology: pixel=(double) QuantumRange; break; 2876ec9ace44c23c302f336f6e672f6857312747d29bcristy case ThinningMorphology: pixel=(double) QuantumRange; break; 2877ec9ace44c23c302f336f6e672f6857312747d29bcristy case ThickenMorphology: pixel=(double) QuantumRange; break; 2878ec9ace44c23c302f336f6e672f6857312747d29bcristy case ErodeMorphology: pixel=(double) QuantumRange; break; 2879ec9ace44c23c302f336f6e672f6857312747d29bcristy case DilateMorphology: pixel=0.0; break; 2880ec9ace44c23c302f336f6e672f6857312747d29bcristy case ErodeIntensityMorphology: 2881ec9ace44c23c302f336f6e672f6857312747d29bcristy case DilateIntensityMorphology: 2882ec9ace44c23c302f336f6e672f6857312747d29bcristy case IterativeDistanceMorphology: 2883ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2884ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) p[center+i]; 2885ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 2886ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2887ec9ace44c23c302f336f6e672f6857312747d29bcristy default: pixel=0; break; 2888ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2889ec9ace44c23c302f336f6e672f6857312747d29bcristy switch (method) 2890ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2891ec9ace44c23c302f336f6e672f6857312747d29bcristy case ConvolveMorphology: 2892ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2893ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 2894ec9ace44c23c302f336f6e672f6857312747d29bcristy Weighted Average of pixels using reflected kernel 2895ec9ace44c23c302f336f6e672f6857312747d29bcristy 2896ec9ace44c23c302f336f6e672f6857312747d29bcristy For correct working of this operation for asymetrical 2897ec9ace44c23c302f336f6e672f6857312747d29bcristy kernels, the kernel needs to be applied in its reflected form. 2898ec9ace44c23c302f336f6e672f6857312747d29bcristy That is its values needs to be reversed. 2899ec9ace44c23c302f336f6e672f6857312747d29bcristy 2900ec9ace44c23c302f336f6e672f6857312747d29bcristy Correlation is actually the same as this but without reflecting 2901ec9ace44c23c302f336f6e672f6857312747d29bcristy the kernel, and thus 'lower-level' that Convolution. However 2902ec9ace44c23c302f336f6e672f6857312747d29bcristy as Convolution is the more common method used, and it does not 2903ec9ace44c23c302f336f6e672f6857312747d29bcristy really cost us much in terms of processing to use a reflected 2904ec9ace44c23c302f336f6e672f6857312747d29bcristy kernel, so it is Convolution that is implemented. 2905ec9ace44c23c302f336f6e672f6857312747d29bcristy 2906ec9ace44c23c302f336f6e672f6857312747d29bcristy Correlation will have its kernel reflected before calling 2907ec9ace44c23c302f336f6e672f6857312747d29bcristy this function to do a Convolve. 2908ec9ace44c23c302f336f6e672f6857312747d29bcristy 2909ec9ace44c23c302f336f6e672f6857312747d29bcristy For more details of Correlation vs Convolution see 2910ec9ace44c23c302f336f6e672f6857312747d29bcristy http://www.cs.umd.edu/~djacobs/CMSC426/Convolution.pdf 2911930be614b4595b97cd79ee864a394796740f76adanthony */ 2912ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 2913ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((morphology_traits & BlendPixelTrait) == 0) 2914ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2915ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 2916ec9ace44c23c302f336f6e672f6857312747d29bcristy No alpha blending. 29178d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 2918ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 2919ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2920ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 2921ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2922a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 292313ffe4b75e0c768d1e6506c4d5e5881bb9124763cristy pixel+=(*k)*pixels[i]; 2924ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 2925ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 29268d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2927b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 29288d18850dee4bed193a64866a6d2353eeeb73e145anthony } 29298693d3f324310fc2ca933cd239aa053d0651e0b6cristy break; 29308d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2931ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 2932ec9ace44c23c302f336f6e672f6857312747d29bcristy Alpha blending. 2933ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 293433c51e0d3335ba3b35248454fe61c1805f65a115cristy for (v=0; v < (ssize_t) kernel->height; v++) 2935ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2936ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 2937ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2938a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 2939ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2940ec9ace44c23c302f336f6e672f6857312747d29bcristy alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels)); 2941ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel+=(*k)*alpha*pixels[i]; 2942602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2943ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 2944ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 2945602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2946b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 2947ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2948602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2949ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2950ec9ace44c23c302f336f6e672f6857312747d29bcristy case ErodeMorphology: 2951ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2952ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 2953ec9ace44c23c302f336f6e672f6857312747d29bcristy Minimum value within kernel neighbourhood. 2954602ab9b30b644a78a4057da93d838a77391ec0acanthony 2955ec9ace44c23c302f336f6e672f6857312747d29bcristy The kernel is not reflected for this operation. In normal 2956ec9ace44c23c302f336f6e672f6857312747d29bcristy Greyscale Morphology, the kernel value should be added 2957ec9ace44c23c302f336f6e672f6857312747d29bcristy to the real value, this is currently not done, due to the 2958ec9ace44c23c302f336f6e672f6857312747d29bcristy nature of the boolean kernels being used. 2959930be614b4595b97cd79ee864a394796740f76adanthony */ 2960ec9ace44c23c302f336f6e672f6857312747d29bcristy k=kernel->values; 2961ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 2962ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2963ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 2964ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2965a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && (*k >= 0.5)) 2966ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2967ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((double) pixels[i] < pixel) 2968ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]; 2969ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2970ec9ace44c23c302f336f6e672f6857312747d29bcristy k++; 2971ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 2972602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2973b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 2974602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2975602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2976ec9ace44c23c302f336f6e672f6857312747d29bcristy } 2977ec9ace44c23c302f336f6e672f6857312747d29bcristy case DilateMorphology: 2978ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2979ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 2980ec9ace44c23c302f336f6e672f6857312747d29bcristy Maximum value within kernel neighbourhood. 2981ec9ace44c23c302f336f6e672f6857312747d29bcristy 2982ec9ace44c23c302f336f6e672f6857312747d29bcristy For correct working of this operation for asymetrical kernels, 2983ec9ace44c23c302f336f6e672f6857312747d29bcristy the kernel needs to be applied in its reflected form. That is 2984ec9ace44c23c302f336f6e672f6857312747d29bcristy its values needs to be reversed. 2985602ab9b30b644a78a4057da93d838a77391ec0acanthony 2986ec9ace44c23c302f336f6e672f6857312747d29bcristy In normal Greyscale Morphology, the kernel value should be 2987ec9ace44c23c302f336f6e672f6857312747d29bcristy added to the real value, this is currently not done, due to the 2988ec9ace44c23c302f336f6e672f6857312747d29bcristy nature of the boolean kernels being used. 2989930be614b4595b97cd79ee864a394796740f76adanthony */ 2990ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 2991ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 2992ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2993ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 2994ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2995a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && (*k > 0.5)) 2996ec9ace44c23c302f336f6e672f6857312747d29bcristy { 2997ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((double) pixels[i] > pixel) 2998ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]; 2999ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3000ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3001ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3002602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3003b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3004602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3005602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3006ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3007ec9ace44c23c302f336f6e672f6857312747d29bcristy case HitAndMissMorphology: 3008ec9ace44c23c302f336f6e672f6857312747d29bcristy case ThinningMorphology: 3009ec9ace44c23c302f336f6e672f6857312747d29bcristy case ThickenMorphology: 3010ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3011ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3012ec9ace44c23c302f336f6e672f6857312747d29bcristy Minimum of foreground pixel minus maxumum of background pixels. 3013602ab9b30b644a78a4057da93d838a77391ec0acanthony 3014ec9ace44c23c302f336f6e672f6857312747d29bcristy The kernel is not reflected for this operation, and consists 3015ec9ace44c23c302f336f6e672f6857312747d29bcristy of both foreground and background pixel neighbourhoods, 0.0 for 3016ec9ace44c23c302f336f6e672f6857312747d29bcristy background, and 1.0 for foreground with either Nan or 0.5 values 3017ec9ace44c23c302f336f6e672f6857312747d29bcristy for don't care. 3018ec9ace44c23c302f336f6e672f6857312747d29bcristy 3019ec9ace44c23c302f336f6e672f6857312747d29bcristy This never produces a meaningless negative result. Such results 3020ec9ace44c23c302f336f6e672f6857312747d29bcristy cause Thinning/Thicken to not work correctly when used against a 3021ec9ace44c23c302f336f6e672f6857312747d29bcristy greyscale image. 30225ef8e94ff55717be2387d537bd49025780a1a558anthony */ 3023ec9ace44c23c302f336f6e672f6857312747d29bcristy k=kernel->values; 3024ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 3025ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3026ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3027ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3028a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3029ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3030ec9ace44c23c302f336f6e672f6857312747d29bcristy if (*k > 0.7) 3031ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3032ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((double) pixels[i] < pixel) 3033ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]; 3034ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3035ec9ace44c23c302f336f6e672f6857312747d29bcristy else 3036ec9ace44c23c302f336f6e672f6857312747d29bcristy if (*k < 0.3) 3037ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3038ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((double) pixels[i] > maximum) 3039ec9ace44c23c302f336f6e672f6857312747d29bcristy maximum=(double) pixels[i]; 3040ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3041ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3042ec9ace44c23c302f336f6e672f6857312747d29bcristy k++; 3043ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 30445ef8e94ff55717be2387d537bd49025780a1a558anthony } 3045b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 30465ef8e94ff55717be2387d537bd49025780a1a558anthony } 3047ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel-=maximum; 3048ec9ace44c23c302f336f6e672f6857312747d29bcristy if (pixel < 0.0) 3049ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=0.0; 3050ec9ace44c23c302f336f6e672f6857312747d29bcristy if (method == ThinningMorphology) 3051ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) p[center+i]-pixel; 3052ec9ace44c23c302f336f6e672f6857312747d29bcristy else 3053ec9ace44c23c302f336f6e672f6857312747d29bcristy if (method == ThickenMorphology) 3054ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel+=(double) p[center+i]+pixel; 30555ef8e94ff55717be2387d537bd49025780a1a558anthony break; 3056ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3057ec9ace44c23c302f336f6e672f6857312747d29bcristy case ErodeIntensityMorphology: 3058ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3059ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3060ec9ace44c23c302f336f6e672f6857312747d29bcristy Select pixel with minimum intensity within kernel neighbourhood. 30616fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3062ec9ace44c23c302f336f6e672f6857312747d29bcristy The kernel is not reflected for this operation. 3063930be614b4595b97cd79ee864a394796740f76adanthony */ 3064ec9ace44c23c302f336f6e672f6857312747d29bcristy k=kernel->values; 3065ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 3066ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3067ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3068ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3069a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && (*k >= 0.5)) 3070ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3071ec9ace44c23c302f336f6e672f6857312747d29bcristy if (GetPixelIntensity(image,pixels) < minimum) 3072ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3073ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]; 3074ec9ace44c23c302f336f6e672f6857312747d29bcristy minimum=GetPixelIntensity(image,pixels); 3075ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3076ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3077ec9ace44c23c302f336f6e672f6857312747d29bcristy k++; 3078ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3079602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3080b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3081602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3082602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3083ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3084ec9ace44c23c302f336f6e672f6857312747d29bcristy case DilateIntensityMorphology: 3085ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3086ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3087ec9ace44c23c302f336f6e672f6857312747d29bcristy Select pixel with maximum intensity within kernel neighbourhood. 30886fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3089ec9ace44c23c302f336f6e672f6857312747d29bcristy The kernel is not reflected for this operation. 3090930be614b4595b97cd79ee864a394796740f76adanthony */ 3091ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 3092ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 3093ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3094ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3095ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3096a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && (*k >= 0.5)) 3097ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3098ec9ace44c23c302f336f6e672f6857312747d29bcristy if (GetPixelIntensity(image,pixels) > maximum) 3099ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3100ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]; 3101ec9ace44c23c302f336f6e672f6857312747d29bcristy maximum=GetPixelIntensity(image,pixels); 3102ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3103ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3104ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3105ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3106602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3107b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3108602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3109602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3110ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3111ec9ace44c23c302f336f6e672f6857312747d29bcristy case IterativeDistanceMorphology: 3112ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3113ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3114ec9ace44c23c302f336f6e672f6857312747d29bcristy Compute th iterative distance from black edge of a white image 3115ec9ace44c23c302f336f6e672f6857312747d29bcristy shape. Essentually white values are decreased to the smallest 3116ec9ace44c23c302f336f6e672f6857312747d29bcristy 'distance from edge' it can find. 31176fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3118ec9ace44c23c302f336f6e672f6857312747d29bcristy It works by adding kernel values to the neighbourhood, and and 3119ec9ace44c23c302f336f6e672f6857312747d29bcristy select the minimum value found. The kernel is rotated before 3120ec9ace44c23c302f336f6e672f6857312747d29bcristy use, so kernel distances match resulting distances, when a user 3121ec9ace44c23c302f336f6e672f6857312747d29bcristy provided asymmetric kernel is applied. 31226fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3123ec9ace44c23c302f336f6e672f6857312747d29bcristy This code is nearly identical to True GrayScale Morphology but 3124ec9ace44c23c302f336f6e672f6857312747d29bcristy not quite. 31256fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3126ec9ace44c23c302f336f6e672f6857312747d29bcristy GreyDilate Kernel values added, maximum value found Kernel is 3127ec9ace44c23c302f336f6e672f6857312747d29bcristy rotated before use. 31286fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3129ec9ace44c23c302f336f6e672f6857312747d29bcristy GrayErode: Kernel values subtracted and minimum value found No 3130ec9ace44c23c302f336f6e672f6857312747d29bcristy kernel rotation used. 31316fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 3132ec9ace44c23c302f336f6e672f6857312747d29bcristy Note the the Iterative Distance method is essentially a 3133ec9ace44c23c302f336f6e672f6857312747d29bcristy GrayErode, but with negative kernel values, and kernel rotation 3134ec9ace44c23c302f336f6e672f6857312747d29bcristy applied. 3135930be614b4595b97cd79ee864a394796740f76adanthony */ 3136ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 3137ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < (ssize_t) kernel->height; v++) 3138ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3139ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3140ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3141a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3142ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3143ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3144ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3145ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3146ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3147ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3148602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3149b772effec6594fbd2b304bb685cfa6226f48780bcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3150602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3151602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3152ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3153ec9ace44c23c302f336f6e672f6857312747d29bcristy case UndefinedMorphology: 3154ec9ace44c23c302f336f6e672f6857312747d29bcristy default: 3155ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 3156ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3157ec9ace44c23c302f336f6e672f6857312747d29bcristy if (fabs(pixel-p[center+i]) > MagickEpsilon) 3158c5876076825b539bd230ddadab1d876805c18291cristy changes[id]++; 3159ec9ace44c23c302f336f6e672f6857312747d29bcristy SetPixelChannel(morphology_image,channel,ClampToQuantum(pixel),q); 316083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 3161ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p+=GetPixelChannels(image); 3162ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(morphology_image); 3163ec9ace44c23c302f336f6e672f6857312747d29bcristy } 31644c08aed51c5899665ade97263692328eea4af106cristy if ( SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 3165602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 3166602ab9b30b644a78a4057da93d838a77391ec0acanthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 3167602ab9b30b644a78a4057da93d838a77391ec0acanthony { 3168602ab9b30b644a78a4057da93d838a77391ec0acanthony MagickBooleanType 3169602ab9b30b644a78a4057da93d838a77391ec0acanthony proceed; 3170602ab9b30b644a78a4057da93d838a77391ec0acanthony 3171602ab9b30b644a78a4057da93d838a77391ec0acanthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 3172954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy #pragma omp critical (MagickCore_MorphologyPrimitive) 3173602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 3174602ab9b30b644a78a4057da93d838a77391ec0acanthony proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows); 3175602ab9b30b644a78a4057da93d838a77391ec0acanthony if (proceed == MagickFalse) 3176602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 3177602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3178ec9ace44c23c302f336f6e672f6857312747d29bcristy } 31794c08aed51c5899665ade97263692328eea4af106cristy morphology_view=DestroyCacheView(morphology_view); 31804c08aed51c5899665ade97263692328eea4af106cristy image_view=DestroyCacheView(image_view); 3181c5876076825b539bd230ddadab1d876805c18291cristy for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++) 3182c5876076825b539bd230ddadab1d876805c18291cristy changed+=changes[i]; 3183306b0f1c3332736bfaddd94c5aaff078a69cbac3cristy changes=(size_t *) RelinquishMagickMemory(changes); 3184c5876076825b539bd230ddadab1d876805c18291cristy return(status ? (ssize_t) changed : -1); 3185602ab9b30b644a78a4057da93d838a77391ec0acanthony} 3186602ab9b30b644a78a4057da93d838a77391ec0acanthony 3187ec9ace44c23c302f336f6e672f6857312747d29bcristy/* 3188ec9ace44c23c302f336f6e672f6857312747d29bcristy This is almost identical to the MorphologyPrimative() function above, but 3189ec9ace44c23c302f336f6e672f6857312747d29bcristy applies the primitive directly to the actual image using two passes, once in 3190ec9ace44c23c302f336f6e672f6857312747d29bcristy each direction, with the results of the previous (and current) row being 3191ec9ace44c23c302f336f6e672f6857312747d29bcristy re-used. 3192ec9ace44c23c302f336f6e672f6857312747d29bcristy 3193ec9ace44c23c302f336f6e672f6857312747d29bcristy That is after each row is 'Sync'ed' into the image, the next row makes use of 3194ec9ace44c23c302f336f6e672f6857312747d29bcristy those values as part of the calculation of the next row. It repeats, but 3195ec9ace44c23c302f336f6e672f6857312747d29bcristy going in the oppisite (bottom-up) direction. 3196ec9ace44c23c302f336f6e672f6857312747d29bcristy 3197ec9ace44c23c302f336f6e672f6857312747d29bcristy Because of this 're-use of results' this function can not make use of multi- 3198ec9ace44c23c302f336f6e672f6857312747d29bcristy threaded, parellel processing. 3199a8843c1f815ffad2568ec592d5b446cb1476aab5anthony*/ 3200e698a255629ba03cd125572de7b35b5e21c4ee5danthonystatic ssize_t MorphologyPrimitiveDirect(Image *image, 3201f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method,const KernelInfo *kernel, 3202f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 3203a8843c1f815ffad2568ec592d5b446cb1476aab5anthony{ 3204a8843c1f815ffad2568ec592d5b446cb1476aab5anthony CacheView 3205ec9ace44c23c302f336f6e672f6857312747d29bcristy *morphology_view, 3206ec9ace44c23c302f336f6e672f6857312747d29bcristy *image_view; 3207a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3208a8843c1f815ffad2568ec592d5b446cb1476aab5anthony MagickBooleanType 3209a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status; 3210a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3211a8843c1f815ffad2568ec592d5b446cb1476aab5anthony MagickOffsetType 3212a8843c1f815ffad2568ec592d5b446cb1476aab5anthony progress; 3213a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3214ec9ace44c23c302f336f6e672f6857312747d29bcristy OffsetInfo 3215ec9ace44c23c302f336f6e672f6857312747d29bcristy offset; 3216a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3217a8843c1f815ffad2568ec592d5b446cb1476aab5anthony size_t 3218ec9ace44c23c302f336f6e672f6857312747d29bcristy width, 3219a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed; 3220a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3221ec9ace44c23c302f336f6e672f6857312747d29bcristy ssize_t 3222ec9ace44c23c302f336f6e672f6857312747d29bcristy y; 3223a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3224a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(image != (Image *) NULL); 3225a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(image->signature == MagickSignature); 3226a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(kernel != (KernelInfo *) NULL); 3227a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(kernel->signature == MagickSignature); 3228a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(exception != (ExceptionInfo *) NULL); 3229a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(exception->signature == MagickSignature); 3230ec9ace44c23c302f336f6e672f6857312747d29bcristy status=MagickTrue; 3231ec9ace44c23c302f336f6e672f6857312747d29bcristy changed=0; 3232ec9ace44c23c302f336f6e672f6857312747d29bcristy progress=0; 3233ec9ace44c23c302f336f6e672f6857312747d29bcristy switch(method) 3234ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3235a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3236e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3237ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3238ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3239ec9ace44c23c302f336f6e672f6857312747d29bcristy Kernel reflected about origin. 3240ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 3241ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.x=(ssize_t) kernel->width-kernel->x-1; 3242ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.y=(ssize_t) kernel->height-kernel->y-1; 3243a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3244ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3245a8843c1f815ffad2568ec592d5b446cb1476aab5anthony default: 3246ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3247ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.x=kernel->x; 3248ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.y=kernel->y; 3249a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3250ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3251a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3252ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3253ec9ace44c23c302f336f6e672f6857312747d29bcristy Two views into same image, do not thread. 3254ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 3255ec9ace44c23c302f336f6e672f6857312747d29bcristy image_view=AcquireVirtualCacheView(image,exception); 3256ec9ace44c23c302f336f6e672f6857312747d29bcristy morphology_view=AcquireAuthenticCacheView(image,exception); 3257ec9ace44c23c302f336f6e672f6857312747d29bcristy width=image->columns+kernel->width-1; 3258a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (y=0; y < (ssize_t) image->rows; y++) 3259a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 32604c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3261a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict p; 3262a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 32634c08aed51c5899665ade97263692328eea4af106cristy register Quantum 3264a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict q; 3265a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3266a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register ssize_t 3267a8843c1f815ffad2568ec592d5b446cb1476aab5anthony x; 3268a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 326927be28f6ee6dcb0c20268851b6359b50fbee71fbcristy ssize_t 327027be28f6ee6dcb0c20268851b6359b50fbee71fbcristy center; 327127be28f6ee6dcb0c20268851b6359b50fbee71fbcristy 3272ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3273ec9ace44c23c302f336f6e672f6857312747d29bcristy Read virtual pixels, and authentic pixels, from the same image! We read 3274ec9ace44c23c302f336f6e672f6857312747d29bcristy using virtual to get virtual pixel handling, but write back into the same 3275ec9ace44c23c302f336f6e672f6857312747d29bcristy image. 3276ec9ace44c23c302f336f6e672f6857312747d29bcristy 3277ec9ace44c23c302f336f6e672f6857312747d29bcristy Only top half of kernel is processed as we do a single pass downward 3278ec9ace44c23c302f336f6e672f6857312747d29bcristy through the image iterating the distance function as we go. 3279a8843c1f815ffad2568ec592d5b446cb1476aab5anthony */ 3280a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (status == MagickFalse) 3281954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy continue; 3282ec9ace44c23c302f336f6e672f6857312747d29bcristy p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width,(size_t) 3283ec9ace44c23c302f336f6e672f6857312747d29bcristy offset.y+1,exception); 32846fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1, 32854c08aed51c5899665ade97263692328eea4af106cristy exception); 32864c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 3287954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy { 3288954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy status=MagickFalse; 3289954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy continue; 3290954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy } 329127be28f6ee6dcb0c20268851b6359b50fbee71fbcristy center=(ssize_t) (GetPixelChannels(image)*width*offset.y+ 329227be28f6ee6dcb0c20268851b6359b50fbee71fbcristy GetPixelChannels(image)*offset.x); 3293a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (x=0; x < (ssize_t) image->columns; x++) 3294a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 3295ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 3296ec9ace44c23c302f336f6e672f6857312747d29bcristy i; 3297a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3298ec9ace44c23c302f336f6e672f6857312747d29bcristy for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 3299ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3300ec9ace44c23c302f336f6e672f6857312747d29bcristy double 3301ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel; 3302a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3303ec9ace44c23c302f336f6e672f6857312747d29bcristy PixelTrait 3304ec9ace44c23c302f336f6e672f6857312747d29bcristy traits; 3305ec9ace44c23c302f336f6e672f6857312747d29bcristy 3306ec9ace44c23c302f336f6e672f6857312747d29bcristy register const MagickRealType 3307ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict k; 3308ec9ace44c23c302f336f6e672f6857312747d29bcristy 3309ec9ace44c23c302f336f6e672f6857312747d29bcristy register const Quantum 3310ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict pixels; 3311ec9ace44c23c302f336f6e672f6857312747d29bcristy 3312ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 3313ec9ace44c23c302f336f6e672f6857312747d29bcristy u; 3314ec9ace44c23c302f336f6e672f6857312747d29bcristy 3315ec9ace44c23c302f336f6e672f6857312747d29bcristy ssize_t 3316ec9ace44c23c302f336f6e672f6857312747d29bcristy v; 3317ec9ace44c23c302f336f6e672f6857312747d29bcristy 33186fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy traits=GetPixelChannelTraits(image,i); 3319ec9ace44c23c302f336f6e672f6857312747d29bcristy if (traits == UndefinedPixelTrait) 3320ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 332127be28f6ee6dcb0c20268851b6359b50fbee71fbcristy if (((traits & CopyPixelTrait) != 0) || 3322883fde11debec15cedb05dc5d7228d8588066bc0cristy (GetPixelReadMask(image,p+center) == 0)) 3323ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 3324ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=p; 332527be28f6ee6dcb0c20268851b6359b50fbee71fbcristy pixel=(double) QuantumRange; 3326ec9ace44c23c302f336f6e672f6857312747d29bcristy switch (method) 3327ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3328ec9ace44c23c302f336f6e672f6857312747d29bcristy case DistanceMorphology: 3329ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3330ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 3331ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v <= offset.y; v++) 3332ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3333ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3334ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3335a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3336e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3337ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3338ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3339e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3340ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3341ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3342e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3343cfb71b157cd8f18b2e595d0a4a7c3c9403d8014dcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3344ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3345ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*(kernel->y+1)-1]); 3346ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=q-offset.x*GetPixelChannels(image); 3347ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < offset.x; u++) 3348ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3349a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && ((x+u-offset.x) >= 0)) 3350ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3351ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3352ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3353ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3354ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3355ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3356e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3357ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 3358ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3359ec9ace44c23c302f336f6e672f6857312747d29bcristy case VoronoiMorphology: 3360ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3361ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->height-1]); 3362ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=0; v < offset.y; v++) 3363ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3364ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3365ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3366a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3367e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3368ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3369ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3370e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3371ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3372ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3373e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3374cfb71b157cd8f18b2e595d0a4a7c3c9403d8014dcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3375ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3376ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*(kernel->y+1)-1]); 3377ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=q-offset.x*GetPixelChannels(image); 3378ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < offset.x; u++) 3379ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3380a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && ((x+u-offset.x) >= 0)) 3381ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3382ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3383ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3384ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3385ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3386ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3387ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3388e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3389ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3390ec9ace44c23c302f336f6e672f6857312747d29bcristy default: 3391ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 3392ec9ace44c23c302f336f6e672f6857312747d29bcristy } 33936fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (fabs(pixel-q[i]) > MagickEpsilon) 3394ec9ace44c23c302f336f6e672f6857312747d29bcristy changed++; 33956fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy q[i]=ClampToQuantum(pixel); 3396e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3397ec9ace44c23c302f336f6e672f6857312747d29bcristy p+=GetPixelChannels(image); 3398ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(image); 3399ec9ace44c23c302f336f6e672f6857312747d29bcristy } 34006fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 3401a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3402a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 3403ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3404ec9ace44c23c302f336f6e672f6857312747d29bcristy MagickBooleanType 3405ec9ace44c23c302f336f6e672f6857312747d29bcristy proceed; 3406a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 34076fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy proceed=SetImageProgress(image,MorphologyTag,progress++,2*image->rows); 3408ec9ace44c23c302f336f6e672f6857312747d29bcristy if (proceed == MagickFalse) 3409ec9ace44c23c302f336f6e672f6857312747d29bcristy status=MagickFalse; 3410ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3411ec9ace44c23c302f336f6e672f6857312747d29bcristy } 34126fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy morphology_view=DestroyCacheView(morphology_view); 34136fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy image_view=DestroyCacheView(image_view); 3414ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3415ec9ace44c23c302f336f6e672f6857312747d29bcristy Do the reverse pass through the image. 3416ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 34176fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy image_view=AcquireVirtualCacheView(image,exception); 34186fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy morphology_view=AcquireAuthenticCacheView(image,exception); 3419ec9ace44c23c302f336f6e672f6857312747d29bcristy for (y=(ssize_t) image->rows-1; y >= 0; y--) 3420a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 34214c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3422a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict p; 3423a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 34244c08aed51c5899665ade97263692328eea4af106cristy register Quantum 3425a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict q; 3426a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3427a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register ssize_t 3428a8843c1f815ffad2568ec592d5b446cb1476aab5anthony x; 3429a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 343027be28f6ee6dcb0c20268851b6359b50fbee71fbcristy ssize_t 343127be28f6ee6dcb0c20268851b6359b50fbee71fbcristy center; 343227be28f6ee6dcb0c20268851b6359b50fbee71fbcristy 3433ec9ace44c23c302f336f6e672f6857312747d29bcristy /* 3434ec9ace44c23c302f336f6e672f6857312747d29bcristy Read virtual pixels, and authentic pixels, from the same image. We 3435ec9ace44c23c302f336f6e672f6857312747d29bcristy read using virtual to get virtual pixel handling, but write back 3436ec9ace44c23c302f336f6e672f6857312747d29bcristy into the same image. 3437a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3438ec9ace44c23c302f336f6e672f6857312747d29bcristy Only the bottom half of the kernel is processed as we up the image. 3439ec9ace44c23c302f336f6e672f6857312747d29bcristy */ 3440db60568e12574785101a4ae8d8da076227a0a889anthony if (status == MagickFalse) 3441954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy continue; 3442ec9ace44c23c302f336f6e672f6857312747d29bcristy p=GetCacheViewVirtualPixels(image_view,-offset.x,y,width,(size_t) 34434c08aed51c5899665ade97263692328eea4af106cristy kernel->y+1,exception); 34446fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1, 34454c08aed51c5899665ade97263692328eea4af106cristy exception); 34464c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 3447954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy { 3448954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy status=MagickFalse; 3449954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy continue; 3450954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy } 3451ec9ace44c23c302f336f6e672f6857312747d29bcristy p+=(image->columns-1)*GetPixelChannels(image); 3452ec9ace44c23c302f336f6e672f6857312747d29bcristy q+=(image->columns-1)*GetPixelChannels(image); 345327be28f6ee6dcb0c20268851b6359b50fbee71fbcristy center=(ssize_t) (offset.x*GetPixelChannels(image)); 34546fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy for (x=(ssize_t) image->columns-1; x >= 0; x--) 3455ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3456ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 3457ec9ace44c23c302f336f6e672f6857312747d29bcristy i; 3458a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3459ec9ace44c23c302f336f6e672f6857312747d29bcristy for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 3460ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3461ec9ace44c23c302f336f6e672f6857312747d29bcristy double 3462ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel; 3463a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3464ec9ace44c23c302f336f6e672f6857312747d29bcristy PixelTrait 3465ec9ace44c23c302f336f6e672f6857312747d29bcristy traits; 3466a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3467ec9ace44c23c302f336f6e672f6857312747d29bcristy register const MagickRealType 3468ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict k; 3469a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3470ec9ace44c23c302f336f6e672f6857312747d29bcristy register const Quantum 3471ec9ace44c23c302f336f6e672f6857312747d29bcristy *restrict pixels; 3472a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3473ec9ace44c23c302f336f6e672f6857312747d29bcristy register ssize_t 3474ec9ace44c23c302f336f6e672f6857312747d29bcristy u; 3475ec9ace44c23c302f336f6e672f6857312747d29bcristy 3476ec9ace44c23c302f336f6e672f6857312747d29bcristy ssize_t 3477ec9ace44c23c302f336f6e672f6857312747d29bcristy v; 3478ec9ace44c23c302f336f6e672f6857312747d29bcristy 34796fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy traits=GetPixelChannelTraits(image,i); 3480ec9ace44c23c302f336f6e672f6857312747d29bcristy if (traits == UndefinedPixelTrait) 3481ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 348227be28f6ee6dcb0c20268851b6359b50fbee71fbcristy if (((traits & CopyPixelTrait) != 0) || 3483883fde11debec15cedb05dc5d7228d8588066bc0cristy (GetPixelReadMask(image,p+center) == 0)) 3484ec9ace44c23c302f336f6e672f6857312747d29bcristy continue; 3485ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=p; 348627be28f6ee6dcb0c20268851b6359b50fbee71fbcristy pixel=(double) QuantumRange; 3487ec9ace44c23c302f336f6e672f6857312747d29bcristy switch (method) 3488ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3489ec9ace44c23c302f336f6e672f6857312747d29bcristy case DistanceMorphology: 3490ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3491ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*(kernel->y+1)-1]); 3492ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=offset.y; v < (ssize_t) kernel->height; v++) 3493ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3494ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3495ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3496a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3497e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3498ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3499ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3500e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3501ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3502ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3503e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 350427be28f6ee6dcb0c20268851b6359b50fbee71fbcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3505e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3506ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*kernel->y+kernel->x-1]); 3507ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=q-offset.x*GetPixelChannels(image); 3508ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=offset.x+1; u < (ssize_t) kernel->width; u++) 3509ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3510a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && 35116fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy ((x+u-offset.x) < (ssize_t) image->columns)) 3512ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3513ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3514ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3515ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3516ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3517ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3518ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3519ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 3520ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3521ec9ace44c23c302f336f6e672f6857312747d29bcristy case VoronoiMorphology: 3522ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3523ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*(kernel->y+1)-1]); 3524ec9ace44c23c302f336f6e672f6857312747d29bcristy for (v=offset.y; v < (ssize_t) kernel->height; v++) 3525ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3526ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=0; u < (ssize_t) kernel->width; u++) 3527ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3528a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if (IfNaN(*k) == MagickFalse) 3529e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3530ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3531ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3532e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3533ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3534ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3535e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 353627be28f6ee6dcb0c20268851b6359b50fbee71fbcristy pixels+=(image->columns-1)*GetPixelChannels(image); 3537ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3538ec9ace44c23c302f336f6e672f6857312747d29bcristy k=(&kernel->values[kernel->width*(kernel->y+1)-1]); 3539ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels=q-offset.x*GetPixelChannels(image); 3540ec9ace44c23c302f336f6e672f6857312747d29bcristy for (u=offset.x+1; u < (ssize_t) kernel->width; u++) 3541ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3542a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ((IfNaN(*k) == MagickFalse) && 35436fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy ((x+u-offset.x) < (ssize_t) image->columns)) 3544ec9ace44c23c302f336f6e672f6857312747d29bcristy { 3545ec9ace44c23c302f336f6e672f6857312747d29bcristy if ((pixels[i]+(*k)) < pixel) 3546ec9ace44c23c302f336f6e672f6857312747d29bcristy pixel=(double) pixels[i]+(*k); 3547ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3548ec9ace44c23c302f336f6e672f6857312747d29bcristy k--; 3549ec9ace44c23c302f336f6e672f6857312747d29bcristy pixels+=GetPixelChannels(image); 3550ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3551e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3552ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3553ec9ace44c23c302f336f6e672f6857312747d29bcristy default: 3554ec9ace44c23c302f336f6e672f6857312747d29bcristy break; 3555ec9ace44c23c302f336f6e672f6857312747d29bcristy } 35566fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (fabs(pixel-q[i]) > MagickEpsilon) 3557ec9ace44c23c302f336f6e672f6857312747d29bcristy changed++; 35586fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy q[i]=ClampToQuantum(pixel); 3559e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 35606fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy p-=GetPixelChannels(image); 35616fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy q-=GetPixelChannels(image); 3562ec9ace44c23c302f336f6e672f6857312747d29bcristy } 35636fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 35646fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy status=MagickFalse; 35656fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (image->progress_monitor != (MagickProgressMonitor) NULL) 35666fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy { 35676fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy MagickBooleanType 35686fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy proceed; 35696fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy 35706fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy proceed=SetImageProgress(image,MorphologyTag,progress++,2*image->rows); 35716fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy if (proceed == MagickFalse) 35726fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy status=MagickFalse; 35736fb2996ae0b3c4bf65026ac78a8890bfb8a494d7cristy } 3574ec9ace44c23c302f336f6e672f6857312747d29bcristy } 3575ec9ace44c23c302f336f6e672f6857312747d29bcristy morphology_view=DestroyCacheView(morphology_view); 3576ec9ace44c23c302f336f6e672f6857312747d29bcristy image_view=DestroyCacheView(image_view); 3577aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy return(status ? (ssize_t) changed : -1); 3578a8843c1f815ffad2568ec592d5b446cb1476aab5anthony} 3579a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3580ec9ace44c23c302f336f6e672f6857312747d29bcristy/* 3581ec9ace44c23c302f336f6e672f6857312747d29bcristy Apply a Morphology by calling one of the above low level primitive 3582ec9ace44c23c302f336f6e672f6857312747d29bcristy application functions. This function handles any iteration loops, 3583ec9ace44c23c302f336f6e672f6857312747d29bcristy composition or re-iteration of results, and compound morphology methods that 3584ec9ace44c23c302f336f6e672f6857312747d29bcristy is based on multiple low-level (staged) morphology methods. 3585ec9ace44c23c302f336f6e672f6857312747d29bcristy 3586ec9ace44c23c302f336f6e672f6857312747d29bcristy Basically this provides the complex glue between the requested morphology 3587ec9ace44c23c302f336f6e672f6857312747d29bcristy method and raw low-level implementation (above). 3588a8843c1f815ffad2568ec592d5b446cb1476aab5anthony*/ 3589cf592636b16d028b14c5fa9dffdc3a94eae7c2f3cristyMagickPrivate Image *MorphologyApply(const Image *image, 3590f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method, const ssize_t iterations, 3591f46d42620631d2581e0b6a56456e203e17c427c8anthony const KernelInfo *kernel, const CompositeOperator compose,const double bias, 3592f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 3593602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 35941cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy CompositeOperator 35951cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy curr_compose; 35961cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy 3597602ab9b30b644a78a4057da93d838a77391ec0acanthony Image 359847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *curr_image, /* Image we are working with or iterating */ 3599a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *work_image, /* secondary image for primitive iteration */ 360047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *save_image, /* saved image - for 'edge' method only */ 360147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *rslt_image; /* resultant image - after multi-kernel handling */ 3602602ab9b30b644a78a4057da93d838a77391ec0acanthony 36034fd27e21043be809d66c8202e779255e5b660d2danthony KernelInfo 360447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *reflected_kernel, /* A reflected copy of the kernel (if needed) */ 360547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *norm_kernel, /* the current normal un-reflected kernel */ 360647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *rflt_kernel, /* the current reflected kernel (if needed) */ 360747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *this_kernel; /* the kernel being applied */ 36084fd27e21043be809d66c8202e779255e5b660d2danthony 36094fd27e21043be809d66c8202e779255e5b660d2danthony MorphologyMethod 3610a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive; /* the current morphology primitive being applied */ 36119eb4f74649b23c053b308ce1152dce51239450baanthony 36129eb4f74649b23c053b308ce1152dce51239450baanthony CompositeOperator 361347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose; /* multi-kernel compose method for results to use */ 361447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 361547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony MagickBooleanType 3616e698a255629ba03cd125572de7b35b5e21c4ee5danthony special, /* do we use a direct modify function? */ 361747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony verbose; /* verbose output of results */ 36184fd27e21043be809d66c8202e779255e5b660d2danthony 3619bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 3620a8843c1f815ffad2568ec592d5b446cb1476aab5anthony method_loop, /* Loop 1: number of compound method iterations (norm 1) */ 362147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_limit, /* maximum number of compound method iterations */ 362247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number, /* Loop 2: the kernel number being applied */ 3623a8843c1f815ffad2568ec592d5b446cb1476aab5anthony stage_loop, /* Loop 3: primitive loop for compound morphology */ 3624a8843c1f815ffad2568ec592d5b446cb1476aab5anthony stage_limit, /* how many primitives are in this compound */ 3625a8843c1f815ffad2568ec592d5b446cb1476aab5anthony kernel_loop, /* Loop 4: iterate the kernel over image */ 362647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_limit, /* number of times to iterate kernel */ 3627a8843c1f815ffad2568ec592d5b446cb1476aab5anthony count, /* total count of primitive steps applied */ 362847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_changed, /* total count of changed using iterated kernel */ 362947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed; /* total count of changed over method iteration */ 363047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 3631a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3632a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed; /* number pixels changed by last primitive operation */ 3633a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 363447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony char 363547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony v_info[80]; 36361b2bc0a7da432e6e1cc0480280402df213faa940anthony 3637602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(image != (Image *) NULL); 3638602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(image->signature == MagickSignature); 36394fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel != (KernelInfo *) NULL); 36404fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel->signature == MagickSignature); 3641602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(exception != (ExceptionInfo *) NULL); 3642602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(exception->signature == MagickSignature); 3643602ab9b30b644a78a4057da93d838a77391ec0acanthony 3644a8843c1f815ffad2568ec592d5b446cb1476aab5anthony count = 0; /* number of low-level morphology primitives performed */ 3645602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( iterations == 0 ) 364647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return((Image *)NULL); /* null operation - nothing to do! */ 3647602ab9b30b644a78a4057da93d838a77391ec0acanthony 3648bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel_limit = (size_t) iterations; 364947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( iterations < 0 ) /* negative interations = infinite (well alomst) */ 3650e698a255629ba03cd125572de7b35b5e21c4ee5danthony kernel_limit = image->columns>image->rows ? image->columns : image->rows; 365128ad1d779b6ca95852e860514185a7a97e06af77anthony 36526f2013165d72f7d8ef5f66bb9453126d88113809anthony verbose = IsStringTrue(GetImageArtifact(image,"verbose")); 36534f1dcb76c95ef6410f2957ca9e7e1d391cee0d02anthony 36549eb4f74649b23c053b308ce1152dce51239450baanthony /* initialise for cleanup */ 365547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; 36561cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy curr_compose = image->compose; 3657aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy (void) curr_compose; 365847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = save_image = rslt_image = (Image *) NULL; 365947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = (KernelInfo *) NULL; 36604fd27e21043be809d66c8202e779255e5b660d2danthony 366147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Initialize specific methods 366247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony * + which loop should use the given iteratations 3663a8843c1f815ffad2568ec592d5b446cb1476aab5anthony * + how many primitives make up the compound morphology 366447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony * + multi-kernel compose method to use (by default) 366547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 366647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_limit = 1; /* just do method once, unless otherwise set */ 3667ea61f01656bb0f9074677452017cc559e54093faanthony stage_limit = 1; /* assume method is not a compound */ 36684ee950098ad0166bbbc85c3a59bc079cd321384aglennrp special = MagickFalse; /* assume it is NOT a direct modify primitive */ 366947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = compose; /* and we are composing multi-kernels as given */ 36709eb4f74649b23c053b308ce1152dce51239450baanthony switch( method ) { 3671a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case SmoothMorphology: /* 4 primitive compound morphology */ 367247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_limit = 4; 3673602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3674a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case OpenMorphology: /* 2 primitive compound morphology */ 3675930be614b4595b97cd79ee864a394796740f76adanthony case OpenIntensityMorphology: 367647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: 367747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: 36784fd27e21043be809d66c8202e779255e5b660d2danthony case CloseIntensityMorphology: 367947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 368047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: 368147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_limit = 2; 3682602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 36839eb4f74649b23c053b308ce1152dce51239450baanthony case HitAndMissMorphology: 368447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = LightenCompositeOp; /* Union of multi-kernel results */ 36853ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony /* FALL THUR */ 3686c3e48258f3253188894e783dcdfd03562f7ab2c5anthony case ThinningMorphology: 36879eb4f74649b23c053b308ce1152dce51239450baanthony case ThickenMorphology: 36883ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony method_limit = kernel_limit; /* iterate the whole method */ 3689c3e48258f3253188894e783dcdfd03562f7ab2c5anthony kernel_limit = 1; /* do not do kernel iteration */ 369047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 3691a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3692e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3693f34d9b2df49a407af764c79e07d587af0600983aanthony special = MagickTrue; /* use special direct primative */ 3694a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 369547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 36969eb4f74649b23c053b308ce1152dce51239450baanthony break; 36979eb4f74649b23c053b308ce1152dce51239450baanthony } 3698602ab9b30b644a78a4057da93d838a77391ec0acanthony 3699e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Apply special methods with special requirments 3700e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** For example, single run only, or post-processing requirements 3701e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 3702e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( special == MagickTrue ) 3703e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3704e698a255629ba03cd125572de7b35b5e21c4ee5danthony rslt_image=CloneImage(image,0,0,MagickTrue,exception); 3705e698a255629ba03cd125572de7b35b5e21c4ee5danthony if (rslt_image == (Image *) NULL) 3706e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto error_cleanup; 3707574cc26500992189f637cd1cdf93d0654e7df7aecristy if (SetImageStorageClass(rslt_image,DirectClass,exception) == MagickFalse) 3708574cc26500992189f637cd1cdf93d0654e7df7aecristy goto error_cleanup; 3709e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3710a325e90b7583eab5e70f0ceebb8257670e652f0fcristy changed=MorphologyPrimitiveDirect(rslt_image,method,kernel,exception); 3711e698a255629ba03cd125572de7b35b5e21c4ee5danthony 37127bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 37135acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) (void) FormatLocaleFile(stderr, 37141e604812fad85bb96f757a2393015ae3d061c39acristy "%s:%.20g.%.20g #%.20g => Changed %.20g\n", 37151e604812fad85bb96f757a2393015ae3d061c39acristy CommandOptionToMnemonic(MagickMorphologyOptions, method), 37161e604812fad85bb96f757a2393015ae3d061c39acristy 1.0,0.0,1.0, (double) changed); 3717e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3718e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( changed < 0 ) 3719e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto error_cleanup; 3720e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3721e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( method == VoronoiMorphology ) { 3722a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony /* Preserve the alpha channel of input image - but turned it off */ 372363240888c3975789a09c2494a4654b523931df96cristy (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel, 372463240888c3975789a09c2494a4654b523931df96cristy exception); 3725feb3e9695150978a5d2372d3fe2f60466a7c8066cristy (void) CompositeImage(rslt_image,image,CopyAlphaCompositeOp, 372639172408bad7ef2ef00a815fa9abf9979e7857cbcristy MagickTrue,0,0,exception); 372763240888c3975789a09c2494a4654b523931df96cristy (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel, 372863240888c3975789a09c2494a4654b523931df96cristy exception); 3729e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3730e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto exit_cleanup; 3731e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3732e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3733c3e48258f3253188894e783dcdfd03562f7ab2c5anthony /* Handle user (caller) specified multi-kernel composition method */ 373447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( compose != UndefinedCompositeOp ) 373547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = compose; /* override default composition for method */ 373647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rslt_compose == UndefinedCompositeOp ) 373747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = NoCompositeOp; /* still not defined! Then re-iterate */ 37384fd27e21043be809d66c8202e779255e5b660d2danthony 3739a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Some methods require a reflected kernel to use with primitives. 3740c3e48258f3253188894e783dcdfd03562f7ab2c5anthony * Create the reflected kernel for those methods. */ 374147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch ( method ) { 374247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CorrelateMorphology: 374347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: 374447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseIntensityMorphology: 374547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 374647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case SmoothMorphology: 374747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = CloneKernelInfo(kernel); 374847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if (reflected_kernel == (KernelInfo *) NULL) 374947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony goto error_cleanup; 375047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony RotateKernelInfo(reflected_kernel,180); 375147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 375247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 375347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 375447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 3755602ab9b30b644a78a4057da93d838a77391ec0acanthony 3756e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Loops around more primitive morpholgy methods 3757e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** erose, dilate, open, close, smooth, edge, etc... 3758e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 375947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 1: iterate the compound method */ 376047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_loop = 0; 376147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed = 1; 376247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( method_loop < method_limit && method_changed > 0 ) { 376347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_loop++; 376447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed = 0; 376547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 376647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 2: iterate over each kernel in a multi-kernel list */ 376747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony norm_kernel = (KernelInfo *) kernel; 3768f2faecf9facdbbb14fcba373365f9f691a9658e0cristy this_kernel = (KernelInfo *) kernel; 376947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rflt_kernel = reflected_kernel; 3770e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony 377147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number = 0; 377247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( norm_kernel != NULL ) { 377347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 377447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 3: Compound Morphology Staging - Select Primative to apply */ 377547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_loop = 0; /* the compound morphology stage number */ 377647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( stage_loop < stage_limit ) { 377747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_loop++; /* The stage of the compound morphology */ 377847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 3779a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Select primitive morphology for this stage of compound method */ 378047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = norm_kernel; /* default use unreflected kernel */ 3781a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = method; /* Assume method is a primitive */ 378247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch( method ) { 378347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case ErodeMorphology: /* just erode */ 378447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeInMorphology: /* erode and image difference */ 3785a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 378647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 378747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case DilateMorphology: /* just dilate */ 378847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeOutMorphology: /* dilate and image difference */ 3789a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 379047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 379147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case OpenMorphology: /* erode then dialate */ 379247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: /* open and image difference */ 3793a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 379447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3795a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 379647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 379747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case OpenIntensityMorphology: 3798a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeIntensityMorphology; 379947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3800a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateIntensityMorphology; 3801e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony break; 380247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: /* dilate, then erode */ 380347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: /* close and image difference */ 380447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3805a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 380647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3807a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 380847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 380947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseIntensityMorphology: 381047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3811a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateIntensityMorphology; 381247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3813a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeIntensityMorphology; 381447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 381547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case SmoothMorphology: /* open, close */ 381647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch ( stage_loop ) { 381747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 1: /* start an open method, which starts with Erode */ 3818a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 381947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 382047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 2: /* now Dilate the Erode */ 3821a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 382247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 382347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 3: /* Reflect kernel a close */ 382447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3825a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 382647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 382747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 4: /* Finish the Close */ 382847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3829a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 383047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 383147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 383247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 383347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: /* dilate and erode difference */ 3834a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 383547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) { 383647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = curr_image; /* save the image difference */ 383747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; 3838a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 383947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 384047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 384147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CorrelateMorphology: 384247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* A Correlation is a Convolution with a reflected kernel. 384347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** However a Convolution is a weighted sum using a reflected 384447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** kernel. It may seem stange to convert a Correlation into a 384547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Convolution as the Correlation is the simplier method, but 384647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Convolution is much more commonly used, and it makes sense to 384747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** implement it directly so as to avoid the need to duplicate the 384847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** kernel when it is not required (which is typically the 384947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** default). 385047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 385147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3852a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ConvolveMorphology; 385347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 385447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 385547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 385647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 3857e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert( this_kernel != (KernelInfo *) NULL ); 38587a01dcf50ce12cb2a789bedff51e9345f022432eanthony 385947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Extra information for debugging compound operations */ 38607bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) { 386147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_limit > 1 ) 3862b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy (void) FormatLocaleString(v_info,MaxTextExtent,"%s:%.20g.%.20g -> ", 3863042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickMorphologyOptions,method),(double) 3864e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy method_loop,(double) stage_loop); 3865a8843c1f815ffad2568ec592d5b446cb1476aab5anthony else if ( primitive != method ) 3866b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy (void) FormatLocaleString(v_info, MaxTextExtent, "%s:%.20g -> ", 3867042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickMorphologyOptions, method),(double) 3868e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy method_loop); 386947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else 387047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony v_info[0] = '\0'; 387147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 38729eb4f74649b23c053b308ce1152dce51239450baanthony 3873a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Loop 4: Iterate the kernel with primitive */ 387447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_loop = 0; 387547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_changed = 0; 387647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony changed = 1; 387747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( kernel_loop < kernel_limit && changed > 0 ) { 387847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_loop++; /* the iteration of this kernel */ 38799eb4f74649b23c053b308ce1152dce51239450baanthony 3880a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Create a clone as the destination image, if not yet defined */ 38819eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image == (Image *) NULL ) 38829eb4f74649b23c053b308ce1152dce51239450baanthony { 38839eb4f74649b23c053b308ce1152dce51239450baanthony work_image=CloneImage(image,0,0,MagickTrue,exception); 38849eb4f74649b23c053b308ce1152dce51239450baanthony if (work_image == (Image *) NULL) 38859eb4f74649b23c053b308ce1152dce51239450baanthony goto error_cleanup; 3886574cc26500992189f637cd1cdf93d0654e7df7aecristy if (SetImageStorageClass(work_image,DirectClass,exception) == MagickFalse) 3887574cc26500992189f637cd1cdf93d0654e7df7aecristy goto error_cleanup; 38889eb4f74649b23c053b308ce1152dce51239450baanthony } 38899eb4f74649b23c053b308ce1152dce51239450baanthony 3890501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* APPLY THE MORPHOLOGICAL PRIMITIVE (curr -> work) */ 38919eb4f74649b23c053b308ce1152dce51239450baanthony count++; 3892e698a255629ba03cd125572de7b35b5e21c4ee5danthony changed = MorphologyPrimitive(curr_image, work_image, primitive, 3893f46d42620631d2581e0b6a56456e203e17c427c8anthony this_kernel, bias, exception); 389447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 38957bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) { 389647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( kernel_loop > 1 ) 38975acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line from previous */ 38985acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) (void) FormatLocaleFile(stderr, 38991e604812fad85bb96f757a2393015ae3d061c39acristy "%s%s%s:%.20g.%.20g #%.20g => Changed %.20g", 3900042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy v_info,CommandOptionToMnemonic(MagickMorphologyOptions, 3901a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive),(this_kernel == rflt_kernel ) ? "*" : "", 3902e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy (double) (method_loop+kernel_loop-1),(double) kernel_number, 3903e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy (double) count,(double) changed); 390447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 3905a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( changed < 0 ) 3906a8843c1f815ffad2568ec592d5b446cb1476aab5anthony goto error_cleanup; 3907a325e90b7583eab5e70f0ceebb8257670e652f0fcristy #pragma omp flush(changed) 3908a8843c1f815ffad2568ec592d5b446cb1476aab5anthony kernel_changed += changed; 3909a8843c1f815ffad2568ec592d5b446cb1476aab5anthony method_changed += changed; 3910a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 39119eb4f74649b23c053b308ce1152dce51239450baanthony /* prepare next loop */ 39129eb4f74649b23c053b308ce1152dce51239450baanthony { Image *tmp = work_image; /* swap images for iteration */ 39139eb4f74649b23c053b308ce1152dce51239450baanthony work_image = curr_image; 39149eb4f74649b23c053b308ce1152dce51239450baanthony curr_image = tmp; 39159eb4f74649b23c053b308ce1152dce51239450baanthony } 39169eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image == image ) 391747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = (Image *) NULL; /* replace input 'image' */ 39189eb4f74649b23c053b308ce1152dce51239450baanthony 3919a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* End Loop 4: Iterate the kernel with primitive */ 39207a01dcf50ce12cb2a789bedff51e9345f022432eanthony 39217bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) && kernel_changed != (size_t)changed ) 39225acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " Total %.20g",(double) kernel_changed); 39237bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) && stage_loop < stage_limit ) 39245acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line before looping */ 39259eb4f74649b23c053b308ce1152dce51239450baanthony 392647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony#if 0 39275acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "--E-- image=0x%lx\n", (unsigned long)image); 39285acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " curr =0x%lx\n", (unsigned long)curr_image); 39295acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " work =0x%lx\n", (unsigned long)work_image); 39305acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " save =0x%lx\n", (unsigned long)save_image); 39315acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " union=0x%lx\n", (unsigned long)rslt_image); 393247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony#endif 39331b2bc0a7da432e6e1cc0480280402df213faa940anthony 393447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 3: Primative (staging) Loop for Coumpound Methods */ 39351b2bc0a7da432e6e1cc0480280402df213faa940anthony 393647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Final Post-processing for some Compound Methods 393747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** 393847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** The removal of any 'Sync' channel flag in the Image Compositon 393947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** below ensures the methematical compose method is applied in a 394047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** purely mathematical way, and only to the selected channels. 394147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Turn off SVG composition 'alpha blending'. 394247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 394347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch( method ) { 394447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeOutMorphology: 394547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeInMorphology: 394647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: 394747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 39487bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 3949e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy (void) FormatLocaleFile(stderr, 3950e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy "\n%s: Difference with original image",CommandOptionToMnemonic( 3951e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy MagickMorphologyOptions, method) ); 3952feb3e9695150978a5d2372d3fe2f60466a7c8066cristy (void) CompositeImage(curr_image,image,DifferenceCompositeOp, 395339172408bad7ef2ef00a815fa9abf9979e7857cbcristy MagickTrue,0,0,exception); 395447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 395547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: 39567bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 3957e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy (void) FormatLocaleFile(stderr, 3958e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy "\n%s: Difference of Dilate and Erode",CommandOptionToMnemonic( 3959e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy MagickMorphologyOptions, method) ); 3960feb3e9695150978a5d2372d3fe2f60466a7c8066cristy (void) CompositeImage(curr_image,save_image,DifferenceCompositeOp, 396139172408bad7ef2ef00a815fa9abf9979e7857cbcristy MagickTrue,0,0,exception); 396247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = DestroyImage(save_image); /* finished with save image */ 396347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 396447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 396547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 3966602ab9b30b644a78a4057da93d838a77391ec0acanthony } 39679eb4f74649b23c053b308ce1152dce51239450baanthony 396847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* multi-kernel handling: re-iterate, or compose results */ 396947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( kernel->next == (KernelInfo *) NULL ) 3970c3e48258f3253188894e783dcdfd03562f7ab2c5anthony rslt_image = curr_image; /* just return the resulting image */ 397147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else if ( rslt_compose == NoCompositeOp ) 39727bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony { if ( IfMagickTrue(verbose) ) { 3973c3e48258f3253188894e783dcdfd03562f7ab2c5anthony if ( this_kernel->next != (KernelInfo *) NULL ) 39745acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (re-iterate)"); 3975c3e48258f3253188894e783dcdfd03562f7ab2c5anthony else 39765acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (done)"); 3977c3e48258f3253188894e783dcdfd03562f7ab2c5anthony } 3978c3e48258f3253188894e783dcdfd03562f7ab2c5anthony rslt_image = curr_image; /* return result, and re-iterate */ 39799eb4f74649b23c053b308ce1152dce51239450baanthony } 398047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else if ( rslt_image == (Image *) NULL) 39817bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony { if ( IfMagickTrue(verbose) ) 39825acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (save for compose)"); 398347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_image = curr_image; 398447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; /* continue with original image */ 39859eb4f74649b23c053b308ce1152dce51239450baanthony } 398647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else 3987ea61f01656bb0f9074677452017cc559e54093faanthony { /* Add the new 'current' result to the composition 398847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** 398947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** The removal of any 'Sync' channel flag in the Image Compositon 399047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** below ensures the methematical compose method is applied in a 399147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** purely mathematical way, and only to the selected channels. 3992ea61f01656bb0f9074677452017cc559e54093faanthony ** IE: Turn off SVG composition 'alpha blending'. 399347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 39947bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 39955acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (compose \"%s\")", 3996feb3e9695150978a5d2372d3fe2f60466a7c8066cristy CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) ); 399739172408bad7ef2ef00a815fa9abf9979e7857cbcristy (void) CompositeImage(rslt_image,curr_image,rslt_compose,MagickTrue, 3998feb3e9695150978a5d2372d3fe2f60466a7c8066cristy 0,0,exception); 39990bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony curr_image = DestroyImage(curr_image); 400047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; /* continue with original image */ 400147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 40027bcfe7f0f9a0028eb9efdb79c842eb50e909dc45anthony if ( IfMagickTrue(verbose) ) 40035acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); 40044fd27e21043be809d66c8202e779255e5b660d2danthony 400547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* loop to the next kernel in a multi-kernel list */ 400647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony norm_kernel = norm_kernel->next; 400747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rflt_kernel != (KernelInfo *) NULL ) 400847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rflt_kernel = rflt_kernel->next; 400947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number++; 401047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 2: Loop over each kernel */ 40119eb4f74649b23c053b308ce1152dce51239450baanthony 401247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 1: compound method interation */ 4013602ab9b30b644a78a4057da93d838a77391ec0acanthony 40149eb4f74649b23c053b308ce1152dce51239450baanthony goto exit_cleanup; 40151b2bc0a7da432e6e1cc0480280402df213faa940anthony 401647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Yes goto's are bad, but it makes cleanup lot more efficient */ 40171b2bc0a7da432e6e1cc0480280402df213faa940anthonyerror_cleanup: 4018ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image == rslt_image ) 4019ea61f01656bb0f9074677452017cc559e54093faanthony curr_image = (Image *) NULL; 402047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rslt_image != (Image *) NULL ) 402147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_image = DestroyImage(rslt_image); 40221b2bc0a7da432e6e1cc0480280402df213faa940anthonyexit_cleanup: 4023ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image == rslt_image || curr_image == image ) 4024ea61f01656bb0f9074677452017cc559e54093faanthony curr_image = (Image *) NULL; 4025ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image != (Image *) NULL ) 402647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = DestroyImage(curr_image); 40279eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image != (Image *) NULL ) 402847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = DestroyImage(work_image); 40299eb4f74649b23c053b308ce1152dce51239450baanthony if ( save_image != (Image *) NULL ) 403047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = DestroyImage(save_image); 403147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( reflected_kernel != (KernelInfo *) NULL ) 403247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = DestroyKernelInfo(reflected_kernel); 403347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return(rslt_image); 40349eb4f74649b23c053b308ce1152dce51239450baanthony} 4035a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 40369eb4f74649b23c053b308ce1152dce51239450baanthony 40379eb4f74649b23c053b308ce1152dce51239450baanthony/* 40389eb4f74649b23c053b308ce1152dce51239450baanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 40399eb4f74649b23c053b308ce1152dce51239450baanthony% % 40409eb4f74649b23c053b308ce1152dce51239450baanthony% % 40419eb4f74649b23c053b308ce1152dce51239450baanthony% % 4042f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% M o r p h o l o g y I m a g e % 40439eb4f74649b23c053b308ce1152dce51239450baanthony% % 40449eb4f74649b23c053b308ce1152dce51239450baanthony% % 40459eb4f74649b23c053b308ce1152dce51239450baanthony% % 40469eb4f74649b23c053b308ce1152dce51239450baanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 40479eb4f74649b23c053b308ce1152dce51239450baanthony% 4048a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony% MorphologyImage() applies a user supplied kernel to the image according to 4049a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony% the given mophology method. 40509eb4f74649b23c053b308ce1152dce51239450baanthony% 40519eb4f74649b23c053b308ce1152dce51239450baanthony% This function applies any and all user defined settings before calling 40529eb4f74649b23c053b308ce1152dce51239450baanthony% the above internal function MorphologyApply(). 40539eb4f74649b23c053b308ce1152dce51239450baanthony% 40549eb4f74649b23c053b308ce1152dce51239450baanthony% User defined settings include... 405522de2722b682eb405b60ec6022a7546df994674eanthony% * Output Bias for Convolution and correlation ("-define convolve:bias=??") 405622de2722b682eb405b60ec6022a7546df994674eanthony% * Kernel Scale/normalize settings ("-define convolve:scale=??") 405746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This can also includes the addition of a scaled unity kernel. 405822de2722b682eb405b60ec6022a7546df994674eanthony% * Show Kernel being applied ("-define showkernel=1") 405922de2722b682eb405b60ec6022a7546df994674eanthony% 406022de2722b682eb405b60ec6022a7546df994674eanthony% Other operators that do not want user supplied options interfering, 406122de2722b682eb405b60ec6022a7546df994674eanthony% especially "convolve:bias" and "showkernel" should use MorphologyApply() 406222de2722b682eb405b60ec6022a7546df994674eanthony% directly. 40639eb4f74649b23c053b308ce1152dce51239450baanthony% 40649eb4f74649b23c053b308ce1152dce51239450baanthony% The format of the MorphologyImage method is: 40659eb4f74649b23c053b308ce1152dce51239450baanthony% 40669eb4f74649b23c053b308ce1152dce51239450baanthony% Image *MorphologyImage(const Image *image,MorphologyMethod method, 4067bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% const ssize_t iterations,KernelInfo *kernel,ExceptionInfo *exception) 40689eb4f74649b23c053b308ce1152dce51239450baanthony% 40699eb4f74649b23c053b308ce1152dce51239450baanthony% A description of each parameter follows: 40709eb4f74649b23c053b308ce1152dce51239450baanthony% 40719eb4f74649b23c053b308ce1152dce51239450baanthony% o image: the image. 40729eb4f74649b23c053b308ce1152dce51239450baanthony% 40739eb4f74649b23c053b308ce1152dce51239450baanthony% o method: the morphology method to be applied. 40749eb4f74649b23c053b308ce1152dce51239450baanthony% 40759eb4f74649b23c053b308ce1152dce51239450baanthony% o iterations: apply the operation this many times (or no change). 40769eb4f74649b23c053b308ce1152dce51239450baanthony% A value of -1 means loop until no change found. 40779eb4f74649b23c053b308ce1152dce51239450baanthony% How this is applied may depend on the morphology method. 40789eb4f74649b23c053b308ce1152dce51239450baanthony% Typically this is a value of 1. 40799eb4f74649b23c053b308ce1152dce51239450baanthony% 40809eb4f74649b23c053b308ce1152dce51239450baanthony% o kernel: An array of double representing the morphology kernel. 40819eb4f74649b23c053b308ce1152dce51239450baanthony% Warning: kernel may be normalized for the Convolve method. 40829eb4f74649b23c053b308ce1152dce51239450baanthony% 40839eb4f74649b23c053b308ce1152dce51239450baanthony% o exception: return any errors or warnings in this structure. 40849eb4f74649b23c053b308ce1152dce51239450baanthony% 40859eb4f74649b23c053b308ce1152dce51239450baanthony*/ 4086f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristyMagickExport Image *MorphologyImage(const Image *image, 4087f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method,const ssize_t iterations, 4088f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const KernelInfo *kernel,ExceptionInfo *exception) 40899eb4f74649b23c053b308ce1152dce51239450baanthony{ 40909eb4f74649b23c053b308ce1152dce51239450baanthony KernelInfo 40919eb4f74649b23c053b308ce1152dce51239450baanthony *curr_kernel; 40929eb4f74649b23c053b308ce1152dce51239450baanthony 409347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony CompositeOperator 409447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony compose; 409547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 40969eb4f74649b23c053b308ce1152dce51239450baanthony Image 40979eb4f74649b23c053b308ce1152dce51239450baanthony *morphology_image; 40989eb4f74649b23c053b308ce1152dce51239450baanthony 4099f46d42620631d2581e0b6a56456e203e17c427c8anthony double 4100f46d42620631d2581e0b6a56456e203e17c427c8anthony bias; 41019eb4f74649b23c053b308ce1152dce51239450baanthony 410222de2722b682eb405b60ec6022a7546df994674eanthony curr_kernel = (KernelInfo *) kernel; 410322de2722b682eb405b60ec6022a7546df994674eanthony bias=0.0; 4104d228c03fa334bae897eee6c2d8721fa48e1577bacristy compose = UndefinedCompositeOp; /* use default for method */ 410522de2722b682eb405b60ec6022a7546df994674eanthony 410646a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Apply Convolve/Correlate Normalization and Scaling Factors. 410746a369d839971ab627bdb31a93d8bd63e81b65a3anthony * This is done BEFORE the ShowKernelInfo() function is called so that 410846a369d839971ab627bdb31a93d8bd63e81b65a3anthony * users can see the results of the 'option:convolve:scale' option. 41099eb4f74649b23c053b308ce1152dce51239450baanthony */ 411022de2722b682eb405b60ec6022a7546df994674eanthony if ( method == ConvolveMorphology || method == CorrelateMorphology ) { 411128ad1d779b6ca95852e860514185a7a97e06af77anthony const char 411228ad1d779b6ca95852e860514185a7a97e06af77anthony *artifact; 4113f46d42620631d2581e0b6a56456e203e17c427c8anthony 411422de2722b682eb405b60ec6022a7546df994674eanthony /* Get the bias value as it will be needed */ 411522de2722b682eb405b60ec6022a7546df994674eanthony artifact = GetImageArtifact(image,"convolve:bias"); 411622de2722b682eb405b60ec6022a7546df994674eanthony if ( artifact != (const char *) NULL) { 411722de2722b682eb405b60ec6022a7546df994674eanthony if (IfMagickFalse(IsGeometry(artifact))) 411822de2722b682eb405b60ec6022a7546df994674eanthony (void) ThrowMagickException(exception,GetMagickModule(), 411922de2722b682eb405b60ec6022a7546df994674eanthony OptionWarning,"InvalidSetting","'%s' '%s'", 412022de2722b682eb405b60ec6022a7546df994674eanthony "convolve:bias",artifact); 412122de2722b682eb405b60ec6022a7546df994674eanthony else 412222de2722b682eb405b60ec6022a7546df994674eanthony bias=StringToDoubleInterval(artifact,(double) QuantumRange+1.0); 412322de2722b682eb405b60ec6022a7546df994674eanthony } 412422de2722b682eb405b60ec6022a7546df994674eanthony 412522de2722b682eb405b60ec6022a7546df994674eanthony /* Scale kernel according to user wishes */ 41269eb4f74649b23c053b308ce1152dce51239450baanthony artifact = GetImageArtifact(image,"convolve:scale"); 4127e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony if ( artifact != (const char *)NULL ) { 412822de2722b682eb405b60ec6022a7546df994674eanthony if (IfMagickFalse(IsGeometry(artifact))) 412922de2722b682eb405b60ec6022a7546df994674eanthony (void) ThrowMagickException(exception,GetMagickModule(), 413022de2722b682eb405b60ec6022a7546df994674eanthony OptionWarning,"InvalidSetting","'%s' '%s'", 413122de2722b682eb405b60ec6022a7546df994674eanthony "convolve:scale",artifact); 413222de2722b682eb405b60ec6022a7546df994674eanthony else { 413322de2722b682eb405b60ec6022a7546df994674eanthony if ( curr_kernel == kernel ) 413422de2722b682eb405b60ec6022a7546df994674eanthony curr_kernel = CloneKernelInfo(kernel); 413522de2722b682eb405b60ec6022a7546df994674eanthony if (curr_kernel == (KernelInfo *) NULL) 413622de2722b682eb405b60ec6022a7546df994674eanthony return((Image *) NULL); 413722de2722b682eb405b60ec6022a7546df994674eanthony ScaleGeometryKernelInfo(curr_kernel, artifact); 41389eb4f74649b23c053b308ce1152dce51239450baanthony } 41399eb4f74649b23c053b308ce1152dce51239450baanthony } 41409eb4f74649b23c053b308ce1152dce51239450baanthony } 41419eb4f74649b23c053b308ce1152dce51239450baanthony 41429eb4f74649b23c053b308ce1152dce51239450baanthony /* display the (normalized) kernel via stderr */ 414348656f2d1ca9ac9979eac32052e4cdc4958c9010cristy if ( IfStringTrue(GetImageArtifact(image,"showkernel")) 414448656f2d1ca9ac9979eac32052e4cdc4958c9010cristy || IfStringTrue(GetImageArtifact(image,"convolve:showkernel")) 414548656f2d1ca9ac9979eac32052e4cdc4958c9010cristy || IfStringTrue(GetImageArtifact(image,"morphology:showkernel")) ) 41469eb4f74649b23c053b308ce1152dce51239450baanthony ShowKernelInfo(curr_kernel); 41479eb4f74649b23c053b308ce1152dce51239450baanthony 41483206678d008425bc56dd2dbad002f2bb26299dc2anthony /* Override the default handling of multi-kernel morphology results 41493206678d008425bc56dd2dbad002f2bb26299dc2anthony * If 'Undefined' use the default method 41503206678d008425bc56dd2dbad002f2bb26299dc2anthony * If 'None' (default for 'Convolve') re-iterate previous result 41513206678d008425bc56dd2dbad002f2bb26299dc2anthony * Otherwise merge resulting images using compose method given. 41523206678d008425bc56dd2dbad002f2bb26299dc2anthony * Default for 'HitAndMiss' is 'Lighten'. 415347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 415428ad1d779b6ca95852e860514185a7a97e06af77anthony { const char 415528ad1d779b6ca95852e860514185a7a97e06af77anthony *artifact; 415622de2722b682eb405b60ec6022a7546df994674eanthony ssize_t 415722de2722b682eb405b60ec6022a7546df994674eanthony parse; 415822de2722b682eb405b60ec6022a7546df994674eanthony 4159f46d42620631d2581e0b6a56456e203e17c427c8anthony artifact = GetImageArtifact(image,"morphology:compose"); 416022de2722b682eb405b60ec6022a7546df994674eanthony if ( artifact != (const char *) NULL) { 416122de2722b682eb405b60ec6022a7546df994674eanthony parse=ParseCommandOption(MagickComposeOptions, 416270b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy MagickFalse,artifact); 416322de2722b682eb405b60ec6022a7546df994674eanthony if ( parse < 0 ) 416422de2722b682eb405b60ec6022a7546df994674eanthony (void) ThrowMagickException(exception,GetMagickModule(), 416522de2722b682eb405b60ec6022a7546df994674eanthony OptionWarning,"UnrecognizedComposeOperator","'%s' '%s'", 416622de2722b682eb405b60ec6022a7546df994674eanthony "morphology:compose",artifact); 416722de2722b682eb405b60ec6022a7546df994674eanthony else 416822de2722b682eb405b60ec6022a7546df994674eanthony compose=(CompositeOperator)parse; 416922de2722b682eb405b60ec6022a7546df994674eanthony } 417028ad1d779b6ca95852e860514185a7a97e06af77anthony } 41719eb4f74649b23c053b308ce1152dce51239450baanthony /* Apply the Morphology */ 4172f46d42620631d2581e0b6a56456e203e17c427c8anthony morphology_image = MorphologyApply(image,method,iterations, 4173f46d42620631d2581e0b6a56456e203e17c427c8anthony curr_kernel,compose,bias,exception); 41749eb4f74649b23c053b308ce1152dce51239450baanthony 41759eb4f74649b23c053b308ce1152dce51239450baanthony /* Cleanup and Exit */ 41769eb4f74649b23c053b308ce1152dce51239450baanthony if ( curr_kernel != kernel ) 41771b2bc0a7da432e6e1cc0480280402df213faa940anthony curr_kernel=DestroyKernelInfo(curr_kernel); 41789eb4f74649b23c053b308ce1152dce51239450baanthony return(morphology_image); 41799eb4f74649b23c053b308ce1152dce51239450baanthony} 418083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 418183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony/* 418283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 418383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 418483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 418583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 41864fd27e21043be809d66c8202e779255e5b660d2danthony+ R o t a t e K e r n e l I n f o % 418783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 418883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 418983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 419083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 419183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 419246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% RotateKernelInfo() rotates the kernel by the angle given. 419346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 419446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Currently it is restricted to 90 degree angles, of either 1D kernels 419546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% or square kernels. And 'circular' rotations of 45 degrees for 3x3 kernels. 419646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% It will ignore usless rotations for specific 'named' built-in kernels. 419783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 41984fd27e21043be809d66c8202e779255e5b660d2danthony% The format of the RotateKernelInfo method is: 419983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 42004fd27e21043be809d66c8202e779255e5b660d2danthony% void RotateKernelInfo(KernelInfo *kernel, double angle) 420183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 420283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A description of each parameter follows: 420383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 420483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o kernel: the Morphology/Convolution kernel 420583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 420683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o angle: angle to rotate in degrees 420783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 420846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This function is currently internal to this module only, but can be exported 420946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% to other modules if needed. 421083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony*/ 42114fd27e21043be809d66c8202e779255e5b660d2danthonystatic void RotateKernelInfo(KernelInfo *kernel, double angle) 421283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony{ 42131b2bc0a7da432e6e1cc0480280402df213faa940anthony /* angle the lower kernels first */ 42141b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 42151b2bc0a7da432e6e1cc0480280402df213faa940anthony RotateKernelInfo(kernel->next, angle); 42161b2bc0a7da432e6e1cc0480280402df213faa940anthony 421783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* WARNING: Currently assumes the kernel (rightly) is horizontally symetrical 421883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony ** 421983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony ** TODO: expand beyond simple 90 degree rotates, flips and flops 422083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony */ 422183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 422283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* Modulus the angle */ 422383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle = fmod(angle, 360.0); 422483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( angle < 0 ) 422583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle += 360.0; 422683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 42273c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 337.5 < angle || angle <= 22.5 ) 422843c4925e5305a26e48d68f7893e94f55d0831c39anthony return; /* Near zero angle - no change! - At least not at this time */ 422983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 42303dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* Handle special cases */ 423183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony switch (kernel->type) { 423283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These built-in kernels are cylindrical kernels, rotating is useless */ 423383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case GaussianKernel: 4234501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 4235501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 423683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case DiskKernel: 42373dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case PeaksKernel: 42383dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case LaplacianKernel: 423983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case ChebyshevKernel: 4240bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 424183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case EuclideanKernel: 424283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 424383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 424483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These may be rotatable at non-90 angles in the future */ 424583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* but simply rotating them in multiples of 90 degrees is useless */ 424683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case SquareKernel: 424783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case DiamondKernel: 424883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case PlusKernel: 42493dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case CrossKernel: 425083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 425183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 425283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These only allows a +/-90 degree rotation (by transpose) */ 425383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* A 180 degree rotation is useless */ 425483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case BlurKernel: 425583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 135.0 < angle && angle <= 225.0 ) 425683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 425783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 225.0 < angle && angle <= 315.0 ) 425883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle -= 180; 425983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony break; 426083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 42613dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony default: 426283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony break; 426383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 426457fe7a498c1302232dac8466864e84b12fad0807anthony /* Attempt rotations by 45 degrees -- 3x3 kernels only */ 42653c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 ) 42663c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { 42673c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( kernel->width == 3 && kernel->height == 3 ) 42683c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { /* Rotate a 3x3 square by 45 degree angle */ 4269a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy double t = kernel->values[0]; 427043c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[0] = kernel->values[3]; 427143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[3] = kernel->values[6]; 427243c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[6] = kernel->values[7]; 427343c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[7] = kernel->values[8]; 427443c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[8] = kernel->values[5]; 427543c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[5] = kernel->values[2]; 427643c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[2] = kernel->values[1]; 427743c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[1] = t; 42781d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* rotate non-centered origin */ 42791d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( kernel->x != 1 || kernel->y != 1 ) { 4280bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t x,y; 4281bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy x = (ssize_t) kernel->x-1; 4282bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy y = (ssize_t) kernel->y-1; 42831d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( x == y ) x = 0; 42841d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( x == 0 ) x = -y; 42851d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( x == -y ) y = 0; 42861d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( y == 0 ) y = x; 4287ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->x = (ssize_t) x+1; 4288ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->y = (ssize_t) y+1; 42891d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 429043c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+315.0, 360.0); /* angle reduced 45 degrees */ 429143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+45.0, 360.0); 42923c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 42933c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else 42943c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony perror("Unable to rotate non-3x3 kernel by 45 degrees"); 42953c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 42963c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 45.0 < fmod(angle, 180.0) && fmod(angle,180.0) <= 135.0 ) 42973c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { 42983c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( kernel->width == 1 || kernel->height == 1 ) 42994c08aed51c5899665ade97263692328eea4af106cristy { /* Do a transpose of a 1 dimensional kernel, 4300bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ** which results in a fast 90 degree rotation of some type. 43013c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony */ 4302bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t 43033c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony t; 4304bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy t = (ssize_t) kernel->width; 43053c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->width = kernel->height; 4306bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t) t; 43073c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony t = kernel->x; 43083c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->x = kernel->y; 43093c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->y = t; 431043c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( kernel->width == 1 ) { 431143c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+270.0, 360.0); /* angle reduced 90 degrees */ 431243c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+90.0, 360.0); 431343c4925e5305a26e48d68f7893e94f55d0831c39anthony } else { 431443c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+90.0, 360.0); /* angle increased 90 degrees */ 431543c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+270.0, 360.0); 431643c4925e5305a26e48d68f7893e94f55d0831c39anthony } 43173c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 43183c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else if ( kernel->width == kernel->height ) 43193c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { /* Rotate a square array of values by 90 degrees */ 4320d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy { register ssize_t 43211d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony i,j,x,y; 4322d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 4323d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register MagickRealType 43241d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony *k,t; 4325d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy 43261d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k=kernel->values; 4327d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy for( i=0, x=(ssize_t) kernel->width-1; i<=x; i++, x--) 4328d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy for( j=0, y=(ssize_t) kernel->height-1; j<y; j++, y--) 43291d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony { t = k[i+j*kernel->width]; 43301d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[i+j*kernel->width] = k[j+x*kernel->width]; 43311d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[j+x*kernel->width] = k[x+y*kernel->width]; 43321d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[x+y*kernel->width] = k[y+i*kernel->width]; 43331d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[y+i*kernel->width] = t; 43341d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 43351d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 43361d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* rotate the origin - relative to center of array */ 4337bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy { register ssize_t x,y; 4338eaedf06777741da32408da72c1e512975c600c48cristy x = (ssize_t) (kernel->x*2-kernel->width+1); 4339eaedf06777741da32408da72c1e512975c600c48cristy y = (ssize_t) (kernel->y*2-kernel->height+1); 4340ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->x = (ssize_t) ( -y +(ssize_t) kernel->width-1)/2; 4341ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->y = (ssize_t) ( +x +(ssize_t) kernel->height-1)/2; 43421d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 434343c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+270.0, 360.0); /* angle reduced 90 degrees */ 434443c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+90.0, 360.0); 43453c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 43463c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else 43473c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony perror("Unable to rotate a non-square, non-linear kernel 90 degrees"); 43483c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 434983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 135.0 < angle && angle <= 225.0 ) 435083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony { 435143c4925e5305a26e48d68f7893e94f55d0831c39anthony /* For a 180 degree rotation - also know as a reflection 435243c4925e5305a26e48d68f7893e94f55d0831c39anthony * This is actually a very very common operation! 435343c4925e5305a26e48d68f7893e94f55d0831c39anthony * Basically all that is needed is a reversal of the kernel data! 435443c4925e5305a26e48d68f7893e94f55d0831c39anthony * And a reflection of the origon 435543c4925e5305a26e48d68f7893e94f55d0831c39anthony */ 4356a23c649213358645994ad489b8c9a317c60111afcristy MagickRealType 4357a96f2494a8e79144a225056be9545cc75e868137cristy t; 4358a96f2494a8e79144a225056be9545cc75e868137cristy 4359d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy register MagickRealType 4360a96f2494a8e79144a225056be9545cc75e868137cristy *k; 4361a96f2494a8e79144a225056be9545cc75e868137cristy 4362a96f2494a8e79144a225056be9545cc75e868137cristy ssize_t 4363a96f2494a8e79144a225056be9545cc75e868137cristy i, 4364a96f2494a8e79144a225056be9545cc75e868137cristy j; 436583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 436683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony k=kernel->values; 4367e42f658533644aecb733785ffd91b286d6778deacristy j=(ssize_t) (kernel->width*kernel->height-1); 4368e42f658533644aecb733785ffd91b286d6778deacristy for (i=0; i < j; i++, j--) 436983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony t=k[i], k[i]=k[j], k[j]=t; 437083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 4371bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) kernel->width - kernel->x - 1; 4372bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = (ssize_t) kernel->height - kernel->y - 1; 437343c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle-180.0, 360.0); /* angle+180 degrees */ 437443c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+180.0, 360.0); 437583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 43763c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony /* At this point angle should at least between -45 (315) and +45 degrees 437783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony * In the future some form of non-orthogonal angled rotates could be 437883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony * performed here, posibily with a linear kernel restriction. 437983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony */ 438083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 438183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 438283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony} 438383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 438483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony/* 438583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 438683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 438783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 438883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 438946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% S c a l e G e o m e t r y K e r n e l I n f o % 439046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 439146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 439246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 439346a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 439446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 439546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% ScaleGeometryKernelInfo() takes a geometry argument string, typically 439646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% provided as a "-set option:convolve:scale {geometry}" user setting, 439746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% and modifies the kernel according to the parsed arguments of that setting. 439846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 439946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The first argument (and any normalization flags) are passed to 440046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% ScaleKernelInfo() to scale/normalize the kernel. The second argument 440146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% is then passed to UnityAddKernelInfo() to add a scled unity kernel 440246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% into the scaled/normalized kernel. 440346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 4404ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% The format of the ScaleGeometryKernelInfo method is: 440546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 4406ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% void ScaleGeometryKernelInfo(KernelInfo *kernel, 4407ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% const double scaling_factor,const MagickStatusType normalize_flags) 440846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 440946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% A description of each parameter follows: 441046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 441146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o kernel: the Morphology/Convolution kernel to modify 441246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 441346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o geometry: 441446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The geometry string to parse, typically from the user provided 441546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% "-set option:convolve:scale {geometry}" setting. 441646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 441746a369d839971ab627bdb31a93d8bd63e81b65a3anthony*/ 441846a369d839971ab627bdb31a93d8bd63e81b65a3anthonyMagickExport void ScaleGeometryKernelInfo (KernelInfo *kernel, 4419954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy const char *geometry) 442046a369d839971ab627bdb31a93d8bd63e81b65a3anthony{ 4421ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy MagickStatusType 442246a369d839971ab627bdb31a93d8bd63e81b65a3anthony flags; 4423ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy 442446a369d839971ab627bdb31a93d8bd63e81b65a3anthony GeometryInfo 442546a369d839971ab627bdb31a93d8bd63e81b65a3anthony args; 442646a369d839971ab627bdb31a93d8bd63e81b65a3anthony 442746a369d839971ab627bdb31a93d8bd63e81b65a3anthony SetGeometryInfo(&args); 442822de2722b682eb405b60ec6022a7546df994674eanthony flags = ParseGeometry(geometry, &args); 442946a369d839971ab627bdb31a93d8bd63e81b65a3anthony 443046a369d839971ab627bdb31a93d8bd63e81b65a3anthony#if 0 443146a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* For Debugging Geometry Input */ 44325acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", 443346a369d839971ab627bdb31a93d8bd63e81b65a3anthony flags, args.rho, args.sigma, args.xi, args.psi ); 443446a369d839971ab627bdb31a93d8bd63e81b65a3anthony#endif 443546a369d839971ab627bdb31a93d8bd63e81b65a3anthony 443646a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & PercentValue) != 0 ) /* Handle Percentage flag*/ 443746a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.rho *= 0.01, args.sigma *= 0.01; 443846a369d839971ab627bdb31a93d8bd63e81b65a3anthony 443946a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & RhoValue) == 0 ) /* Set Defaults for missing args */ 444046a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.rho = 1.0; 444146a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & SigmaValue) == 0 ) 444246a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.sigma = 0.0; 444346a369d839971ab627bdb31a93d8bd63e81b65a3anthony 444446a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Scale/Normalize the input kernel */ 4445d228c03fa334bae897eee6c2d8721fa48e1577bacristy ScaleKernelInfo(kernel, args.rho, (GeometryFlags) flags); 444646a369d839971ab627bdb31a93d8bd63e81b65a3anthony 444746a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Add Unity Kernel, for blending with original */ 444846a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & SigmaValue) != 0 ) 444946a369d839971ab627bdb31a93d8bd63e81b65a3anthony UnityAddKernelInfo(kernel, args.sigma); 445046a369d839971ab627bdb31a93d8bd63e81b65a3anthony 445146a369d839971ab627bdb31a93d8bd63e81b65a3anthony return; 445246a369d839971ab627bdb31a93d8bd63e81b65a3anthony} 445346a369d839971ab627bdb31a93d8bd63e81b65a3anthony/* 445446a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 445546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 445646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 445746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 44586771f1e8987fa49f52d4176281a2e8524b8e31cbcristy% S c a l e K e r n e l I n f o % 4459cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4460cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4461cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4462cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4463cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 44641b2bc0a7da432e6e1cc0480280402df213faa940anthony% ScaleKernelInfo() scales the given kernel list by the given amount, with or 44651b2bc0a7da432e6e1cc0480280402df213faa940anthony% without normalization of the sum of the kernel values (as per given flags). 4466999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4467999bb2c20aa9d42875bb5adba44951988d4ae354anthony% By default (no flags given) the values within the kernel is scaled 44681b2bc0a7da432e6e1cc0480280402df213faa940anthony% directly using given scaling factor without change. 4469999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 447046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% If either of the two 'normalize_flags' are given the kernel will first be 447146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% normalized and then further scaled by the scaling factor value given. 4472999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4473999bb2c20aa9d42875bb5adba44951988d4ae354anthony% Kernel normalization ('normalize_flags' given) is designed to ensure that 4474999bb2c20aa9d42875bb5adba44951988d4ae354anthony% any use of the kernel scaling factor with 'Convolve' or 'Correlate' 44751b2bc0a7da432e6e1cc0480280402df213faa940anthony% morphology methods will fall into -1.0 to +1.0 range. Note that for 44761b2bc0a7da432e6e1cc0480280402df213faa940anthony% non-HDRI versions of IM this may cause images to have any negative results 44771b2bc0a7da432e6e1cc0480280402df213faa940anthony% clipped, unless some 'bias' is used. 4478999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4479999bb2c20aa9d42875bb5adba44951988d4ae354anthony% More specifically. Kernels which only contain positive values (such as a 4480999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 'Gaussian' kernel) will be scaled so that those values sum to +1.0, 44811b2bc0a7da432e6e1cc0480280402df213faa940anthony% ensuring a 0.0 to +1.0 output range for non-HDRI images. 4482999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4483999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For Kernels that contain some negative values, (such as 'Sharpen' kernels) 4484999bb2c20aa9d42875bb5adba44951988d4ae354anthony% the kernel will be scaled by the absolute of the sum of kernel values, so 4485999bb2c20aa9d42875bb5adba44951988d4ae354anthony% that it will generally fall within the +/- 1.0 range. 4486cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4487999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For kernels whose values sum to zero, (such as 'Laplician' kernels) kernel 4488999bb2c20aa9d42875bb5adba44951988d4ae354anthony% will be scaled by just the sum of the postive values, so that its output 4489999bb2c20aa9d42875bb5adba44951988d4ae354anthony% range will again fall into the +/- 1.0 range. 4490cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4491999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For special kernels designed for locating shapes using 'Correlate', (often 4492999bb2c20aa9d42875bb5adba44951988d4ae354anthony% only containing +1 and -1 values, representing foreground/brackground 4493999bb2c20aa9d42875bb5adba44951988d4ae354anthony% matching) a special normalization method is provided to scale the positive 44941e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp% values separately to those of the negative values, so the kernel will be 4495999bb2c20aa9d42875bb5adba44951988d4ae354anthony% forced to become a zero-sum kernel better suited to such searches. 4496999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 44971b2bc0a7da432e6e1cc0480280402df213faa940anthony% WARNING: Correct normalization of the kernel assumes that the '*_range' 4498999bb2c20aa9d42875bb5adba44951988d4ae354anthony% attributes within the kernel structure have been correctly set during the 4499999bb2c20aa9d42875bb5adba44951988d4ae354anthony% kernels creation. 4500999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4501999bb2c20aa9d42875bb5adba44951988d4ae354anthony% NOTE: The values used for 'normalize_flags' have been selected specifically 450246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% to match the use of geometry options, so that '!' means NormalizeValue, '^' 450346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% means CorrelateNormalizeValue. All other GeometryFlags values are ignored. 4504cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 45054fd27e21043be809d66c8202e779255e5b660d2danthony% The format of the ScaleKernelInfo method is: 4506cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4507999bb2c20aa9d42875bb5adba44951988d4ae354anthony% void ScaleKernelInfo(KernelInfo *kernel, const double scaling_factor, 4508999bb2c20aa9d42875bb5adba44951988d4ae354anthony% const MagickStatusType normalize_flags ) 4509cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4510cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% A description of each parameter follows: 4511cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4512cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% o kernel: the Morphology/Convolution kernel 4513cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4514999bb2c20aa9d42875bb5adba44951988d4ae354anthony% o scaling_factor: 4515999bb2c20aa9d42875bb5adba44951988d4ae354anthony% multiply all values (after normalization) by this factor if not 4516999bb2c20aa9d42875bb5adba44951988d4ae354anthony% zero. If the kernel is normalized regardless of any flags. 4517999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4518999bb2c20aa9d42875bb5adba44951988d4ae354anthony% o normalize_flags: 4519999bb2c20aa9d42875bb5adba44951988d4ae354anthony% GeometryFlags defining normalization method to use. 4520999bb2c20aa9d42875bb5adba44951988d4ae354anthony% specifically: NormalizeValue, CorrelateNormalizeValue, 4521999bb2c20aa9d42875bb5adba44951988d4ae354anthony% and/or PercentValue 4522cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4523cc6c836da2a53b6023b716e4973090a6714dc3b0anthony*/ 45246771f1e8987fa49f52d4176281a2e8524b8e31cbcristyMagickExport void ScaleKernelInfo(KernelInfo *kernel, 45256771f1e8987fa49f52d4176281a2e8524b8e31cbcristy const double scaling_factor,const GeometryFlags normalize_flags) 4526cc6c836da2a53b6023b716e4973090a6714dc3b0anthony{ 4527999bb2c20aa9d42875bb5adba44951988d4ae354anthony register double 4528999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale, 4529999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale; 4530999bb2c20aa9d42875bb5adba44951988d4ae354anthony 4531954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy register ssize_t 4532954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy i; 4533954d6e5af31b0cd13b9effa91210044b1e8f68f2cristy 453446a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 45351b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 45361b2bc0a7da432e6e1cc0480280402df213faa940anthony ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags); 45371b2bc0a7da432e6e1cc0480280402df213faa940anthony 453846a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Normalization of Kernel */ 4539999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = 1.0; 4540999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( (normalize_flags&NormalizeValue) != 0 ) { 4541b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(kernel->positive_range + kernel->negative_range) >= MagickEpsilon ) 4542f4e0031305baeb01c89cfd2842cbbec021883550anthony /* non-zero-summing kernel (generally positive) */ 4543999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = fabs(kernel->positive_range + kernel->negative_range); 4544cc6c836da2a53b6023b716e4973090a6714dc3b0anthony else 4545f4e0031305baeb01c89cfd2842cbbec021883550anthony /* zero-summing kernel */ 4546f4e0031305baeb01c89cfd2842cbbec021883550anthony pos_scale = kernel->positive_range; 4547999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 454846a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Force kernel into a normalized zero-summing kernel */ 4549999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) { 4550b978e458a8e1f210bcb580951cf623687236b2fecristy pos_scale = ( fabs(kernel->positive_range) >= MagickEpsilon ) 4551999bb2c20aa9d42875bb5adba44951988d4ae354anthony ? kernel->positive_range : 1.0; 4552b978e458a8e1f210bcb580951cf623687236b2fecristy neg_scale = ( fabs(kernel->negative_range) >= MagickEpsilon ) 4553999bb2c20aa9d42875bb5adba44951988d4ae354anthony ? -kernel->negative_range : 1.0; 4554999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 4555999bb2c20aa9d42875bb5adba44951988d4ae354anthony else 4556999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale = pos_scale; 4557999bb2c20aa9d42875bb5adba44951988d4ae354anthony 4558999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* finialize scaling_factor for positive and negative components */ 4559999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = scaling_factor/pos_scale; 4560999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale = scaling_factor/neg_scale; 4561cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4562bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++) 4563a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ( ! IfNaN(kernel->values[i]) ) 4564999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale; 4565999bb2c20aa9d42875bb5adba44951988d4ae354anthony 4566999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* convolution output range */ 4567999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->positive_range *= pos_scale; 4568999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->negative_range *= neg_scale; 4569999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* maximum and minimum values in kernel */ 4570999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale; 4571999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale; 4572999bb2c20aa9d42875bb5adba44951988d4ae354anthony 457346a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* swap kernel settings if user's scaling factor is negative */ 4574999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( scaling_factor < MagickEpsilon ) { 4575999bb2c20aa9d42875bb5adba44951988d4ae354anthony double t; 4576999bb2c20aa9d42875bb5adba44951988d4ae354anthony t = kernel->positive_range; 4577999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->positive_range = kernel->negative_range; 4578999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->negative_range = t; 4579999bb2c20aa9d42875bb5adba44951988d4ae354anthony t = kernel->maximum; 4580999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->maximum = kernel->minimum; 4581999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->minimum = 1; 4582999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 4583cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4584cc6c836da2a53b6023b716e4973090a6714dc3b0anthony return; 4585cc6c836da2a53b6023b716e4973090a6714dc3b0anthony} 4586cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4587cc6c836da2a53b6023b716e4973090a6714dc3b0anthony/* 4588cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4589cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4590cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4591cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 459246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% S h o w K e r n e l I n f o % 459383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 459483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 459583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 459683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 459783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 45984fd27e21043be809d66c8202e779255e5b660d2danthony% ShowKernelInfo() outputs the details of the given kernel defination to 45994fd27e21043be809d66c8202e779255e5b660d2danthony% standard error, generally due to a users 'showkernel' option request. 460083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 460183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% The format of the ShowKernel method is: 460283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 460357fe7a498c1302232dac8466864e84b12fad0807anthony% void ShowKernelInfo(const KernelInfo *kernel) 460483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 460583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A description of each parameter follows: 460683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 460783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o kernel: the Morphology/Convolution kernel 460883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 460983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony*/ 4610433d11887841b922ec5e6805f9fdd240c320b92ecristyMagickPrivate void ShowKernelInfo(const KernelInfo *kernel) 461183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony{ 461257fe7a498c1302232dac8466864e84b12fad0807anthony const KernelInfo 46137a01dcf50ce12cb2a789bedff51e9345f022432eanthony *k; 46147a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4615bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 46167a01dcf50ce12cb2a789bedff51e9345f022432eanthony c, i, u, v; 46177a01dcf50ce12cb2a789bedff51e9345f022432eanthony 46187a01dcf50ce12cb2a789bedff51e9345f022432eanthony for (c=0, k=kernel; k != (KernelInfo *) NULL; c++, k=k->next ) { 46197a01dcf50ce12cb2a789bedff51e9345f022432eanthony 46205acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Kernel"); 46217a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( kernel->next != (KernelInfo *) NULL ) 46225acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " #%lu", (unsigned long) c ); 46235acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " \"%s", 4624042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickKernelOptions, k->type) ); 4625b978e458a8e1f210bcb580951cf623687236b2fecristy if ( fabs(k->angle) >= MagickEpsilon ) 46265acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "@%lg", k->angle); 46275acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\" of size %lux%lu%+ld%+ld",(unsigned long) 46281e604812fad85bb96f757a2393015ae3d061c39acristy k->width,(unsigned long) k->height,(long) k->x,(long) k->y); 46295acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, 46307a01dcf50ce12cb2a789bedff51e9345f022432eanthony " with values from %.*lg to %.*lg\n", 46317a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->minimum, 46327a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->maximum); 46335acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Forming a output range from %.*lg to %.*lg", 46347a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->negative_range, 463546a369d839971ab627bdb31a93d8bd63e81b65a3anthony GetMagickPrecision(), k->positive_range); 463646a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( fabs(k->positive_range+k->negative_range) < MagickEpsilon ) 46375acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Zero-Summing)\n"); 463846a369d839971ab627bdb31a93d8bd63e81b65a3anthony else if ( fabs(k->positive_range+k->negative_range-1.0) < MagickEpsilon ) 46395acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Normalized)\n"); 464046a369d839971ab627bdb31a93d8bd63e81b65a3anthony else 46415acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Sum %.*lg)\n", 464246a369d839971ab627bdb31a93d8bd63e81b65a3anthony GetMagickPrecision(), k->positive_range+k->negative_range); 464343c4925e5305a26e48d68f7893e94f55d0831c39anthony for (i=v=0; v < k->height; v++) { 46445acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%2lu:", (unsigned long) v ); 464543c4925e5305a26e48d68f7893e94f55d0831c39anthony for (u=0; u < k->width; u++, i++) 4646a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ( IfNaN(k->values[i]) ) 46475acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr," %*s", GetMagickPrecision()+3, "nan"); 46487a01dcf50ce12cb2a789bedff51e9345f022432eanthony else 46495acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr," %*.*lg", GetMagickPrecision()+3, 4650d1e1c2296e4765b36d6a008a07d1763ac876bf77cristy GetMagickPrecision(), (double) k->values[i]); 46515acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr,"\n"); 46527a01dcf50ce12cb2a789bedff51e9345f022432eanthony } 465383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 465483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony} 4655cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4656cc6c836da2a53b6023b716e4973090a6714dc3b0anthony/* 4657cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4658cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4659cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4660cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 466143c4925e5305a26e48d68f7893e94f55d0831c39anthony% U n i t y A d d K e r n a l I n f o % 466243c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 466343c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 466443c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 466543c4925e5305a26e48d68f7893e94f55d0831c39anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 466643c4925e5305a26e48d68f7893e94f55d0831c39anthony% 466743c4925e5305a26e48d68f7893e94f55d0831c39anthony% UnityAddKernelInfo() Adds a given amount of the 'Unity' Convolution Kernel 466843c4925e5305a26e48d68f7893e94f55d0831c39anthony% to the given pre-scaled and normalized Kernel. This in effect adds that 466943c4925e5305a26e48d68f7893e94f55d0831c39anthony% amount of the original image into the resulting convolution kernel. This 467043c4925e5305a26e48d68f7893e94f55d0831c39anthony% value is usually provided by the user as a percentage value in the 467143c4925e5305a26e48d68f7893e94f55d0831c39anthony% 'convolve:scale' setting. 467243c4925e5305a26e48d68f7893e94f55d0831c39anthony% 4673501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% The resulting effect is to convert the defined kernels into blended 4674501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% soft-blurs, unsharp kernels or into sharpening kernels. 467543c4925e5305a26e48d68f7893e94f55d0831c39anthony% 467646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The format of the UnityAdditionKernelInfo method is: 467743c4925e5305a26e48d68f7893e94f55d0831c39anthony% 467843c4925e5305a26e48d68f7893e94f55d0831c39anthony% void UnityAdditionKernelInfo(KernelInfo *kernel, const double scale ) 467943c4925e5305a26e48d68f7893e94f55d0831c39anthony% 468043c4925e5305a26e48d68f7893e94f55d0831c39anthony% A description of each parameter follows: 468143c4925e5305a26e48d68f7893e94f55d0831c39anthony% 468243c4925e5305a26e48d68f7893e94f55d0831c39anthony% o kernel: the Morphology/Convolution kernel 468343c4925e5305a26e48d68f7893e94f55d0831c39anthony% 468443c4925e5305a26e48d68f7893e94f55d0831c39anthony% o scale: 468543c4925e5305a26e48d68f7893e94f55d0831c39anthony% scaling factor for the unity kernel to be added to 468643c4925e5305a26e48d68f7893e94f55d0831c39anthony% the given kernel. 468743c4925e5305a26e48d68f7893e94f55d0831c39anthony% 468843c4925e5305a26e48d68f7893e94f55d0831c39anthony*/ 468943c4925e5305a26e48d68f7893e94f55d0831c39anthonyMagickExport void UnityAddKernelInfo(KernelInfo *kernel, 469043c4925e5305a26e48d68f7893e94f55d0831c39anthony const double scale) 469143c4925e5305a26e48d68f7893e94f55d0831c39anthony{ 469246a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 469346a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( kernel->next != (KernelInfo *) NULL) 469446a369d839971ab627bdb31a93d8bd63e81b65a3anthony UnityAddKernelInfo(kernel->next, scale); 469543c4925e5305a26e48d68f7893e94f55d0831c39anthony 469646a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Add the scaled unity kernel to the existing kernel */ 469743c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[kernel->x+kernel->y*kernel->width] += scale; 469846a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* recalculate the meta-data */ 469943c4925e5305a26e48d68f7893e94f55d0831c39anthony 470043c4925e5305a26e48d68f7893e94f55d0831c39anthony return; 470143c4925e5305a26e48d68f7893e94f55d0831c39anthony} 470243c4925e5305a26e48d68f7893e94f55d0831c39anthony 470343c4925e5305a26e48d68f7893e94f55d0831c39anthony/* 470443c4925e5305a26e48d68f7893e94f55d0831c39anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 470543c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 470643c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 470743c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 470843c4925e5305a26e48d68f7893e94f55d0831c39anthony% Z e r o K e r n e l N a n s % 4709cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4710cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4711cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4712cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4713cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4714cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% ZeroKernelNans() replaces any special 'nan' value that may be present in 4715cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% the kernel with a zero value. This is typically done when the kernel will 4716cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% be used in special hardware (GPU) convolution processors, to simply 4717cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% matters. 4718cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4719cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% The format of the ZeroKernelNans method is: 4720cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 472146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% void ZeroKernelNans (KernelInfo *kernel) 4722cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4723cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% A description of each parameter follows: 4724cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4725cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% o kernel: the Morphology/Convolution kernel 4726cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4727cc6c836da2a53b6023b716e4973090a6714dc3b0anthony*/ 4728cf592636b16d028b14c5fa9dffdc3a94eae7c2f3cristyMagickPrivate void ZeroKernelNans(KernelInfo *kernel) 4729cc6c836da2a53b6023b716e4973090a6714dc3b0anthony{ 4730bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 4731cc6c836da2a53b6023b716e4973090a6714dc3b0anthony i; 4732cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 473346a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 47341b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 47351b2bc0a7da432e6e1cc0480280402df213faa940anthony ZeroKernelNans(kernel->next); 47361b2bc0a7da432e6e1cc0480280402df213faa940anthony 473743c4925e5305a26e48d68f7893e94f55d0831c39anthony for (i=0; i < (kernel->width*kernel->height); i++) 4738a322a839a56b8d9fa40751b1906ce2a4780a24d6anthony if ( IfNaN(kernel->values[i]) ) 4739cc6c836da2a53b6023b716e4973090a6714dc3b0anthony kernel->values[i] = 0.0; 4740cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4741cc6c836da2a53b6023b716e4973090a6714dc3b0anthony return; 4742cc6c836da2a53b6023b716e4973090a6714dc3b0anthony} 4743