morphology.c revision 8ea81224e9ff022e56eb2cddb12860a8b2e90411
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% % 207e41fe84a841d7b9d7b36b245b65e9dcb3314943cristy% Copyright 1999-2011 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" 674c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h" 684c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/morphology.h" 694c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/morphology-private.h" 704c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/option.h" 714c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h" 724c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/prepress.h" 734c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantize.h" 744c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/registry.h" 754c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/semaphore.h" 764c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/splay-tree.h" 774c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/statistic.h" 784c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h" 794c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string-private.h" 804c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/token.h" 814c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/utility.h" 82d1dd6e4fefa0810b9893e6ac9418f79c97c1b39acristy#include "MagickCore/utility-private.h" 83a29d45f897949f04a47bb3da077395969f13dcbacristy 84c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony 85c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony/* 86c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** The following test is for special floating point numbers of value NaN (not 87c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** a number), that may be used within a Kernel Definition. NaN's are defined 88c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** as part of the IEEE standard for floating point number representation. 89c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** 90c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** These are used as a Kernel value to mean that this kernel position is not 91c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** part of the kernel neighbourhood for convolution or morphology processing, 92c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** and thus should be ignored. This allows the use of 'shaped' kernels. 93c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** 94c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** The special properity that two NaN's are never equal, even if they are from 95c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** the same variable allow you to test if a value is special NaN value. 96c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** 97c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony** This macro IsNaN() is thus is only true if the value given is NaN. 98a29d45f897949f04a47bb3da077395969f13dcbacristy*/ 99602ab9b30b644a78a4057da93d838a77391ec0acanthony#define IsNan(a) ((a)!=(a)) 100602ab9b30b644a78a4057da93d838a77391ec0acanthony 10129188a8682a98d4b7882cca434b170517555fc7danthony/* 102a29d45f897949f04a47bb3da077395969f13dcbacristy Other global definitions used by module. 103a29d45f897949f04a47bb3da077395969f13dcbacristy*/ 10429188a8682a98d4b7882cca434b170517555fc7danthonystatic inline double MagickMin(const double x,const double y) 10529188a8682a98d4b7882cca434b170517555fc7danthony{ 10629188a8682a98d4b7882cca434b170517555fc7danthony return( x < y ? x : y); 10729188a8682a98d4b7882cca434b170517555fc7danthony} 10829188a8682a98d4b7882cca434b170517555fc7danthonystatic inline double MagickMax(const double x,const double y) 10929188a8682a98d4b7882cca434b170517555fc7danthony{ 11029188a8682a98d4b7882cca434b170517555fc7danthony return( x > y ? x : y); 11129188a8682a98d4b7882cca434b170517555fc7danthony} 11229188a8682a98d4b7882cca434b170517555fc7danthony#define Minimize(assign,value) assign=MagickMin(assign,value) 11329188a8682a98d4b7882cca434b170517555fc7danthony#define Maximize(assign,value) assign=MagickMax(assign,value) 11429188a8682a98d4b7882cca434b170517555fc7danthony 115c4c86e0ad78bebf6b9f931a659fb82987a7042e3anthony/* Currently these are only internal to this module */ 116c4c86e0ad78bebf6b9f931a659fb82987a7042e3anthonystatic void 11746a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(KernelInfo *), 118bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(KernelInfo *), 119bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(KernelInfo *, const double), 120ef656913b0b30d713ae94c82c47693c9dc69c9f4cristy RotateKernelInfo(KernelInfo *, double); 121602ab9b30b644a78a4057da93d838a77391ec0acanthony 1223dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony 1233dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony/* Quick function to find last kernel in a kernel list */ 1243dd0f620e7a1d12f747ce167844cd7269bfa9f12anthonystatic inline KernelInfo *LastKernelInfo(KernelInfo *kernel) 1253dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony{ 1263dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony while (kernel->next != (KernelInfo *) NULL) 1273dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony kernel = kernel->next; 1283dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony return(kernel); 1293dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony} 1303dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony 131602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 132602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 133602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 134602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 135602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 13683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A c q u i r e K e r n e l I n f o % 137602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 138602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 139602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 140602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 141602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1422be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% AcquireKernelInfo() takes the given string (generally supplied by the 143602ab9b30b644a78a4057da93d838a77391ec0acanthony% user) and converts it into a Morphology/Convolution Kernel. This allows 144602ab9b30b644a78a4057da93d838a77391ec0acanthony% users to specify a kernel from a number of pre-defined kernels, or to fully 145602ab9b30b644a78a4057da93d838a77391ec0acanthony% specify their own kernel for a specific Convolution or Morphology 146602ab9b30b644a78a4057da93d838a77391ec0acanthony% Operation. 147602ab9b30b644a78a4057da93d838a77391ec0acanthony% 148602ab9b30b644a78a4057da93d838a77391ec0acanthony% The kernel so generated can be any rectangular array of floating point 149602ab9b30b644a78a4057da93d838a77391ec0acanthony% values (doubles) with the 'control point' or 'pixel being affected' 150602ab9b30b644a78a4057da93d838a77391ec0acanthony% anywhere within that array of values. 151602ab9b30b644a78a4057da93d838a77391ec0acanthony% 15283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% Previously IM was restricted to a square of odd size using the exact 15319910ef25dd3d99d1981a9e42c934133170ee714anthony% center as origin, this is no longer the case, and any rectangular kernel 15483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% with any value being declared the origin. This in turn allows the use of 15583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% highly asymmetrical kernels. 156602ab9b30b644a78a4057da93d838a77391ec0acanthony% 157602ab9b30b644a78a4057da93d838a77391ec0acanthony% The floating point values in the kernel can also include a special value 15883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% known as 'nan' or 'not a number' to indicate that this value is not part 15983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% of the kernel array. This allows you to shaped the kernel within its 16083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% rectangular area. That is 'nan' values provide a 'mask' for the kernel 16183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% shape. However at least one non-nan value must be provided for correct 16283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% working of a kernel. 163602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1647a01dcf50ce12cb2a789bedff51e9345f022432eanthony% The returned kernel should be freed using the DestroyKernelInfo() when you 1657a01dcf50ce12cb2a789bedff51e9345f022432eanthony% are finished with it. Do not free this memory yourself. 166602ab9b30b644a78a4057da93d838a77391ec0acanthony% 167602ab9b30b644a78a4057da93d838a77391ec0acanthony% Input kernel defintion strings can consist of any of three types. 168602ab9b30b644a78a4057da93d838a77391ec0acanthony% 169bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% "name:args[[@><]" 17029188a8682a98d4b7882cca434b170517555fc7danthony% Select from one of the built in kernels, using the name and 17129188a8682a98d4b7882cca434b170517555fc7danthony% geometry arguments supplied. See AcquireKernelBuiltIn() 172602ab9b30b644a78a4057da93d838a77391ec0acanthony% 173bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% "WxH[+X+Y][@><]:num, num, num ..." 1741b2bc0a7da432e6e1cc0480280402df213faa940anthony% a kernel of size W by H, with W*H floating point numbers following. 175602ab9b30b644a78a4057da93d838a77391ec0acanthony% the 'center' can be optionally be defined at +X+Y (such that +0+0 17629188a8682a98d4b7882cca434b170517555fc7danthony% is top left corner). If not defined the pixel in the center, for 17729188a8682a98d4b7882cca434b170517555fc7danthony% odd sizes, or to the immediate top or left of center for even sizes 17829188a8682a98d4b7882cca434b170517555fc7danthony% is automatically selected. 179602ab9b30b644a78a4057da93d838a77391ec0acanthony% 18029188a8682a98d4b7882cca434b170517555fc7danthony% "num, num, num, num, ..." 18129188a8682a98d4b7882cca434b170517555fc7danthony% list of floating point numbers defining an 'old style' odd sized 18229188a8682a98d4b7882cca434b170517555fc7danthony% square kernel. At least 9 values should be provided for a 3x3 18329188a8682a98d4b7882cca434b170517555fc7danthony% square kernel, 25 for a 5x5 square kernel, 49 for 7x7, etc. 18429188a8682a98d4b7882cca434b170517555fc7danthony% Values can be space or comma separated. This is not recommended. 185602ab9b30b644a78a4057da93d838a77391ec0acanthony% 1867a01dcf50ce12cb2a789bedff51e9345f022432eanthony% You can define a 'list of kernels' which can be used by some morphology 1871e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp% operators A list is defined as a semi-colon separated list kernels. 1887a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 189dbc8989a61339951c6434d9a43e7b6fefb5da374anthony% " kernel ; kernel ; kernel ; " 1907a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 1911dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% Any extra ';' characters, at start, end or between kernel defintions are 19243c4925e5305a26e48d68f7893e94f55d0831c39anthony% simply ignored. 19343c4925e5305a26e48d68f7893e94f55d0831c39anthony% 194bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The special flags will expand a single kernel, into a list of rotated 195bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% kernels. A '@' flag will expand a 3x3 kernel into a list of 45-degree 196bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% cyclic rotations, while a '>' will generate a list of 90-degree rotations. 197bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The '<' also exands using 90-degree rotates, but giving a 180-degree 198bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% reflected kernel before the +/- 90-degree rotations, which can be important 199bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% for Thinning operations. 200bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 20143c4925e5305a26e48d68f7893e94f55d0831c39anthony% Note that 'name' kernels will start with an alphabetic character while the 20243c4925e5305a26e48d68f7893e94f55d0831c39anthony% new kernel specification has a ':' character in its specification string. 20343c4925e5305a26e48d68f7893e94f55d0831c39anthony% If neither is the case, it is assumed an old style of a simple list of 20443c4925e5305a26e48d68f7893e94f55d0831c39anthony% numbers generating a odd-sized square kernel has been given. 2057a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 206602ab9b30b644a78a4057da93d838a77391ec0acanthony% The format of the AcquireKernal method is: 207602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2082be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% KernelInfo *AcquireKernelInfo(const char *kernel_string) 209602ab9b30b644a78a4057da93d838a77391ec0acanthony% 210602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 211602ab9b30b644a78a4057da93d838a77391ec0acanthony% 212602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel_string: the Morphology/Convolution kernel wanted. 213602ab9b30b644a78a4057da93d838a77391ec0acanthony% 214602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 215602ab9b30b644a78a4057da93d838a77391ec0acanthony 216c84dce50867229e4872193e8eed5dbab58eb9f02anthony/* This was separated so that it could be used as a separate 2175ef8e94ff55717be2387d537bd49025780a1a558anthony** array input handling function, such as for -color-matrix 218c84dce50867229e4872193e8eed5dbab58eb9f02anthony*/ 2195ef8e94ff55717be2387d537bd49025780a1a558anthonystatic KernelInfo *ParseKernelArray(const char *kernel_string) 220602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 2212be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy KernelInfo 222602ab9b30b644a78a4057da93d838a77391ec0acanthony *kernel; 223602ab9b30b644a78a4057da93d838a77391ec0acanthony 224602ab9b30b644a78a4057da93d838a77391ec0acanthony char 225602ab9b30b644a78a4057da93d838a77391ec0acanthony token[MaxTextExtent]; 226602ab9b30b644a78a4057da93d838a77391ec0acanthony 227602ab9b30b644a78a4057da93d838a77391ec0acanthony const char 2285ef8e94ff55717be2387d537bd49025780a1a558anthony *p, 2295ef8e94ff55717be2387d537bd49025780a1a558anthony *end; 230602ab9b30b644a78a4057da93d838a77391ec0acanthony 231bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 232c84dce50867229e4872193e8eed5dbab58eb9f02anthony i; 233602ab9b30b644a78a4057da93d838a77391ec0acanthony 23429188a8682a98d4b7882cca434b170517555fc7danthony double 23529188a8682a98d4b7882cca434b170517555fc7danthony nan = sqrt((double)-1.0); /* Special Value : Not A Number */ 23629188a8682a98d4b7882cca434b170517555fc7danthony 23743c4925e5305a26e48d68f7893e94f55d0831c39anthony MagickStatusType 23843c4925e5305a26e48d68f7893e94f55d0831c39anthony flags; 23943c4925e5305a26e48d68f7893e94f55d0831c39anthony 24043c4925e5305a26e48d68f7893e94f55d0831c39anthony GeometryInfo 24143c4925e5305a26e48d68f7893e94f55d0831c39anthony args; 24243c4925e5305a26e48d68f7893e94f55d0831c39anthony 2432be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel)); 2442be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy if (kernel == (KernelInfo *)NULL) 245602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 246602ab9b30b644a78a4057da93d838a77391ec0acanthony (void) ResetMagickMemory(kernel,0,sizeof(*kernel)); 24743c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->minimum = kernel->maximum = kernel->angle = 0.0; 2487a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel->negative_range = kernel->positive_range = 0.0; 249602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->type = UserDefinedKernel; 2507a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel->next = (KernelInfo *) NULL; 251d43a46bc9598004091eae232bc7938e009b494a1cristy kernel->signature = MagickSignature; 2525e6be1e6a77c230e4a204fa9163d873104730c35cristy if (kernel_string == (const char *) NULL) 2535e6be1e6a77c230e4a204fa9163d873104730c35cristy return(kernel); 254602ab9b30b644a78a4057da93d838a77391ec0acanthony 2555ef8e94ff55717be2387d537bd49025780a1a558anthony /* find end of this specific kernel definition string */ 2565ef8e94ff55717be2387d537bd49025780a1a558anthony end = strchr(kernel_string, ';'); 2575ef8e94ff55717be2387d537bd49025780a1a558anthony if ( end == (char *) NULL ) 2585ef8e94ff55717be2387d537bd49025780a1a558anthony end = strchr(kernel_string, '\0'); 2595ef8e94ff55717be2387d537bd49025780a1a558anthony 260a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* clear flags - for Expanding kernel lists thorugh rotations */ 26143c4925e5305a26e48d68f7893e94f55d0831c39anthony flags = NoValue; 26243c4925e5305a26e48d68f7893e94f55d0831c39anthony 263602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Has a ':' in argument - New user kernel specification */ 264602ab9b30b644a78a4057da93d838a77391ec0acanthony p = strchr(kernel_string, ':'); 2655ef8e94ff55717be2387d537bd49025780a1a558anthony if ( p != (char *) NULL && p < end) 266602ab9b30b644a78a4057da93d838a77391ec0acanthony { 267602ab9b30b644a78a4057da93d838a77391ec0acanthony /* ParseGeometry() needs the geometry separated! -- Arrgghh */ 268150989ed67ef9da53141a65e5f3ebdb05dd025abcristy memcpy(token, kernel_string, (size_t) (p-kernel_string)); 269602ab9b30b644a78a4057da93d838a77391ec0acanthony token[p-kernel_string] = '\0'; 270c84dce50867229e4872193e8eed5dbab58eb9f02anthony SetGeometryInfo(&args); 271602ab9b30b644a78a4057da93d838a77391ec0acanthony flags = ParseGeometry(token, &args); 272602ab9b30b644a78a4057da93d838a77391ec0acanthony 27329188a8682a98d4b7882cca434b170517555fc7danthony /* Size handling and checks of geometry settings */ 274602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( (flags & WidthValue) == 0 ) /* if no width then */ 275602ab9b30b644a78a4057da93d838a77391ec0acanthony args.rho = args.sigma; /* then width = height */ 276602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.rho < 1.0 ) /* if width too small */ 277602ab9b30b644a78a4057da93d838a77391ec0acanthony args.rho = 1.0; /* then width = 1 */ 278602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.sigma < 1.0 ) /* if height too small */ 279602ab9b30b644a78a4057da93d838a77391ec0acanthony args.sigma = args.rho; /* then height = width */ 280bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args.rho; 281bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t)args.sigma; 282602ab9b30b644a78a4057da93d838a77391ec0acanthony 283602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Offset Handling and Checks */ 284602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args.xi < 0.0 || args.psi < 0.0 ) 28583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 286bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi 287bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy : (ssize_t) (kernel->width-1)/2; 288bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi 289bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy : (ssize_t) (kernel->height-1)/2; 290bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( kernel->x >= (ssize_t) kernel->width || 291bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y >= (ssize_t) kernel->height ) 29283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 293602ab9b30b644a78a4057da93d838a77391ec0acanthony 294602ab9b30b644a78a4057da93d838a77391ec0acanthony p++; /* advance beyond the ':' */ 295602ab9b30b644a78a4057da93d838a77391ec0acanthony } 296602ab9b30b644a78a4057da93d838a77391ec0acanthony else 297c84dce50867229e4872193e8eed5dbab58eb9f02anthony { /* ELSE - Old old specification, forming odd-square kernel */ 298602ab9b30b644a78a4057da93d838a77391ec0acanthony /* count up number of values given */ 299602ab9b30b644a78a4057da93d838a77391ec0acanthony p=(const char *) kernel_string; 300a699b171eff7e0178463e8f271b35a3cbb995f0ecristy while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\'')) 30129188a8682a98d4b7882cca434b170517555fc7danthony p++; /* ignore "'" chars for convolve filter usage - Cristy */ 3025ef8e94ff55717be2387d537bd49025780a1a558anthony for (i=0; p < end; i++) 303602ab9b30b644a78a4057da93d838a77391ec0acanthony { 304602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 305602ab9b30b644a78a4057da93d838a77391ec0acanthony if (*token == ',') 306602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 307602ab9b30b644a78a4057da93d838a77391ec0acanthony } 308602ab9b30b644a78a4057da93d838a77391ec0acanthony /* set the size of the kernel - old sized square */ 309bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height= (size_t) sqrt((double) i+1.0); 310bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 311602ab9b30b644a78a4057da93d838a77391ec0acanthony p=(const char *) kernel_string; 31229188a8682a98d4b7882cca434b170517555fc7danthony while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\'')) 31329188a8682a98d4b7882cca434b170517555fc7danthony p++; /* ignore "'" chars for convolve filter usage - Cristy */ 314602ab9b30b644a78a4057da93d838a77391ec0acanthony } 315602ab9b30b644a78a4057da93d838a77391ec0acanthony 316602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Read in the kernel values from rest of input string argument */ 3175e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 318602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height*sizeof(double)); 319602ab9b30b644a78a4057da93d838a77391ec0acanthony if (kernel->values == (double *) NULL) 32083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 321602ab9b30b644a78a4057da93d838a77391ec0acanthony 322c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->minimum = +MagickHuge; 323c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = -MagickHuge; 324c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 325c84dce50867229e4872193e8eed5dbab58eb9f02anthony 326bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++) 327602ab9b30b644a78a4057da93d838a77391ec0acanthony { 328602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 329602ab9b30b644a78a4057da93d838a77391ec0acanthony if (*token == ',') 330602ab9b30b644a78a4057da93d838a77391ec0acanthony GetMagickToken(p,&p,token); 33129188a8682a98d4b7882cca434b170517555fc7danthony if ( LocaleCompare("nan",token) == 0 332c84dce50867229e4872193e8eed5dbab58eb9f02anthony || LocaleCompare("-",token) == 0 ) { 33329188a8682a98d4b7882cca434b170517555fc7danthony kernel->values[i] = nan; /* do not include this value in kernel */ 33429188a8682a98d4b7882cca434b170517555fc7danthony } 33529188a8682a98d4b7882cca434b170517555fc7danthony else { 336c1acd8495db5b00e9ced313e86dfdbe8c60c111dcristy kernel->values[i] = InterpretLocaleValue(token,(char **) NULL); 33729188a8682a98d4b7882cca434b170517555fc7danthony ( kernel->values[i] < 0) 338c99304fe3c8d9c617da792b40b57c118bb1249afcristy ? ( kernel->negative_range += kernel->values[i] ) 339c99304fe3c8d9c617da792b40b57c118bb1249afcristy : ( kernel->positive_range += kernel->values[i] ); 340c99304fe3c8d9c617da792b40b57c118bb1249afcristy Minimize(kernel->minimum, kernel->values[i]); 341c99304fe3c8d9c617da792b40b57c118bb1249afcristy Maximize(kernel->maximum, kernel->values[i]); 34229188a8682a98d4b7882cca434b170517555fc7danthony } 34329188a8682a98d4b7882cca434b170517555fc7danthony } 34429188a8682a98d4b7882cca434b170517555fc7danthony 3455ef8e94ff55717be2387d537bd49025780a1a558anthony /* sanity check -- no more values in kernel definition */ 3465ef8e94ff55717be2387d537bd49025780a1a558anthony GetMagickToken(p,&p,token); 3475ef8e94ff55717be2387d537bd49025780a1a558anthony if ( *token != '\0' && *token != ';' && *token != '\'' ) 3485ef8e94ff55717be2387d537bd49025780a1a558anthony return(DestroyKernelInfo(kernel)); 3495ef8e94ff55717be2387d537bd49025780a1a558anthony 350c84dce50867229e4872193e8eed5dbab58eb9f02anthony#if 0 351c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* this was the old method of handling a incomplete kernel */ 352bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( i < (ssize_t) (kernel->width*kernel->height) ) { 353c99304fe3c8d9c617da792b40b57c118bb1249afcristy Minimize(kernel->minimum, kernel->values[i]); 354c99304fe3c8d9c617da792b40b57c118bb1249afcristy Maximize(kernel->maximum, kernel->values[i]); 355bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( ; i < (ssize_t) (kernel->width*kernel->height); i++) 35629188a8682a98d4b7882cca434b170517555fc7danthony kernel->values[i]=0.0; 357602ab9b30b644a78a4057da93d838a77391ec0acanthony } 358c84dce50867229e4872193e8eed5dbab58eb9f02anthony#else 359c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* Number of values for kernel was not enough - Report Error */ 360bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if ( i < (ssize_t) (kernel->width*kernel->height) ) 361c84dce50867229e4872193e8eed5dbab58eb9f02anthony return(DestroyKernelInfo(kernel)); 362c84dce50867229e4872193e8eed5dbab58eb9f02anthony#endif 363c84dce50867229e4872193e8eed5dbab58eb9f02anthony 364c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* check that we recieved at least one real (non-nan) value! */ 365c84dce50867229e4872193e8eed5dbab58eb9f02anthony if ( kernel->minimum == MagickHuge ) 366c84dce50867229e4872193e8eed5dbab58eb9f02anthony return(DestroyKernelInfo(kernel)); 367602ab9b30b644a78a4057da93d838a77391ec0acanthony 36843c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( (flags & AreaValue) != 0 ) /* '@' symbol in kernel size */ 369bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 45.0); /* cyclic rotate 3x3 kernels */ 370bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */ 371bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 90.0); /* 90 degree rotate of kernel */ 372bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & LessValue) != 0 ) /* '<' symbol in kernel args */ 373bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(kernel); /* 90 degree mirror rotate */ 37443c4925e5305a26e48d68f7893e94f55d0831c39anthony 375602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 376602ab9b30b644a78a4057da93d838a77391ec0acanthony} 377c84dce50867229e4872193e8eed5dbab58eb9f02anthony 37843c4925e5305a26e48d68f7893e94f55d0831c39anthonystatic KernelInfo *ParseKernelName(const char *kernel_string) 379c84dce50867229e4872193e8eed5dbab58eb9f02anthony{ 380c84dce50867229e4872193e8eed5dbab58eb9f02anthony char 381c84dce50867229e4872193e8eed5dbab58eb9f02anthony token[MaxTextExtent]; 382c84dce50867229e4872193e8eed5dbab58eb9f02anthony 383c84dce50867229e4872193e8eed5dbab58eb9f02anthony const char 3847a01dcf50ce12cb2a789bedff51e9345f022432eanthony *p, 3857a01dcf50ce12cb2a789bedff51e9345f022432eanthony *end; 386c84dce50867229e4872193e8eed5dbab58eb9f02anthony 3879d314ff2c17a77996c05413c2013880387e50f0ecristy GeometryInfo 3889d314ff2c17a77996c05413c2013880387e50f0ecristy args; 3899d314ff2c17a77996c05413c2013880387e50f0ecristy 3909d314ff2c17a77996c05413c2013880387e50f0ecristy KernelInfo 3919d314ff2c17a77996c05413c2013880387e50f0ecristy *kernel; 3929d314ff2c17a77996c05413c2013880387e50f0ecristy 393c84dce50867229e4872193e8eed5dbab58eb9f02anthony MagickStatusType 394c84dce50867229e4872193e8eed5dbab58eb9f02anthony flags; 395c84dce50867229e4872193e8eed5dbab58eb9f02anthony 3969d314ff2c17a77996c05413c2013880387e50f0ecristy ssize_t 3979d314ff2c17a77996c05413c2013880387e50f0ecristy type; 398c84dce50867229e4872193e8eed5dbab58eb9f02anthony 399c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* Parse special 'named' kernel */ 4005ef8e94ff55717be2387d537bd49025780a1a558anthony GetMagickToken(kernel_string,&p,token); 401042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy type=ParseCommandOption(MagickKernelOptions,MagickFalse,token); 402c84dce50867229e4872193e8eed5dbab58eb9f02anthony if ( type < 0 || type == UserDefinedKernel ) 4035ef8e94ff55717be2387d537bd49025780a1a558anthony return((KernelInfo *)NULL); /* not a valid named kernel */ 404c84dce50867229e4872193e8eed5dbab58eb9f02anthony 405c84dce50867229e4872193e8eed5dbab58eb9f02anthony while (((isspace((int) ((unsigned char) *p)) != 0) || 4065ef8e94ff55717be2387d537bd49025780a1a558anthony (*p == ',') || (*p == ':' )) && (*p != '\0') && (*p != ';')) 407c84dce50867229e4872193e8eed5dbab58eb9f02anthony p++; 4087a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4097a01dcf50ce12cb2a789bedff51e9345f022432eanthony end = strchr(p, ';'); /* end of this kernel defintion */ 4107a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( end == (char *) NULL ) 4117a01dcf50ce12cb2a789bedff51e9345f022432eanthony end = strchr(p, '\0'); 4127a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4137a01dcf50ce12cb2a789bedff51e9345f022432eanthony /* ParseGeometry() needs the geometry separated! -- Arrgghh */ 4147a01dcf50ce12cb2a789bedff51e9345f022432eanthony memcpy(token, p, (size_t) (end-p)); 4157a01dcf50ce12cb2a789bedff51e9345f022432eanthony token[end-p] = '\0'; 416c84dce50867229e4872193e8eed5dbab58eb9f02anthony SetGeometryInfo(&args); 4177a01dcf50ce12cb2a789bedff51e9345f022432eanthony flags = ParseGeometry(token, &args); 418c84dce50867229e4872193e8eed5dbab58eb9f02anthony 4193c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony#if 0 4203c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony /* For Debugging Geometry Input */ 4215acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", 4221e604812fad85bb96f757a2393015ae3d061c39acristy flags, args.rho, args.sigma, args.xi, args.psi ); 4233c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony#endif 4243c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony 425c84dce50867229e4872193e8eed5dbab58eb9f02anthony /* special handling of missing values in input string */ 426c84dce50867229e4872193e8eed5dbab58eb9f02anthony switch( type ) { 427a9892d898acb81e1ec73106d892855fdc5a69427anthony /* Shape Kernel Defaults */ 428529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 429529482f4b494010a13338a74446c510712f670b3anthony if ( (flags & WidthValue) == 0 ) 430a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = 1.0; /* Default scale = 1.0, zero is valid */ 4315ef8e94ff55717be2387d537bd49025780a1a558anthony break; 4325ef8e94ff55717be2387d537bd49025780a1a558anthony case SquareKernel: 4335ef8e94ff55717be2387d537bd49025780a1a558anthony case DiamondKernel: 4341ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 4355ef8e94ff55717be2387d537bd49025780a1a558anthony case DiskKernel: 4365ef8e94ff55717be2387d537bd49025780a1a558anthony case PlusKernel: 4373dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case CrossKernel: 4385ef8e94ff55717be2387d537bd49025780a1a558anthony if ( (flags & HeightValue) == 0 ) 439a9892d898acb81e1ec73106d892855fdc5a69427anthony args.sigma = 1.0; /* Default scale = 1.0, zero is valid */ 4405ef8e94ff55717be2387d537bd49025780a1a558anthony break; 441c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RingKernel: 442c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( (flags & XValue) == 0 ) 443a9892d898acb81e1ec73106d892855fdc5a69427anthony args.xi = 1.0; /* Default scale = 1.0, zero is valid */ 444c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 445a9892d898acb81e1ec73106d892855fdc5a69427anthony case RectangleKernel: /* Rectangle - set size defaults */ 446a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & WidthValue) == 0 ) /* if no width then */ 447a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = args.sigma; /* then width = height */ 448a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( args.rho < 1.0 ) /* if width too small */ 449a9892d898acb81e1ec73106d892855fdc5a69427anthony args.rho = 3; /* then width = 3 */ 450a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( args.sigma < 1.0 ) /* if height too small */ 451a9892d898acb81e1ec73106d892855fdc5a69427anthony args.sigma = args.rho; /* then height = width */ 452a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & XValue) == 0 ) /* center offset if not defined */ 453a9892d898acb81e1ec73106d892855fdc5a69427anthony args.xi = (double)(((ssize_t)args.rho-1)/2); 454a9892d898acb81e1ec73106d892855fdc5a69427anthony if ( (flags & YValue) == 0 ) 455a9892d898acb81e1ec73106d892855fdc5a69427anthony args.psi = (double)(((ssize_t)args.sigma-1)/2); 456a9892d898acb81e1ec73106d892855fdc5a69427anthony break; 457a9892d898acb81e1ec73106d892855fdc5a69427anthony /* Distance Kernel Defaults */ 4585ef8e94ff55717be2387d537bd49025780a1a558anthony case ChebyshevKernel: 459bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 4601ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonalKernel: 4615ef8e94ff55717be2387d537bd49025780a1a558anthony case EuclideanKernel: 46243c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( (flags & HeightValue) == 0 ) /* no distance scale */ 46343c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma = 100.0; /* default distance scaling */ 46443c4925e5305a26e48d68f7893e94f55d0831c39anthony else if ( (flags & AspectValue ) != 0 ) /* '!' flag */ 46543c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma = QuantumRange/(args.sigma+1); /* maximum pixel distance */ 46643c4925e5305a26e48d68f7893e94f55d0831c39anthony else if ( (flags & PercentValue ) != 0 ) /* '%' flag */ 46743c4925e5305a26e48d68f7893e94f55d0831c39anthony args.sigma *= QuantumRange/100.0; /* percentage of color range */ 4685ef8e94ff55717be2387d537bd49025780a1a558anthony break; 4695ef8e94ff55717be2387d537bd49025780a1a558anthony default: 4705ef8e94ff55717be2387d537bd49025780a1a558anthony break; 471c84dce50867229e4872193e8eed5dbab58eb9f02anthony } 472c84dce50867229e4872193e8eed5dbab58eb9f02anthony 473f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony kernel = AcquireKernelBuiltIn((KernelInfoType)type, &args); 474529482f4b494010a13338a74446c510712f670b3anthony if ( kernel == (KernelInfo *) NULL ) 475529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 476f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony 477f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony /* global expand to rotated kernel list - only for single kernels */ 478f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony if ( kernel->next == (KernelInfo *) NULL ) { 479f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony if ( (flags & AreaValue) != 0 ) /* '@' symbol in kernel args */ 480bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 45.0); 481bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */ 482bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandRotateKernelInfo(kernel, 90.0); 483bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony else if ( (flags & LessValue) != 0 ) /* '<' symbol in kernel args */ 484bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ExpandMirrorKernelInfo(kernel); 485f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony } 486f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony 487f0176c3994ec4f0eed7a5e0078e4bd7a012194c4anthony return(kernel); 488c84dce50867229e4872193e8eed5dbab58eb9f02anthony} 489c84dce50867229e4872193e8eed5dbab58eb9f02anthony 4905ef8e94ff55717be2387d537bd49025780a1a558anthonyMagickExport KernelInfo *AcquireKernelInfo(const char *kernel_string) 4915ef8e94ff55717be2387d537bd49025780a1a558anthony{ 4927a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4937a01dcf50ce12cb2a789bedff51e9345f022432eanthony KernelInfo 494dbc8989a61339951c6434d9a43e7b6fefb5da374anthony *kernel, 49543c4925e5305a26e48d68f7893e94f55d0831c39anthony *new_kernel; 4967a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4975ef8e94ff55717be2387d537bd49025780a1a558anthony char 4985ef8e94ff55717be2387d537bd49025780a1a558anthony token[MaxTextExtent]; 4995ef8e94ff55717be2387d537bd49025780a1a558anthony 5007a01dcf50ce12cb2a789bedff51e9345f022432eanthony const char 501dbc8989a61339951c6434d9a43e7b6fefb5da374anthony *p; 5027a01dcf50ce12cb2a789bedff51e9345f022432eanthony 503bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 504e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony kernel_number; 505e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony 5065e6be1e6a77c230e4a204fa9163d873104730c35cristy if (kernel_string == (const char *) NULL) 5075e6be1e6a77c230e4a204fa9163d873104730c35cristy return(ParseKernelArray(kernel_string)); 508dbc8989a61339951c6434d9a43e7b6fefb5da374anthony p = kernel_string; 50943c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel = NULL; 510e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony kernel_number = 0; 5117a01dcf50ce12cb2a789bedff51e9345f022432eanthony 512dbc8989a61339951c6434d9a43e7b6fefb5da374anthony while ( GetMagickToken(p,NULL,token), *token != '\0' ) { 5137a01dcf50ce12cb2a789bedff51e9345f022432eanthony 5141e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp /* ignore extra or multiple ';' kernel separators */ 515dbc8989a61339951c6434d9a43e7b6fefb5da374anthony if ( *token != ';' ) { 5167a01dcf50ce12cb2a789bedff51e9345f022432eanthony 517dbc8989a61339951c6434d9a43e7b6fefb5da374anthony /* tokens starting with alpha is a Named kernel */ 51843c4925e5305a26e48d68f7893e94f55d0831c39anthony if (isalpha((int) *token) != 0) 51943c4925e5305a26e48d68f7893e94f55d0831c39anthony new_kernel = ParseKernelName(p); 520dbc8989a61339951c6434d9a43e7b6fefb5da374anthony else /* otherwise a user defined kernel array */ 52143c4925e5305a26e48d68f7893e94f55d0831c39anthony new_kernel = ParseKernelArray(p); 522dbc8989a61339951c6434d9a43e7b6fefb5da374anthony 523e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony /* Error handling -- this is not proper error handling! */ 524e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony if ( new_kernel == (KernelInfo *) NULL ) { 5255acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Failed to parse kernel number #%.20g\n", 5261e604812fad85bb96f757a2393015ae3d061c39acristy (double) kernel_number); 527e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony if ( kernel != (KernelInfo *) NULL ) 528e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony kernel=DestroyKernelInfo(kernel); 529e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony return((KernelInfo *) NULL); 530dbc8989a61339951c6434d9a43e7b6fefb5da374anthony } 531e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony 532e108a3fd07919343dc9e3b7720da59ef5c4c5c55anthony /* initialise or append the kernel list */ 5333dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony if ( kernel == (KernelInfo *) NULL ) 5343dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony kernel = new_kernel; 5353dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony else 53643c4925e5305a26e48d68f7893e94f55d0831c39anthony LastKernelInfo(kernel)->next = new_kernel; 537dbc8989a61339951c6434d9a43e7b6fefb5da374anthony } 538dbc8989a61339951c6434d9a43e7b6fefb5da374anthony 539dbc8989a61339951c6434d9a43e7b6fefb5da374anthony /* look for the next kernel in list */ 540dbc8989a61339951c6434d9a43e7b6fefb5da374anthony p = strchr(p, ';'); 541dbc8989a61339951c6434d9a43e7b6fefb5da374anthony if ( p == (char *) NULL ) 542dbc8989a61339951c6434d9a43e7b6fefb5da374anthony break; 543dbc8989a61339951c6434d9a43e7b6fefb5da374anthony p++; 5445ef8e94ff55717be2387d537bd49025780a1a558anthony 545dbc8989a61339951c6434d9a43e7b6fefb5da374anthony } 5467a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(kernel); 5475ef8e94ff55717be2387d537bd49025780a1a558anthony} 5485ef8e94ff55717be2387d537bd49025780a1a558anthony 549602ab9b30b644a78a4057da93d838a77391ec0acanthony 550602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 551602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 552602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 553602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 554602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 555602ab9b30b644a78a4057da93d838a77391ec0acanthony% A c q u i r e K e r n e l B u i l t I n % 556602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 557602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 558602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 559602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 560602ab9b30b644a78a4057da93d838a77391ec0acanthony% 561602ab9b30b644a78a4057da93d838a77391ec0acanthony% AcquireKernelBuiltIn() returned one of the 'named' built-in types of 562602ab9b30b644a78a4057da93d838a77391ec0acanthony% kernels used for special purposes such as gaussian blurring, skeleton 563602ab9b30b644a78a4057da93d838a77391ec0acanthony% pruning, and edge distance determination. 564602ab9b30b644a78a4057da93d838a77391ec0acanthony% 565602ab9b30b644a78a4057da93d838a77391ec0acanthony% They take a KernelType, and a set of geometry style arguments, which were 566602ab9b30b644a78a4057da93d838a77391ec0acanthony% typically decoded from a user supplied string, or from a more complex 567602ab9b30b644a78a4057da93d838a77391ec0acanthony% Morphology Method that was requested. 568602ab9b30b644a78a4057da93d838a77391ec0acanthony% 569602ab9b30b644a78a4057da93d838a77391ec0acanthony% The format of the AcquireKernalBuiltIn method is: 570602ab9b30b644a78a4057da93d838a77391ec0acanthony% 5712be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy% KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type, 572602ab9b30b644a78a4057da93d838a77391ec0acanthony% const GeometryInfo args) 573602ab9b30b644a78a4057da93d838a77391ec0acanthony% 574602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 575602ab9b30b644a78a4057da93d838a77391ec0acanthony% 576602ab9b30b644a78a4057da93d838a77391ec0acanthony% o type: the pre-defined type of kernel wanted 577602ab9b30b644a78a4057da93d838a77391ec0acanthony% 578602ab9b30b644a78a4057da93d838a77391ec0acanthony% o args: arguments defining or modifying the kernel 579602ab9b30b644a78a4057da93d838a77391ec0acanthony% 580602ab9b30b644a78a4057da93d838a77391ec0acanthony% Convolution Kernels 581602ab9b30b644a78a4057da93d838a77391ec0acanthony% 58246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Unity 583529482f4b494010a13338a74446c510712f670b3anthony% The a No-Op or Scaling single element kernel. 58446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 5853c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Gaussian:{radius},{sigma} 5862489f53a1153c2b619b1c9a6744602e8840bd9a9glennrp% Generate a two-dimensional gaussian kernel, as used by -gaussian. 587c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The sigma for the curve is required. The resulting kernel is 588c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% normalized, 589c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 590c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% If 'sigma' is zero, you get a single pixel on a field of zeros. 591602ab9b30b644a78a4057da93d838a77391ec0acanthony% 592602ab9b30b644a78a4057da93d838a77391ec0acanthony% NOTE: that the 'radius' is optional, but if provided can limit (clip) 593602ab9b30b644a78a4057da93d838a77391ec0acanthony% the final size of the resulting kernel to a square 2*radius+1 in size. 594602ab9b30b644a78a4057da93d838a77391ec0acanthony% The radius should be at least 2 times that of the sigma value, or 595602ab9b30b644a78a4057da93d838a77391ec0acanthony% sever clipping and aliasing may result. If not given or set to 0 the 596602ab9b30b644a78a4057da93d838a77391ec0acanthony% radius will be determined so as to produce the best minimal error 597602ab9b30b644a78a4057da93d838a77391ec0acanthony% result, which is usally much larger than is normally needed. 598602ab9b30b644a78a4057da93d838a77391ec0acanthony% 599501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% LoG:{radius},{sigma} 600501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% "Laplacian of a Gaussian" or "Mexician Hat" Kernel. 601501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% The supposed ideal edge detection, zero-summing kernel. 602501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 603501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% An alturnative to this kernel is to use a "DoG" with a sigma ratio of 604501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% approx 1.6 (according to wikipedia). 605501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 606501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% DoG:{radius},{sigma1},{sigma2} 607c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% "Difference of Gaussians" Kernel. 608c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% As "Gaussian" but with a gaussian produced by 'sigma2' subtracted 609c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% from the gaussian produced by 'sigma1'. Typically sigma2 > sigma1. 610c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The result is a zero-summing kernel. 611c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 612c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Blur:{radius},{sigma}[,{angle}] 6134c08aed51c5899665ade97263692328eea4af106cristy% Generates a 1 dimensional or linear gaussian blur, at the angle given 614c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% (current restricted to orthogonal angles). If a 'radius' is given the 615c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% kernel is clipped to a width of 2*radius+1. Kernel can be rotated 616c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% by a 90 degree angle. 617c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 618c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% If 'sigma' is zero, you get a single pixel on a field of zeros. 619c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 620c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Note that two convolutions with two "Blur" kernels perpendicular to 621f0a92fd8deb68d411304359906b12679b675691fglennrp% each other, is equivalent to a far larger "Gaussian" kernel with the 622c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% same sigma value, However it is much faster to apply. This is how the 623c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% "-blur" operator actually works. 624c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 6253c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Comet:{width},{sigma},{angle} 6263c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Blur in one direction only, much like how a bright object leaves 627602ab9b30b644a78a4057da93d838a77391ec0acanthony% a comet like trail. The Kernel is actually half a gaussian curve, 6283c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Adding two such blurs in opposite directions produces a Blur Kernel. 6293c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Angle can be rotated in multiples of 90 degrees. 630602ab9b30b644a78a4057da93d838a77391ec0acanthony% 6313c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Note that the first argument is the width of the kernel and not the 632602ab9b30b644a78a4057da93d838a77391ec0acanthony% radius of the kernel. 633602ab9b30b644a78a4057da93d838a77391ec0acanthony% 634602ab9b30b644a78a4057da93d838a77391ec0acanthony% # Still to be implemented... 635602ab9b30b644a78a4057da93d838a77391ec0acanthony% # 6364fd27e21043be809d66c8202e779255e5b660d2danthony% # Filter2D 6374fd27e21043be809d66c8202e779255e5b660d2danthony% # Filter1D 6384fd27e21043be809d66c8202e779255e5b660d2danthony% # Set kernel values using a resize filter, and given scale (sigma) 639dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp% # Cylindrical or Linear. Is this possible with an image? 6404fd27e21043be809d66c8202e779255e5b660d2danthony% # 641602ab9b30b644a78a4057da93d838a77391ec0acanthony% 6423c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Named Constant Convolution Kernels 6433c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 644c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% All these are unscaled, zero-summing kernels by default. As such for 645c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% non-HDRI version of ImageMagick some form of normalization, user scaling, 646c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% and biasing the results is recommended, to prevent the resulting image 647c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% being 'clipped'. 648c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 649c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The 3x3 kernels (most of these) can be circularly rotated in multiples of 650c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 45 degrees to generate the 8 angled varients of each of the kernels. 6513c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 6523c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Laplacian:{type} 65343c4925e5305a26e48d68f7893e94f55d0831c39anthony% Discrete Lapacian Kernels, (without normalization) 654c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Type 0 : 3x3 with center:8 surounded by -1 (8 neighbourhood) 655c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Type 1 : 3x3 with center:4 edge:-1 corner:0 (4 neighbourhood) 6569eb4f74649b23c053b308ce1152dce51239450baanthony% Type 2 : 3x3 with center:4 edge:1 corner:-2 6579eb4f74649b23c053b308ce1152dce51239450baanthony% Type 3 : 3x3 with center:4 edge:-2 corner:1 6589eb4f74649b23c053b308ce1152dce51239450baanthony% Type 5 : 5x5 laplacian 6599eb4f74649b23c053b308ce1152dce51239450baanthony% Type 7 : 7x7 laplacian 660501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Type 15 : 5x5 LoG (sigma approx 1.4) 661501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Type 19 : 9x9 LoG (sigma approx 1.4) 662c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 663c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Sobel:{angle} 66446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Sobel 'Edge' convolution kernel (3x3) 665c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 666c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 0,-2 | 667c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 668c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 669c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Roberts:{angle} 67046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Roberts convolution kernel (3x3) 671c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | 672c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 0 | 673c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | 674c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 675c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Prewitt:{angle} 676c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Prewitt Edge convolution kernel (3x3) 677c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 678c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 679c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 680c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 6819eb4f74649b23c053b308ce1152dce51239450baanthony% Compass:{angle} 6829eb4f74649b23c053b308ce1152dce51239450baanthony% Prewitt's "Compass" convolution kernel (3x3) 683c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 1 | 684c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1,-2, 1 | 685c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 1, 1 | 686c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 6879eb4f74649b23c053b308ce1152dce51239450baanthony% Kirsch:{angle} 6889eb4f74649b23c053b308ce1152dce51239450baanthony% Kirsch's "Compass" convolution kernel (3x3) 689c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3,-3, 5 | 690c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3, 0, 5 | 691c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -3,-3, 5 | 6923c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 693c40ac1e79923a1516075ba1197ae4ed90244af9banthony% FreiChen:{angle} 6941d5e67090dc7232b35bfcc71b31266c20838defcanthony% Frei-Chen Edge Detector is based on a kernel that is similar to 6951d5e67090dc7232b35bfcc71b31266c20838defcanthony% the Sobel Kernel, but is designed to be isotropic. That is it takes 6961d5e67090dc7232b35bfcc71b31266c20838defcanthony% into account the distance of the diagonal in the kernel. 697c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 698c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 699c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | 700c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 701c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 702c40ac1e79923a1516075ba1197ae4ed90244af9banthony% FreiChen:{type},{angle} 703c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 704c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Frei-Chen Pre-weighted kernels... 705c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 706c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 0: default un-nomalized version shown above. 707c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 708c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 1: Orthogonal Kernel (same as type 11 below) 709c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 710c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 711c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 712c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 713c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 2: Diagonal form of Kernel... 714c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, sqrt(2), 0 | 715c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 716c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, -sqrt(2) -1 | 717c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 7181d5e67090dc7232b35bfcc71b31266c20838defcanthony% However this kernel is als at the heart of the FreiChen Edge Detection 7191d5e67090dc7232b35bfcc71b31266c20838defcanthony% Process which uses a set of 9 specially weighted kernel. These 9 7201d5e67090dc7232b35bfcc71b31266c20838defcanthony% kernels not be normalized, but directly applied to the image. The 7211d5e67090dc7232b35bfcc71b31266c20838defcanthony% results is then added together, to produce the intensity of an edge in 7221d5e67090dc7232b35bfcc71b31266c20838defcanthony% a specific direction. The square root of the pixel value can then be 7231d5e67090dc7232b35bfcc71b31266c20838defcanthony% taken as the cosine of the edge, and at least 2 such runs at 90 degrees 7241d5e67090dc7232b35bfcc71b31266c20838defcanthony% from each other, both the direction and the strength of the edge can be 7251d5e67090dc7232b35bfcc71b31266c20838defcanthony% determined. 7261d5e67090dc7232b35bfcc71b31266c20838defcanthony% 727c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 10: All 9 of the following pre-weighted kernels... 728c40ac1e79923a1516075ba1197ae4ed90244af9banthony% 729c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 11: | 1, 0, -1 | 730c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2) 731c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, -1 | 732e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 733c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 12: | 1, sqrt(2), 1 | 734c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | / 2*sqrt(2) 735c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, sqrt(2), 1 | 736e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 737c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 13: | sqrt(2), -1, 0 | 738c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | / 2*sqrt(2) 739c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 1, -sqrt(2) | 740e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 741c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 14: | 0, 1, -sqrt(2) | 742c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | / 2*sqrt(2) 743c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | sqrt(2), -1, 0 | 744e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 745c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 15: | 0, -1, 0 | 746c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 0, 1 | / 2 747c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, -1, 0 | 748e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 749c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 16: | 1, 0, -1 | 750c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 0, 0, 0 | / 2 751c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, 0, 1 | 752e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 753c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 17: | 1, -2, 1 | 754c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 4, -2 | / 6 755c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -1, -2, 1 | 756501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% 757c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 18: | -2, 1, -2 | 758c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 4, 1 | / 6 759c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | -2, 1, -2 | 760e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 761c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Type 19: | 1, 1, 1 | 762c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 1, 1 | / 3 763c40ac1e79923a1516075ba1197ae4ed90244af9banthony% | 1, 1, 1 | 764e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 765e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% The first 4 are for edge detection, the next 4 are for line detection 766e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% and the last is to add a average component to the results. 767e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 768c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% Using a special type of '-1' will return all 9 pre-weighted kernels 769c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% as a multi-kernel list, so that you can use them directly (without 770c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% normalization) with the special "-set option:morphology:compose Plus" 771c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% setting to apply the full FreiChen Edge Detection Technique. 772c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony% 7731dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% If 'type' is large it will be taken to be an actual rotation angle for 7741dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% the default FreiChen (type 0) kernel. As such FreiChen:45 will look 7751dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% like a Sobel:45 but with 'sqrt(2)' instead of '2' values. 7761dd091ae3bc17edc26c16cc47f436a24bd48412aanthony% 777501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% WARNING: The above was layed out as per 778501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf 779501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% But rotated 90 degrees so direction is from left rather than the top. 780501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% I have yet to find any secondary confirmation of the above. The only 781501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% other source found was actual source code at 782501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf 783501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% Neigher paper defineds the kernels in a way that looks locical or 784501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% correct when taken as a whole. 785e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony% 786602ab9b30b644a78a4057da93d838a77391ec0acanthony% Boolean Kernels 787602ab9b30b644a78a4057da93d838a77391ec0acanthony% 7883c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Diamond:[{radius}[,{scale}]] 7891b2bc0a7da432e6e1cc0480280402df213faa940anthony% Generate a diamond shaped kernel with given radius to the points. 790602ab9b30b644a78a4057da93d838a77391ec0acanthony% Kernel size will again be radius*2+1 square and defaults to radius 1, 791602ab9b30b644a78a4057da93d838a77391ec0acanthony% generating a 3x3 kernel that is slightly larger than a square. 792602ab9b30b644a78a4057da93d838a77391ec0acanthony% 7933c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Square:[{radius}[,{scale}]] 794602ab9b30b644a78a4057da93d838a77391ec0acanthony% Generate a square shaped kernel of size radius*2+1, and defaulting 795602ab9b30b644a78a4057da93d838a77391ec0acanthony% to a 3x3 (radius 1). 796602ab9b30b644a78a4057da93d838a77391ec0acanthony% 7971ef941fea2534a0d20ba7d71307d35040247decbanthony% Octagon:[{radius}[,{scale}]] 7981ef941fea2534a0d20ba7d71307d35040247decbanthony% Generate octagonal shaped kernel of given radius and constant scale. 7990bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% Default radius is 3 producing a 7x7 kernel. A radius of 1 will result 8001ef941fea2534a0d20ba7d71307d35040247decbanthony% in "Diamond" kernel. 8011ef941fea2534a0d20ba7d71307d35040247decbanthony% 8023c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Disk:[{radius}[,{scale}]] 8031ef941fea2534a0d20ba7d71307d35040247decbanthony% Generate a binary disk, thresholded at the radius given, the radius 8041ef941fea2534a0d20ba7d71307d35040247decbanthony% may be a float-point value. Final Kernel size is floor(radius)*2+1 8050bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% square. A radius of 5.3 is the default. 8061ef941fea2534a0d20ba7d71307d35040247decbanthony% 8071ef941fea2534a0d20ba7d71307d35040247decbanthony% NOTE: That a low radii Disk kernels produce the same results as 8081ef941fea2534a0d20ba7d71307d35040247decbanthony% many of the previously defined kernels, but differ greatly at larger 8091ef941fea2534a0d20ba7d71307d35040247decbanthony% radii. Here is a table of equivalences... 8101ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:1" => "Diamond", "Octagon:1", or "Cross:1" 8111ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:1.5" => "Square" 8121ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2" => "Diamond:2" 8131ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2.5" => "Octagon" 8141ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:2.9" => "Square:2" 8150bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony% "Disk:3.5" => "Octagon:3" 8161ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:4.5" => "Octagon:4" 8171ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:5.4" => "Octagon:5" 8181ef941fea2534a0d20ba7d71307d35040247decbanthony% "Disk:6.4" => "Octagon:6" 8191ef941fea2534a0d20ba7d71307d35040247decbanthony% All other Disk shapes are unique to this kernel, but because a "Disk" 8201ef941fea2534a0d20ba7d71307d35040247decbanthony% is more circular when using a larger radius, using a larger radius is 8211ef941fea2534a0d20ba7d71307d35040247decbanthony% preferred over iterating the morphological operation. 822602ab9b30b644a78a4057da93d838a77391ec0acanthony% 823a9892d898acb81e1ec73106d892855fdc5a69427anthony% Rectangle:{geometry} 824a9892d898acb81e1ec73106d892855fdc5a69427anthony% Simply generate a rectangle of 1's with the size given. You can also 825a9892d898acb81e1ec73106d892855fdc5a69427anthony% specify the location of the 'control point', otherwise the closest 826a9892d898acb81e1ec73106d892855fdc5a69427anthony% pixel to the center of the rectangle is selected. 827a9892d898acb81e1ec73106d892855fdc5a69427anthony% 828a9892d898acb81e1ec73106d892855fdc5a69427anthony% Properly centered and odd sized rectangles work the best. 829a9892d898acb81e1ec73106d892855fdc5a69427anthony% 830c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Symbol Dilation Kernels 831c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 832c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% These kernel is not a good general morphological kernel, but is used 833c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% more for highlighting and marking any single pixels in an image using, 834c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a "Dilate" method as appropriate. 835c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 836c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% For the same reasons iterating these kernels does not produce the 837c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% same result as using a larger radius for the symbol. 838c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% 8393c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% Plus:[{radius}[,{scale}]] 8403dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Cross:[{radius}[,{scale}]] 841c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Generate a kernel in the shape of a 'plus' or a 'cross' with 842c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a each arm the length of the given radius (default 2). 8433dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% 844f0a92fd8deb68d411304359906b12679b675691fglennrp% NOTE: "plus:1" is equivalent to a "Diamond" kernel. 845602ab9b30b644a78a4057da93d838a77391ec0acanthony% 846c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Ring:{radius1},{radius2}[,{scale}] 847c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% A ring of the values given that falls between the two radii. 848c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Defaults to a ring of approximataly 3 radius in a 7x7 kernel. 849c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% This is the 'edge' pixels of the default "Disk" kernel, 850c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% More specifically, "Ring" -> "Ring:2.5,3.5,1.0" 8513dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% 8523dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Hit and Miss Kernels 853602ab9b30b644a78a4057da93d838a77391ec0acanthony% 8543dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Peak:radius1,radius2 855c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Find any peak larger than the pixels the fall between the two radii. 856c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% The default ring of pixels is as per "Ring". 85743c4925e5305a26e48d68f7893e94f55d0831c39anthony% Edges 858694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find flat orthogonal edges of a binary shape 8593dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Corners 860694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find 90 degree corners of a binary shape 861529482f4b494010a13338a74446c510712f670b3anthony% Diagonals:type 862529482f4b494010a13338a74446c510712f670b3anthony% A special kernel to thin the 'outside' of diagonals 863694934fa79dd310f727588b1d0a7481fa6170f1danthony% LineEnds:type 8643dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% Find end points of lines (for pruning a skeletion) 865694934fa79dd310f727588b1d0a7481fa6170f1danthony% Two types of lines ends (default to both) can be searched for 866694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 0: All line ends 867694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: single kernel for 4-conneected line ends 868694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: single kernel for simple line ends 8693dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% LineJunctions 87043c4925e5305a26e48d68f7893e94f55d0831c39anthony% Find three line junctions (within a skeletion) 871694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 0: all line junctions 872694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Y Junction kernel 873694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: Diagonal T Junction kernel 874694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 3: Orthogonal T Junction kernel 875694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 4: Diagonal X Junction kernel 876694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 5: Orthogonal + Junction kernel 877694934fa79dd310f727588b1d0a7481fa6170f1danthony% Ridges:type 878694934fa79dd310f727588b1d0a7481fa6170f1danthony% Find single pixel ridges or thin lines 879694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Fine single pixel thick lines and ridges 880694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: Find two pixel thick lines and ridges 8813dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony% ConvexHull 882a9892d898acb81e1ec73106d892855fdc5a69427anthony% Octagonal Thickening Kernel, to generate convex hulls of 45 degrees 883c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Skeleton:type 884c40ac1e79923a1516075ba1197ae4ed90244af9banthony% Traditional skeleton generating kernels. 885694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 1: Tradional Skeleton kernel (4 connected skeleton) 886694934fa79dd310f727588b1d0a7481fa6170f1danthony% Type 2: HIPR2 Skeleton kernel (8 connected skeleton) 887e816a586a13717bab2d6839ced6e5c3828a37f19anthony% Type 3: Thinning skeleton based on a ressearch paper by 8882b2290b46c246ce1f14cb78f1695394e4c4a3ddfanthony% Dan S. Bloomberg (Default Type) 889e816a586a13717bab2d6839ced6e5c3828a37f19anthony% ThinSE:type 890e816a586a13717bab2d6839ced6e5c3828a37f19anthony% A huge variety of Thinning Kernels designed to preserve conectivity. 891e816a586a13717bab2d6839ced6e5c3828a37f19anthony% many other kernel sets use these kernels as source definitions. 892e816a586a13717bab2d6839ced6e5c3828a37f19anthony% Type numbers are 41-49, 81-89, 481, and 482 which are based on 893e816a586a13717bab2d6839ced6e5c3828a37f19anthony% the super and sub notations used in the source research paper. 894602ab9b30b644a78a4057da93d838a77391ec0acanthony% 895602ab9b30b644a78a4057da93d838a77391ec0acanthony% Distance Measuring Kernels 896602ab9b30b644a78a4057da93d838a77391ec0acanthony% 897c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Different types of distance measuring methods, which are used with the 898c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% a 'Distance' morphology method for generating a gradient based on 899c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% distance from an edge of a binary shape, though there is a technique 900c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% for handling a anti-aliased shape. 901602ab9b30b644a78a4057da93d838a77391ec0acanthony% 902c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% See the 'Distance' Morphological Method, for information of how it is 903c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% applied. 904602ab9b30b644a78a4057da93d838a77391ec0acanthony% 905c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Chebyshev:[{radius}][x{scale}[%!]] 9061ef941fea2534a0d20ba7d71307d35040247decbanthony% Chebyshev Distance (also known as Tchebychev or Chessboard distance) 9071ef941fea2534a0d20ba7d71307d35040247decbanthony% is a value of one to any neighbour, orthogonal or diagonal. One why 9081ef941fea2534a0d20ba7d71307d35040247decbanthony% of thinking of it is the number of squares a 'King' or 'Queen' in 9091ef941fea2534a0d20ba7d71307d35040247decbanthony% chess needs to traverse reach any other position on a chess board. 9101ef941fea2534a0d20ba7d71307d35040247decbanthony% It results in a 'square' like distance function, but one where 9111ef941fea2534a0d20ba7d71307d35040247decbanthony% diagonals are given a value that is closer than expected. 912c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 913bee715c4c0fd9efe6e21d8627ae8664434df7750anthony% Manhattan:[{radius}][x{scale}[%!]] 9141ef941fea2534a0d20ba7d71307d35040247decbanthony% Manhattan Distance (also known as Rectilinear, City Block, or the Taxi 9151ef941fea2534a0d20ba7d71307d35040247decbanthony% Cab distance metric), it is the distance needed when you can only 9161ef941fea2534a0d20ba7d71307d35040247decbanthony% travel in horizontal or vertical directions only. It is the 9171ef941fea2534a0d20ba7d71307d35040247decbanthony% distance a 'Rook' in chess would have to travel, and results in a 9181ef941fea2534a0d20ba7d71307d35040247decbanthony% diamond like distances, where diagonals are further than expected. 9191ef941fea2534a0d20ba7d71307d35040247decbanthony% 9201ef941fea2534a0d20ba7d71307d35040247decbanthony% Octagonal:[{radius}][x{scale}[%!]] 9211ef941fea2534a0d20ba7d71307d35040247decbanthony% An interleving of Manhatten and Chebyshev metrics producing an 9221ef941fea2534a0d20ba7d71307d35040247decbanthony% increasing octagonally shaped distance. Distances matches those of 9231ef941fea2534a0d20ba7d71307d35040247decbanthony% the "Octagon" shaped kernel of the same radius. The minimum radius 9241ef941fea2534a0d20ba7d71307d35040247decbanthony% and default is 2, producing a 5x5 kernel. 925c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 926c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony% Euclidean:[{radius}][x{scale}[%!]] 9271ef941fea2534a0d20ba7d71307d35040247decbanthony% Euclidean distance is the 'direct' or 'as the crow flys' distance. 928c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% However by default the kernel size only has a radius of 1, which 929c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% limits the distance to 'Knight' like moves, with only orthogonal and 930c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% diagonal measurements being correct. As such for the default kernel 9311ef941fea2534a0d20ba7d71307d35040247decbanthony% you will get octagonal like distance function. 9321ef941fea2534a0d20ba7d71307d35040247decbanthony% 9331ef941fea2534a0d20ba7d71307d35040247decbanthony% However using a larger radius such as "Euclidean:4" you will get a 9341ef941fea2534a0d20ba7d71307d35040247decbanthony% much smoother distance gradient from the edge of the shape. Especially 9351ef941fea2534a0d20ba7d71307d35040247decbanthony% if the image is pre-processed to include any anti-aliasing pixels. 9361ef941fea2534a0d20ba7d71307d35040247decbanthony% Of course a larger kernel is slower to use, and not always needed. 9371ef941fea2534a0d20ba7d71307d35040247decbanthony% 9381ef941fea2534a0d20ba7d71307d35040247decbanthony% The first three Distance Measuring Kernels will only generate distances 9391ef941fea2534a0d20ba7d71307d35040247decbanthony% of exact multiples of {scale} in binary images. As such you can use a 9401ef941fea2534a0d20ba7d71307d35040247decbanthony% scale of 1 without loosing any information. However you also need some 9411ef941fea2534a0d20ba7d71307d35040247decbanthony% scaling when handling non-binary anti-aliased shapes. 9421ef941fea2534a0d20ba7d71307d35040247decbanthony% 9431ef941fea2534a0d20ba7d71307d35040247decbanthony% The "Euclidean" Distance Kernel however does generate a non-integer 9441ef941fea2534a0d20ba7d71307d35040247decbanthony% fractional results, and as such scaling is vital even for binary shapes. 945c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% 946602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 947602ab9b30b644a78a4057da93d838a77391ec0acanthony 9482be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristyMagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type, 949602ab9b30b644a78a4057da93d838a77391ec0acanthony const GeometryInfo *args) 950602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 9512be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy KernelInfo 952602ab9b30b644a78a4057da93d838a77391ec0acanthony *kernel; 953602ab9b30b644a78a4057da93d838a77391ec0acanthony 954bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 955602ab9b30b644a78a4057da93d838a77391ec0acanthony i; 956602ab9b30b644a78a4057da93d838a77391ec0acanthony 957bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 958602ab9b30b644a78a4057da93d838a77391ec0acanthony u, 959602ab9b30b644a78a4057da93d838a77391ec0acanthony v; 960602ab9b30b644a78a4057da93d838a77391ec0acanthony 961602ab9b30b644a78a4057da93d838a77391ec0acanthony double 962602ab9b30b644a78a4057da93d838a77391ec0acanthony nan = sqrt((double)-1.0); /* Special Value : Not A Number */ 963602ab9b30b644a78a4057da93d838a77391ec0acanthony 964c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Generate a new empty kernel if needed */ 965e96405a0f45f803fb9c26f75e7bdee252437febbcristy kernel=(KernelInfo *) NULL; 966c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony switch(type) { 9671dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case UndefinedKernel: /* These should not call this function */ 9689eb4f74649b23c053b308ce1152dce51239450baanthony case UserDefinedKernel: 969529482f4b494010a13338a74446c510712f670b3anthony assert("Should not call this function" != (char *)NULL); 9709eb4f74649b23c053b308ce1152dce51239450baanthony break; 971529482f4b494010a13338a74446c510712f670b3anthony case LaplacianKernel: /* Named Descrete Convolution Kernels */ 972529482f4b494010a13338a74446c510712f670b3anthony case SobelKernel: /* these are defined using other kernels */ 9739eb4f74649b23c053b308ce1152dce51239450baanthony case RobertsKernel: 9749eb4f74649b23c053b308ce1152dce51239450baanthony case PrewittKernel: 9759eb4f74649b23c053b308ce1152dce51239450baanthony case CompassKernel: 9769eb4f74649b23c053b308ce1152dce51239450baanthony case KirschKernel: 9771dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case FreiChenKernel: 978694934fa79dd310f727588b1d0a7481fa6170f1danthony case EdgesKernel: /* Hit and Miss kernels */ 979694934fa79dd310f727588b1d0a7481fa6170f1danthony case CornersKernel: 980529482f4b494010a13338a74446c510712f670b3anthony case DiagonalsKernel: 9819eb4f74649b23c053b308ce1152dce51239450baanthony case LineEndsKernel: 9829eb4f74649b23c053b308ce1152dce51239450baanthony case LineJunctionsKernel: 9831dd091ae3bc17edc26c16cc47f436a24bd48412aanthony case RidgesKernel: 9849eb4f74649b23c053b308ce1152dce51239450baanthony case ConvexHullKernel: 9859eb4f74649b23c053b308ce1152dce51239450baanthony case SkeletonKernel: 9869a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case ThinSEKernel: 987c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; /* A pre-generated kernel is not needed */ 988c40ac1e79923a1516075ba1197ae4ed90244af9banthony#if 0 989c40ac1e79923a1516075ba1197ae4ed90244af9banthony /* set to 1 to do a compile-time check that we haven't missed anything */ 990529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 991c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case GaussianKernel: 992501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 993501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 994c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case BlurKernel: 995c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CometKernel: 996c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiamondKernel: 997c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SquareKernel: 998c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RectangleKernel: 9991ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 1000c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiskKernel: 1001c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PlusKernel: 1002c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CrossKernel: 1003c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RingKernel: 1004c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PeaksKernel: 1005c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case ChebyshevKernel: 1006bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 10071ef941fea2534a0d20ba7d71307d35040247decbanthony case OctangonalKernel: 1008c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case EuclideanKernel: 10091dd091ae3bc17edc26c16cc47f436a24bd48412aanthony#else 10109eb4f74649b23c053b308ce1152dce51239450baanthony default: 10111dd091ae3bc17edc26c16cc47f436a24bd48412aanthony#endif 10129eb4f74649b23c053b308ce1152dce51239450baanthony /* Generate the base Kernel Structure */ 1013c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel)); 1014c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1015c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1016c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony (void) ResetMagickMemory(kernel,0,sizeof(*kernel)); 101743c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->minimum = kernel->maximum = kernel->angle = 0.0; 1018c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->negative_range = kernel->positive_range = 0.0; 1019c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 1020c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->next = (KernelInfo *) NULL; 1021c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->signature = MagickSignature; 1022c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1023c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1024602ab9b30b644a78a4057da93d838a77391ec0acanthony 1025602ab9b30b644a78a4057da93d838a77391ec0acanthony switch(type) { 1026529482f4b494010a13338a74446c510712f670b3anthony /* 1027529482f4b494010a13338a74446c510712f670b3anthony Convolution Kernels 1028529482f4b494010a13338a74446c510712f670b3anthony */ 1029529482f4b494010a13338a74446c510712f670b3anthony case UnityKernel: 1030529482f4b494010a13338a74446c510712f670b3anthony { 1031529482f4b494010a13338a74446c510712f670b3anthony kernel->height = kernel->width = (size_t) 1; 1032529482f4b494010a13338a74446c510712f670b3anthony kernel->x = kernel->y = (ssize_t) 0; 10335e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(1,sizeof(double)); 1034529482f4b494010a13338a74446c510712f670b3anthony if (kernel->values == (double *) NULL) 1035529482f4b494010a13338a74446c510712f670b3anthony return(DestroyKernelInfo(kernel)); 1036529482f4b494010a13338a74446c510712f670b3anthony kernel->maximum = kernel->values[0] = args->rho; 1037529482f4b494010a13338a74446c510712f670b3anthony break; 1038529482f4b494010a13338a74446c510712f670b3anthony } 1039529482f4b494010a13338a74446c510712f670b3anthony break; 1040602ab9b30b644a78a4057da93d838a77391ec0acanthony case GaussianKernel: 1041501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 1042501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 1043602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 1044c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma = fabs(args->sigma), 1045c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma2 = fabs(args->xi), 10469eb4f74649b23c053b308ce1152dce51239450baanthony A, B, R; 1047c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1048c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( args->rho >= 1.0 ) 1049bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho*2+1; 1050501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony else if ( (type != DoGKernel) || (sigma >= sigma2) ) 1051c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = GetOptimalKernelWidth2D(args->rho,sigma); 1052c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1053c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2); 1054c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->height = kernel->width; 1055bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 10565e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 1057602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height*sizeof(double)); 1058602ab9b30b644a78a4057da93d838a77391ec0acanthony if (kernel->values == (double *) NULL) 105983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1060602ab9b30b644a78a4057da93d838a77391ec0acanthony 106146a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* WARNING: The following generates a 'sampled gaussian' kernel. 10629eb4f74649b23c053b308ce1152dce51239450baanthony * What we really want is a 'discrete gaussian' kernel. 106346a369d839971ab627bdb31a93d8bd63e81b65a3anthony * 1064529482f4b494010a13338a74446c510712f670b3anthony * How to do this is I don't know, but appears to be basied on the 1065529482f4b494010a13338a74446c510712f670b3anthony * Error Function 'erf()' (intergral of a gaussian) 10669eb4f74649b23c053b308ce1152dce51239450baanthony */ 10679eb4f74649b23c053b308ce1152dce51239450baanthony 1068501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == GaussianKernel || type == DoGKernel ) 1069501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony { /* Calculate a Gaussian, OR positive half of a DoG */ 10709eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 10719eb4f74649b23c053b308ce1152dce51239450baanthony { A = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 107255a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(Magick2PI*sigma*sigma)); 1073bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1074bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 10759eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] = exp(-((double)(u*u+v*v))*A)*B; 10769eb4f74649b23c053b308ce1152dce51239450baanthony } 10779eb4f74649b23c053b308ce1152dce51239450baanthony else /* limiting case - a unity (normalized Dirac) kernel */ 10789eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 10799eb4f74649b23c053b308ce1152dce51239450baanthony kernel->width*kernel->height*sizeof(double)); 10809eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 10819eb4f74649b23c053b308ce1152dce51239450baanthony } 1082c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 10839eb4f74649b23c053b308ce1152dce51239450baanthony 1084501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == DoGKernel ) 1085c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { /* Subtract a Negative Gaussian for "Difference of Gaussian" */ 1086c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma2 > MagickEpsilon ) 1087c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { sigma = sigma2; /* simplify loop expressions */ 10889eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); 108955a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(Magick2PI*sigma*sigma)); 1090bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1091bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 10929eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] -= exp(-((double)(u*u+v*v))*A)*B; 1093c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 10949eb4f74649b23c053b308ce1152dce51239450baanthony else /* limiting case - a unity (normalized Dirac) kernel */ 1095c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] -= 1.0; 1096c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 10979eb4f74649b23c053b308ce1152dce51239450baanthony 1098501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony if ( type == LoGKernel ) 10999eb4f74649b23c053b308ce1152dce51239450baanthony { /* Calculate a Laplacian of a Gaussian - Or Mexician Hat */ 11009eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 11019eb4f74649b23c053b308ce1152dce51239450baanthony { A = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 110255a91cddcdea3aa002893186a773e1704884a9dfcristy B = (double) (1.0/(MagickPI*sigma*sigma*sigma*sigma)); 1103bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1104bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 11059eb4f74649b23c053b308ce1152dce51239450baanthony { R = ((double)(u*u+v*v))*A; 11069eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] = (1-R)*exp(-R)*B; 11079eb4f74649b23c053b308ce1152dce51239450baanthony } 11089eb4f74649b23c053b308ce1152dce51239450baanthony } 11099eb4f74649b23c053b308ce1152dce51239450baanthony else /* special case - generate a unity kernel */ 11109eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 11119eb4f74649b23c053b308ce1152dce51239450baanthony kernel->width*kernel->height*sizeof(double)); 11129eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 11139eb4f74649b23c053b308ce1152dce51239450baanthony } 11149eb4f74649b23c053b308ce1152dce51239450baanthony } 11159eb4f74649b23c053b308ce1152dce51239450baanthony 11169eb4f74649b23c053b308ce1152dce51239450baanthony /* Note the above kernels may have been 'clipped' by a user defined 1117c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** radius, producing a smaller (darker) kernel. Also for very small 1118c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** sigma's (> 0.1) the central value becomes larger than one, and thus 1119c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** producing a very bright kernel. 1120c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 1121c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** Normalization will still be needed. 1122c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony */ 1123602ab9b30b644a78a4057da93d838a77391ec0acanthony 11243dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* Normalize the 2D Gaussian Kernel 11253dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** 1126c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** NB: a CorrelateNormalize performs a normal Normalize if 1127c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there are no negative values. 11283dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony */ 112946a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* the other kernel meta-data */ 1130c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue); 1131602ab9b30b644a78a4057da93d838a77391ec0acanthony 1132602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1133602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1134602ab9b30b644a78a4057da93d838a77391ec0acanthony case BlurKernel: 1135602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 1136c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony sigma = fabs(args->sigma), 1137501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony alpha, beta; 1138602ab9b30b644a78a4057da93d838a77391ec0acanthony 1139c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( args->rho >= 1.0 ) 1140bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho*2+1; 1141c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1142501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->width = GetOptimalKernelWidth1D(args->rho,sigma); 1143602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height = 1; 1144bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) (kernel->width-1)/2; 1145c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->y = 0; 1146c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 11475e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 1148602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height*sizeof(double)); 1149602ab9b30b644a78a4057da93d838a77391ec0acanthony if (kernel->values == (double *) NULL) 115083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1151602ab9b30b644a78a4057da93d838a77391ec0acanthony 1152602ab9b30b644a78a4057da93d838a77391ec0acanthony#if 1 1153602ab9b30b644a78a4057da93d838a77391ec0acanthony#define KernelRank 3 1154602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Formula derived from GetBlurKernel() in "effect.c" (plus bug fix). 1155602ab9b30b644a78a4057da93d838a77391ec0acanthony ** It generates a gaussian 3 times the width, and compresses it into 1156602ab9b30b644a78a4057da93d838a77391ec0acanthony ** the expected range. This produces a closer normalization of the 1157602ab9b30b644a78a4057da93d838a77391ec0acanthony ** resulting kernel, especially for very low sigma values. 1158602ab9b30b644a78a4057da93d838a77391ec0acanthony ** As such while wierd it is prefered. 1159602ab9b30b644a78a4057da93d838a77391ec0acanthony ** 1160602ab9b30b644a78a4057da93d838a77391ec0acanthony ** I am told this method originally came from Photoshop. 11619eb4f74649b23c053b308ce1152dce51239450baanthony ** 11629eb4f74649b23c053b308ce1152dce51239450baanthony ** A properly normalized curve is generated (apart from edge clipping) 11639eb4f74649b23c053b308ce1152dce51239450baanthony ** even though we later normalize the result (for edge clipping) 11649eb4f74649b23c053b308ce1152dce51239450baanthony ** to allow the correct generation of a "Difference of Blurs". 1165602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 1166c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1167c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* initialize */ 1168bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy v = (ssize_t) (kernel->width*KernelRank-1)/2; /* start/end points to fit range */ 11699eb4f74649b23c053b308ce1152dce51239450baanthony (void) ResetMagickMemory(kernel->values,0, (size_t) 11709eb4f74649b23c053b308ce1152dce51239450baanthony kernel->width*kernel->height*sizeof(double)); 1171c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Calculate a Positive 1D Gaussian */ 1172c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma > MagickEpsilon ) 1173c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { sigma *= KernelRank; /* simplify loop expressions */ 1174501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony alpha = 1.0/(2.0*sigma*sigma); 117555a91cddcdea3aa002893186a773e1704884a9dfcristy beta= (double) (1.0/(MagickSQ2PI*sigma )); 1176c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony for ( u=-v; u <= v; u++) { 1177501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[(u+v)/KernelRank] += 1178501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony exp(-((double)(u*u))*alpha)*beta; 1179c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1180c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1181c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else /* special case - generate a unity kernel */ 1182c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 1183602ab9b30b644a78a4057da93d838a77391ec0acanthony#else 1184c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Direct calculation without curve averaging */ 1185c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1186c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Calculate a Positive Gaussian */ 1187c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if ( sigma > MagickEpsilon ) 1188501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony { alpha = 1.0/(2.0*sigma*sigma); /* simplify loop expressions */ 1189501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony beta = 1.0/(MagickSQ2PI*sigma); 1190bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 1191501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[i] = exp(-((double)(u*u))*alpha)*beta; 1192c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1193c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else /* special case - generate a unity kernel */ 1194c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 1195c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width*kernel->height*sizeof(double)); 1196c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 1197c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1198602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 1199c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* Note the above kernel may have been 'clipped' by a user defined 1200cc6c836da2a53b6023b716e4973090a6714dc3b0anthony ** radius, producing a smaller (darker) kernel. Also for very small 1201cc6c836da2a53b6023b716e4973090a6714dc3b0anthony ** sigma's (> 0.1) the central value becomes larger than one, and thus 1202cc6c836da2a53b6023b716e4973090a6714dc3b0anthony ** producing a very bright kernel. 1203c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 1204c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** Normalization will still be needed. 1205602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 1206cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 1207602ab9b30b644a78a4057da93d838a77391ec0acanthony /* Normalize the 1D Gaussian Kernel 1208602ab9b30b644a78a4057da93d838a77391ec0acanthony ** 1209c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** NB: a CorrelateNormalize performs a normal Normalize if 1210c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there are no negative values. 1211602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 121246a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* the other kernel meta-data */ 121346a369d839971ab627bdb31a93d8bd63e81b65a3anthony ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue); 1214cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 1215c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* rotate the 1D kernel by given angle */ 1216501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony RotateKernelInfo(kernel, args->xi ); 1217602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1218602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1219602ab9b30b644a78a4057da93d838a77391ec0acanthony case CometKernel: 1220602ab9b30b644a78a4057da93d838a77391ec0acanthony { double 12219eb4f74649b23c053b308ce1152dce51239450baanthony sigma = fabs(args->sigma), 12229eb4f74649b23c053b308ce1152dce51239450baanthony A; 1223602ab9b30b644a78a4057da93d838a77391ec0acanthony 1224602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->rho < 1.0 ) 1225e1cf9465864144e8b8043d522906c1e47bbf6192anthony kernel->width = (GetOptimalKernelWidth1D(args->rho,sigma)-1)/2+1; 1226602ab9b30b644a78a4057da93d838a77391ec0acanthony else 1227bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho; 1228c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->x = kernel->y = 0; 1229602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height = 1; 1230c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->negative_range = kernel->positive_range = 0.0; 12315e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 1232602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height*sizeof(double)); 1233602ab9b30b644a78a4057da93d838a77391ec0acanthony if (kernel->values == (double *) NULL) 123483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1235602ab9b30b644a78a4057da93d838a77391ec0acanthony 1236c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* A comet blur is half a 1D gaussian curve, so that the object is 1237602ab9b30b644a78a4057da93d838a77391ec0acanthony ** blurred in one direction only. This may not be quite the right 12383dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** curve to use so may change in the future. The function must be 12393dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony ** normalised after generation, which also resolves any clipping. 1240c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 1241c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** As we are normalizing and not subtracting gaussians, 1242c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** there is no need for a divisor in the gaussian formula 1243c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony ** 124443c4925e5305a26e48d68f7893e94f55d0831c39anthony ** It is less comples 1245602ab9b30b644a78a4057da93d838a77391ec0acanthony */ 12469eb4f74649b23c053b308ce1152dce51239450baanthony if ( sigma > MagickEpsilon ) 12479eb4f74649b23c053b308ce1152dce51239450baanthony { 1248602ab9b30b644a78a4057da93d838a77391ec0acanthony#if 1 1249602ab9b30b644a78a4057da93d838a77391ec0acanthony#define KernelRank 3 1250bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy v = (ssize_t) kernel->width*KernelRank; /* start/end points */ 12519eb4f74649b23c053b308ce1152dce51239450baanthony (void) ResetMagickMemory(kernel->values,0, (size_t) 12529eb4f74649b23c053b308ce1152dce51239450baanthony kernel->width*sizeof(double)); 12539eb4f74649b23c053b308ce1152dce51239450baanthony sigma *= KernelRank; /* simplify the loop expression */ 12549eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); 12559eb4f74649b23c053b308ce1152dce51239450baanthony /* B = 1.0/(MagickSQ2PI*sigma); */ 12569eb4f74649b23c053b308ce1152dce51239450baanthony for ( u=0; u < v; u++) { 12579eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[u/KernelRank] += 12589eb4f74649b23c053b308ce1152dce51239450baanthony exp(-((double)(u*u))*A); 12599eb4f74649b23c053b308ce1152dce51239450baanthony /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */ 12609eb4f74649b23c053b308ce1152dce51239450baanthony } 1261bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) kernel->width; i++) 12629eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range += kernel->values[i]; 1263602ab9b30b644a78a4057da93d838a77391ec0acanthony#else 12649eb4f74649b23c053b308ce1152dce51239450baanthony A = 1.0/(2.0*sigma*sigma); /* simplify the loop expression */ 12659eb4f74649b23c053b308ce1152dce51239450baanthony /* B = 1.0/(MagickSQ2PI*sigma); */ 1266bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0; i < (ssize_t) kernel->width; i++) 12679eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range += 12689eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[i] = 12699eb4f74649b23c053b308ce1152dce51239450baanthony exp(-((double)(i*i))*A); 12709eb4f74649b23c053b308ce1152dce51239450baanthony /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */ 1271602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 12729eb4f74649b23c053b308ce1152dce51239450baanthony } 12739eb4f74649b23c053b308ce1152dce51239450baanthony else /* special case - generate a unity kernel */ 12749eb4f74649b23c053b308ce1152dce51239450baanthony { (void) ResetMagickMemory(kernel->values,0, (size_t) 12759eb4f74649b23c053b308ce1152dce51239450baanthony kernel->width*kernel->height*sizeof(double)); 12769eb4f74649b23c053b308ce1152dce51239450baanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 12779eb4f74649b23c053b308ce1152dce51239450baanthony kernel->positive_range = 1.0; 12789eb4f74649b23c053b308ce1152dce51239450baanthony } 127946a369d839971ab627bdb31a93d8bd63e81b65a3anthony 128046a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->minimum = 0.0; 1281c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 128246a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->negative_range = 0.0; 1283602ab9b30b644a78a4057da93d838a77391ec0acanthony 1284999bb2c20aa9d42875bb5adba44951988d4ae354anthony ScaleKernelInfo(kernel, 1.0, NormalizeValue); /* Normalize */ 1285999bb2c20aa9d42875bb5adba44951988d4ae354anthony RotateKernelInfo(kernel, args->xi); /* Rotate by angle */ 1286602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 1287602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1288c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1289529482f4b494010a13338a74446c510712f670b3anthony /* 1290529482f4b494010a13338a74446c510712f670b3anthony Convolution Kernels - Well Known Named Constant Kernels 1291529482f4b494010a13338a74446c510712f670b3anthony */ 12923c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony case LaplacianKernel: 1293e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony { switch ( (int) args->rho ) { 12943dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case 0: 12959eb4f74649b23c053b308ce1152dce51239450baanthony default: /* laplacian square filter -- default */ 1296c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: -1,-1,-1 -1,8,-1 -1,-1,-1"); 12973dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony break; 12989eb4f74649b23c053b308ce1152dce51239450baanthony case 1: /* laplacian diamond filter */ 1299c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: 0,-1,0 -1,4,-1 0,-1,0"); 13003c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13013c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony case 2: 13029eb4f74649b23c053b308ce1152dce51239450baanthony kernel=ParseKernelArray("3: -2,1,-2 1,4,1 -2,1,-2"); 13039eb4f74649b23c053b308ce1152dce51239450baanthony break; 13049eb4f74649b23c053b308ce1152dce51239450baanthony case 3: 1305c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel=ParseKernelArray("3: 1,-2,1 -2,4,-2 1,-2,1"); 13063c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13079eb4f74649b23c053b308ce1152dce51239450baanthony case 5: /* a 5x5 laplacian */ 13083c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel=ParseKernelArray( 13099eb4f74649b23c053b308ce1152dce51239450baanthony "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"); 13103c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13119eb4f74649b23c053b308ce1152dce51239450baanthony case 7: /* a 7x7 laplacian */ 13123c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel=ParseKernelArray( 1313c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony "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" ); 13143c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 1315501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case 15: /* a 5x5 LoG (sigma approx 1.4) */ 13169eb4f74649b23c053b308ce1152dce51239450baanthony kernel=ParseKernelArray( 13179eb4f74649b23c053b308ce1152dce51239450baanthony "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"); 13189eb4f74649b23c053b308ce1152dce51239450baanthony break; 1319501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case 19: /* a 9x9 LoG (sigma approx 1.4) */ 132043c4925e5305a26e48d68f7893e94f55d0831c39anthony /* http://www.cscjournals.org/csc/manuscript/Journals/IJIP/volume3/Issue1/IJIP-15.pdf */ 132143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel=ParseKernelArray( 1322bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony "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"); 132343c4925e5305a26e48d68f7893e94f55d0831c39anthony break; 13243c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 13253c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if (kernel == (KernelInfo *) NULL) 13263c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony return(kernel); 13273c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->type = type; 13283c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony break; 13293c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 1330c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SobelKernel: 1331cceb6f05c2016ea3854b29e7770ec5ff49034ecfanthony { /* Simple Sobel Kernel */ 1332dcc2a474c98415e565434fe52f630acba36fa0c1anthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1333dcc2a474c98415e565434fe52f630acba36fa0c1anthony if (kernel == (KernelInfo *) NULL) 1334dcc2a474c98415e565434fe52f630acba36fa0c1anthony return(kernel); 1335dcc2a474c98415e565434fe52f630acba36fa0c1anthony kernel->type = type; 1336dcc2a474c98415e565434fe52f630acba36fa0c1anthony RotateKernelInfo(kernel, args->rho); 1337dcc2a474c98415e565434fe52f630acba36fa0c1anthony break; 1338dcc2a474c98415e565434fe52f630acba36fa0c1anthony } 1339c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RobertsKernel: 1340c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1341501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 0,0,0 1,-1,0 0,0,0"); 1342c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1343c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1344c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 134546a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1346c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1347c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1348c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case PrewittKernel: 1349c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1350501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 1,0,-1 1,0,-1"); 1351c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1352c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1353c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 135446a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1355c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1356c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1357c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case CompassKernel: 1358c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 1359501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,1,-1 1,-2,-1 1,1,-1"); 1360c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 1361c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 1362c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->type = type; 136346a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 1364c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1365c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 13669eb4f74649b23c053b308ce1152dce51239450baanthony case KirschKernel: 13679eb4f74649b23c053b308ce1152dce51239450baanthony { 1368501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 5,-3,-3 5,0,-3 5,-3,-3"); 13699eb4f74649b23c053b308ce1152dce51239450baanthony if (kernel == (KernelInfo *) NULL) 13709eb4f74649b23c053b308ce1152dce51239450baanthony return(kernel); 13719eb4f74649b23c053b308ce1152dce51239450baanthony kernel->type = type; 137246a369d839971ab627bdb31a93d8bd63e81b65a3anthony RotateKernelInfo(kernel, args->rho); 13739eb4f74649b23c053b308ce1152dce51239450baanthony break; 13749eb4f74649b23c053b308ce1152dce51239450baanthony } 1375e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony case FreiChenKernel: 1376501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* Direction is set to be left to right positive */ 1377501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf -- RIGHT? */ 1378501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf -- WRONG? */ 13791dd091ae3bc17edc26c16cc47f436a24bd48412aanthony { switch ( (int) args->rho ) { 1380e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony default: 1381c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony case 0: 1382501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1383c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony if (kernel == (KernelInfo *) NULL) 1384c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony return(kernel); 1385ef33d9f66f955c1f6f5f7105e164cc2d5c5e2a41anthony kernel->type = type; 1386501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[3] = +MagickSQ2; 1387501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[5] = -MagickSQ2; 1388c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 1389c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony break; 1390c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 2: 1391c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel=ParseKernelArray("3: 1,2,0 2,0,-2 0,-2,-1"); 1392c40ac1e79923a1516075ba1197ae4ed90244af9banthony if (kernel == (KernelInfo *) NULL) 1393c40ac1e79923a1516075ba1197ae4ed90244af9banthony return(kernel); 1394c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel->type = type; 1395c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel->values[1] = kernel->values[3] = +MagickSQ2; 1396c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel->values[5] = kernel->values[7] = -MagickSQ2; 1397c40ac1e79923a1516075ba1197ae4ed90244af9banthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 1398d4e3ffa7f64077da0f32c2d8a599737ee8d115ddcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1399c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; 1400c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 10: 1401c40ac1e79923a1516075ba1197ae4ed90244af9banthony kernel=AcquireKernelInfo("FreiChen:11;FreiChen:12;FreiChen:13;FreiChen:14;FreiChen:15;FreiChen:16;FreiChen:17;FreiChen:18;FreiChen:19"); 1402c40ac1e79923a1516075ba1197ae4ed90244af9banthony if (kernel == (KernelInfo *) NULL) 1403c40ac1e79923a1516075ba1197ae4ed90244af9banthony return(kernel); 1404c40ac1e79923a1516075ba1197ae4ed90244af9banthony break; 1405e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony case 1: 1406c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 11: 1407501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,0,-1 2,0,-2 1,0,-1"); 1408e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1409e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1410c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1411501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[3] = +MagickSQ2; 1412501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[5] = -MagickSQ2; 1413e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); /* recalculate meta-data */ 141455a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1415e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1416c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 12: 1417501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,2,1 0,0,0 1,2,1"); 1418e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1419e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1420c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 14211d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel->values[1] = +MagickSQ2; 14221d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel->values[7] = +MagickSQ2; 1423e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 142455a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1425e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1426c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 13: 1427501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 2,-1,0 -1,0,1 0,1,-2"); 1428e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1429e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1430c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1431501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[0] = +MagickSQ2; 1432501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel->values[8] = -MagickSQ2; 1433e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 143455a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1435e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1436c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 14: 14371d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel=ParseKernelArray("3: 0,1,-2 -1,0,1 2,-1,0"); 1438e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1439e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1440c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 14411d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel->values[2] = -MagickSQ2; 14421d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel->values[6] = +MagickSQ2; 1443e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony CalcKernelMetaData(kernel); 144455a91cddcdea3aa002893186a773e1704884a9dfcristy ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue); 1445e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1446c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 15: 1447501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 0,-1,0 1,0,1 0,-1,0"); 1448e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1449e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1450c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1451e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/2.0, NoValue); 1452e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1453c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 16: 14541d5e67090dc7232b35bfcc71b31266c20838defcanthony kernel=ParseKernelArray("3: 1,0,-1 0,0,0 -1,0,1"); 1455e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1456e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1457c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1458e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/2.0, NoValue); 1459e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1460c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 17: 1461501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: 1,-2,1 -2,4,-2 -1,-2,1"); 1462e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1463e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1464c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1465e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/6.0, NoValue); 1466e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1467c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 18: 1468501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony kernel=ParseKernelArray("3: -2,1,-2 1,4,1 -2,1,-2"); 1469e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1470e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1471c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1472e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/6.0, NoValue); 1473e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1474c40ac1e79923a1516075ba1197ae4ed90244af9banthony case 19: 1475c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel=ParseKernelArray("3: 1,1,1 1,1,1 1,1,1"); 1476e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony if (kernel == (KernelInfo *) NULL) 1477e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony return(kernel); 1478c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony kernel->type = type; 1479e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony ScaleKernelInfo(kernel, 1.0/3.0, NoValue); 1480e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1481e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony } 1482c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony if ( fabs(args->sigma) > MagickEpsilon ) 1483c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony /* Rotate by correctly supplied 'angle' */ 1484c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony RotateKernelInfo(kernel, args->sigma); 1485c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony else if ( args->rho > 30.0 || args->rho < -30.0 ) 1486c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony /* Rotate by out of bounds 'type' */ 1487c3cd15b3dec84044ad4a50368681517cfb5e1b3fanthony RotateKernelInfo(kernel, args->rho); 1488e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony break; 1489e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony } 1490e2a60ce55aeee814017d81dae8a58621ffc2acdbanthony 1491529482f4b494010a13338a74446c510712f670b3anthony /* 1492529482f4b494010a13338a74446c510712f670b3anthony Boolean or Shaped Kernels 1493529482f4b494010a13338a74446c510712f670b3anthony */ 1494c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case DiamondKernel: 1495602ab9b30b644a78a4057da93d838a77391ec0acanthony { 1496c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (args->rho < 1.0) 1497c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->width = kernel->height = 3; /* default radius = 1 */ 1498c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1499bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = ((size_t)args->rho)*2+1; 1500bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 1501c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 15025e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 1503c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->height*sizeof(double)); 1504c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel->values == (double *) NULL) 1505c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(DestroyKernelInfo(kernel)); 1506c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony 1507c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony /* set all kernel values within diamond area to scale given */ 1508bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 1509bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 15101d5e67090dc7232b35bfcc71b31266c20838defcanthony if ( (labs((long) u)+labs((long) v)) <= (long) kernel->x) 1511c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->positive_range += kernel->values[i] = args->sigma; 1512c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony else 1513c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->values[i] = nan; 1514c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 1515c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 1516c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 1517c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case SquareKernel: 1518c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony case RectangleKernel: 1519c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { double 1520c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony scale; 1521602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( type == SquareKernel ) 1522602ab9b30b644a78a4057da93d838a77391ec0acanthony { 1523602ab9b30b644a78a4057da93d838a77391ec0acanthony if (args->rho < 1.0) 1524c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 1525602ab9b30b644a78a4057da93d838a77391ec0acanthony else 1526bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = (size_t) (2*args->rho+1); 1527bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 15284fd27e21043be809d66c8202e779255e5b660d2danthony scale = args->sigma; 1529602ab9b30b644a78a4057da93d838a77391ec0acanthony } 1530602ab9b30b644a78a4057da93d838a77391ec0acanthony else { 15312be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy /* NOTE: user defaults set in "AcquireKernelInfo()" */ 1532602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->rho < 1.0 || args->sigma < 1.0 ) 153383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); /* invalid args given */ 1534bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = (size_t)args->rho; 1535bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t)args->sigma; 1536602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( args->xi < 0.0 || args->xi > (double)kernel->width || 1537602ab9b30b644a78a4057da93d838a77391ec0acanthony args->psi < 0.0 || args->psi > (double)kernel->height ) 153883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); /* invalid args given */ 1539bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) args->xi; 1540bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = (ssize_t) args->psi; 15414fd27e21043be809d66c8202e779255e5b660d2danthony scale = 1.0; 1542602ab9b30b644a78a4057da93d838a77391ec0acanthony } 15435e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 1544602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height*sizeof(double)); 1545602ab9b30b644a78a4057da93d838a77391ec0acanthony if (kernel->values == (double *) NULL) 154683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 1547602ab9b30b644a78a4057da93d838a77391ec0acanthony 15483dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* set all kernel values to scale given */ 1549eaedf06777741da32408da72c1e512975c600c48cristy u=(ssize_t) (kernel->width*kernel->height); 1550150989ed67ef9da53141a65e5f3ebdb05dd025abcristy for ( i=0; i < u; i++) 15514fd27e21043be809d66c8202e779255e5b660d2danthony kernel->values[i] = scale; 15524fd27e21043be809d66c8202e779255e5b660d2danthony kernel->minimum = kernel->maximum = scale; /* a flat shape */ 15534fd27e21043be809d66c8202e779255e5b660d2danthony kernel->positive_range = scale*u; 1554cc6c836da2a53b6023b716e4973090a6714dc3b0anthony break; 1555602ab9b30b644a78a4057da93d838a77391ec0acanthony } 15561ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonKernel: 15571ef941fea2534a0d20ba7d71307d35040247decbanthony { 15581ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 1559a9892d898acb81e1ec73106d892855fdc5a69427anthony kernel->width = kernel->height = 5; /* default radius = 2 */ 15601ef941fea2534a0d20ba7d71307d35040247decbanthony else 15611ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 15621ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 15631ef941fea2534a0d20ba7d71307d35040247decbanthony 15645e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 15651ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height*sizeof(double)); 15661ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel->values == (double *) NULL) 15671ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 15681ef941fea2534a0d20ba7d71307d35040247decbanthony 15691ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 15701ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 15711ef941fea2534a0d20ba7d71307d35040247decbanthony if ( (labs((long) u)+labs((long) v)) <= 15721ef941fea2534a0d20ba7d71307d35040247decbanthony ((long)kernel->x + (long)(kernel->x/2)) ) 15731ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = args->sigma; 15741ef941fea2534a0d20ba7d71307d35040247decbanthony else 15751ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = nan; 1576a9892d898acb81e1ec73106d892855fdc5a69427anthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 15771ef941fea2534a0d20ba7d71307d35040247decbanthony break; 15781ef941fea2534a0d20ba7d71307d35040247decbanthony } 15791ef941fea2534a0d20ba7d71307d35040247decbanthony case DiskKernel: 15801ef941fea2534a0d20ba7d71307d35040247decbanthony { 15811ef941fea2534a0d20ba7d71307d35040247decbanthony ssize_t 15820bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony limit = (ssize_t)(args->rho*args->rho); 15831ef941fea2534a0d20ba7d71307d35040247decbanthony 15849bf68d590429a72aa70894f6aea7fc3c94876e54anthony if (args->rho < 0.4) /* default radius approx 4.3 */ 15859bf68d590429a72aa70894f6aea7fc3c94876e54anthony kernel->width = kernel->height = 9L, limit = 18L; 15861ef941fea2534a0d20ba7d71307d35040247decbanthony else 15871ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = (size_t)fabs(args->rho)*2+1; 15881ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 15891ef941fea2534a0d20ba7d71307d35040247decbanthony 15905e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 15911ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height*sizeof(double)); 15921ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel->values == (double *) NULL) 15931ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 15941ef941fea2534a0d20ba7d71307d35040247decbanthony 15951ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 15961ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 15971ef941fea2534a0d20ba7d71307d35040247decbanthony if ((u*u+v*v) <= limit) 15981ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = args->sigma; 15993dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony else 16003dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony kernel->values[i] = nan; 16011ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16021ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16031ef941fea2534a0d20ba7d71307d35040247decbanthony } 16041ef941fea2534a0d20ba7d71307d35040247decbanthony case PlusKernel: 16051ef941fea2534a0d20ba7d71307d35040247decbanthony { 16061ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 16071ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default radius 2 */ 16081ef941fea2534a0d20ba7d71307d35040247decbanthony else 16091ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 16101ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16111ef941fea2534a0d20ba7d71307d35040247decbanthony 16125e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 16131ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height*sizeof(double)); 16141ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel->values == (double *) NULL) 16151ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16161ef941fea2534a0d20ba7d71307d35040247decbanthony 16171ef941fea2534a0d20ba7d71307d35040247decbanthony /* set all kernel values along axises to given scale */ 16181ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16191ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16201ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan; 16211ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16221ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0); 16231ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16241ef941fea2534a0d20ba7d71307d35040247decbanthony } 16251ef941fea2534a0d20ba7d71307d35040247decbanthony case CrossKernel: 16261ef941fea2534a0d20ba7d71307d35040247decbanthony { 16271ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 16281ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default radius 2 */ 16291ef941fea2534a0d20ba7d71307d35040247decbanthony else 16301ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 16311ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16321ef941fea2534a0d20ba7d71307d35040247decbanthony 16335e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 16341ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height*sizeof(double)); 16351ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel->values == (double *) NULL) 16361ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16371ef941fea2534a0d20ba7d71307d35040247decbanthony 16381ef941fea2534a0d20ba7d71307d35040247decbanthony /* set all kernel values along axises to given scale */ 16391ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 16401ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16411ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = (u == v || u == -v) ? args->sigma : nan; 16421ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = args->sigma; /* a flat shape */ 16431ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0); 16441ef941fea2534a0d20ba7d71307d35040247decbanthony break; 16451ef941fea2534a0d20ba7d71307d35040247decbanthony } 1646529482f4b494010a13338a74446c510712f670b3anthony /* 1647529482f4b494010a13338a74446c510712f670b3anthony HitAndMiss Kernels 1648529482f4b494010a13338a74446c510712f670b3anthony */ 16491ef941fea2534a0d20ba7d71307d35040247decbanthony case RingKernel: 16501ef941fea2534a0d20ba7d71307d35040247decbanthony case PeaksKernel: 16511ef941fea2534a0d20ba7d71307d35040247decbanthony { 16521ef941fea2534a0d20ba7d71307d35040247decbanthony ssize_t 16531ef941fea2534a0d20ba7d71307d35040247decbanthony limit1, 16541ef941fea2534a0d20ba7d71307d35040247decbanthony limit2, 16551ef941fea2534a0d20ba7d71307d35040247decbanthony scale; 16561ef941fea2534a0d20ba7d71307d35040247decbanthony 16571ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < args->sigma) 16581ef941fea2534a0d20ba7d71307d35040247decbanthony { 16591ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = ((size_t)args->sigma)*2+1; 16601ef941fea2534a0d20ba7d71307d35040247decbanthony limit1 = (ssize_t)(args->rho*args->rho); 16611ef941fea2534a0d20ba7d71307d35040247decbanthony limit2 = (ssize_t)(args->sigma*args->sigma); 16623dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony } 16631ef941fea2534a0d20ba7d71307d35040247decbanthony else 16641ef941fea2534a0d20ba7d71307d35040247decbanthony { 16651ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = ((size_t)args->rho)*2+1; 16661ef941fea2534a0d20ba7d71307d35040247decbanthony limit1 = (ssize_t)(args->sigma*args->sigma); 16671ef941fea2534a0d20ba7d71307d35040247decbanthony limit2 = (ssize_t)(args->rho*args->rho); 16681ef941fea2534a0d20ba7d71307d35040247decbanthony } 16691ef941fea2534a0d20ba7d71307d35040247decbanthony if ( limit2 <= 0 ) 16701ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = 7L, limit1 = 7L, limit2 = 11L; 16711ef941fea2534a0d20ba7d71307d35040247decbanthony 16721ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height = kernel->width; 16731ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 16745e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 16751ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height*sizeof(double)); 16761ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel->values == (double *) NULL) 16771ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 16781ef941fea2534a0d20ba7d71307d35040247decbanthony 16791ef941fea2534a0d20ba7d71307d35040247decbanthony /* set a ring of points of 'scale' ( 0.0 for PeaksKernel ) */ 16801ef941fea2534a0d20ba7d71307d35040247decbanthony scale = (ssize_t) (( type == PeaksKernel) ? 0.0 : args->xi); 16811ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v= -kernel->y; v <= (ssize_t)kernel->y; v++) 16821ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 16831ef941fea2534a0d20ba7d71307d35040247decbanthony { ssize_t radius=u*u+v*v; 16841ef941fea2534a0d20ba7d71307d35040247decbanthony if (limit1 < radius && radius <= limit2) 16851ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = (double) scale; 16861ef941fea2534a0d20ba7d71307d35040247decbanthony else 16871ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[i] = nan; 16881ef941fea2534a0d20ba7d71307d35040247decbanthony } 16891ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->minimum = kernel->maximum = (double) scale; 16901ef941fea2534a0d20ba7d71307d35040247decbanthony if ( type == PeaksKernel ) { 16911ef941fea2534a0d20ba7d71307d35040247decbanthony /* set the central point in the middle */ 16921ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->values[kernel->x+kernel->y*kernel->width] = 1.0; 16931ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range = 1.0; 16941ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = 1.0; 16951ef941fea2534a0d20ba7d71307d35040247decbanthony } 16961ef941fea2534a0d20ba7d71307d35040247decbanthony break; 1697c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 16981ef941fea2534a0d20ba7d71307d35040247decbanthony case EdgesKernel: 16991ef941fea2534a0d20ba7d71307d35040247decbanthony { 1700529482f4b494010a13338a74446c510712f670b3anthony kernel=AcquireKernelInfo("ThinSE:482"); 17011ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17021ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17031ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 1704529482f4b494010a13338a74446c510712f670b3anthony ExpandMirrorKernelInfo(kernel); /* mirror expansion of kernels */ 17051ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17061ef941fea2534a0d20ba7d71307d35040247decbanthony } 17071ef941fea2534a0d20ba7d71307d35040247decbanthony case CornersKernel: 17081ef941fea2534a0d20ba7d71307d35040247decbanthony { 1709529482f4b494010a13338a74446c510712f670b3anthony kernel=AcquireKernelInfo("ThinSE:87"); 17101ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17111ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17121ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 17131ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* Expand 90 degree rotations */ 17141ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17151ef941fea2534a0d20ba7d71307d35040247decbanthony } 1716529482f4b494010a13338a74446c510712f670b3anthony case DiagonalsKernel: 17171ef941fea2534a0d20ba7d71307d35040247decbanthony { 17181ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 17191ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 17201ef941fea2534a0d20ba7d71307d35040247decbanthony default: 17211ef941fea2534a0d20ba7d71307d35040247decbanthony { KernelInfo 17221ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 1723529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,0 0,-,1 1,1,-"); 17241ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 17251ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 17261ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 1727529482f4b494010a13338a74446c510712f670b3anthony new_kernel=ParseKernelArray("3: 0,0,1 0,-,1 0,1,-"); 17281ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 17291ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 17301ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 17311ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 17321ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandMirrorKernelInfo(kernel); 1733529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 17341ef941fea2534a0d20ba7d71307d35040247decbanthony } 17351ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 1736529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,0 0,-,1 1,1,-"); 17371ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17381ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 1739529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,0,1 0,-,1 0,1,-"); 17401ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17411ef941fea2534a0d20ba7d71307d35040247decbanthony } 1742529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1743529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1744529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1745529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 17461ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17471ef941fea2534a0d20ba7d71307d35040247decbanthony } 17481ef941fea2534a0d20ba7d71307d35040247decbanthony case LineEndsKernel: 17491ef941fea2534a0d20ba7d71307d35040247decbanthony { /* Kernels for finding the end of thin lines */ 17501ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 17511ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 17521ef941fea2534a0d20ba7d71307d35040247decbanthony default: 17531ef941fea2534a0d20ba7d71307d35040247decbanthony /* set of kernels to find all end of lines */ 1754529482f4b494010a13338a74446c510712f670b3anthony return(AcquireKernelInfo("LineEnds:1>;LineEnds:2>")); 17551ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 17561ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel for 4-connected line ends - no rotation */ 17571ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,- 0,1,1 0,0,-"); 17581ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17591ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 17601ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel to add for 8-connected lines - no rotation */ 17611ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,0 0,0,1"); 17621ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17631ef941fea2534a0d20ba7d71307d35040247decbanthony case 3: 17641ef941fea2534a0d20ba7d71307d35040247decbanthony /* kernel to add for orthogonal line ends - does not find corners */ 17651ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,1 0,0,0"); 17661ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17671ef941fea2534a0d20ba7d71307d35040247decbanthony case 4: 17681ef941fea2534a0d20ba7d71307d35040247decbanthony /* traditional line end - fails on last T end */ 17691ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 0,0,0 0,1,- 0,0,-"); 17701ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17711ef941fea2534a0d20ba7d71307d35040247decbanthony } 1772529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1773529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1774529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1775529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 17761ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17771ef941fea2534a0d20ba7d71307d35040247decbanthony } 17781ef941fea2534a0d20ba7d71307d35040247decbanthony case LineJunctionsKernel: 17791ef941fea2534a0d20ba7d71307d35040247decbanthony { /* kernels for finding the junctions of multiple lines */ 17801ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 17811ef941fea2534a0d20ba7d71307d35040247decbanthony case 0: 17821ef941fea2534a0d20ba7d71307d35040247decbanthony default: 17831ef941fea2534a0d20ba7d71307d35040247decbanthony /* set of kernels to find all line junctions */ 1784529482f4b494010a13338a74446c510712f670b3anthony return(AcquireKernelInfo("LineJunctions:1@;LineJunctions:2>")); 17851ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 17861ef941fea2534a0d20ba7d71307d35040247decbanthony /* Y Junction */ 17871ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,1 -,1,- -,1,-"); 17881ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17891ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 17901ef941fea2534a0d20ba7d71307d35040247decbanthony /* Diagonal T Junctions */ 17911ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,- -,1,- 1,-,1"); 17921ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17931ef941fea2534a0d20ba7d71307d35040247decbanthony case 3: 17941ef941fea2534a0d20ba7d71307d35040247decbanthony /* Orthogonal T Junctions */ 17951ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: -,-,- 1,1,1 -,1,-"); 17961ef941fea2534a0d20ba7d71307d35040247decbanthony break; 17971ef941fea2534a0d20ba7d71307d35040247decbanthony case 4: 17981ef941fea2534a0d20ba7d71307d35040247decbanthony /* Diagonal X Junctions */ 17991ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,-,1 -,1,- 1,-,1"); 18001ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18011ef941fea2534a0d20ba7d71307d35040247decbanthony case 5: 18021ef941fea2534a0d20ba7d71307d35040247decbanthony /* Orthogonal X Junctions - minimal diamond kernel */ 18031ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: -,1,- 1,1,1 -,1,-"); 18041ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18051ef941fea2534a0d20ba7d71307d35040247decbanthony } 1806529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 1807529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 1808529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 1809529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 18101ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18111ef941fea2534a0d20ba7d71307d35040247decbanthony } 18121ef941fea2534a0d20ba7d71307d35040247decbanthony case RidgesKernel: 18131ef941fea2534a0d20ba7d71307d35040247decbanthony { /* Ridges - Ridge finding kernels */ 18141ef941fea2534a0d20ba7d71307d35040247decbanthony KernelInfo 18151ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 18161ef941fea2534a0d20ba7d71307d35040247decbanthony switch ( (int) args->rho ) { 18171ef941fea2534a0d20ba7d71307d35040247decbanthony case 1: 18181ef941fea2534a0d20ba7d71307d35040247decbanthony default: 18191ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3x1:0,1,0"); 18201ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 18211ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 18221ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 18231ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* 2 rotated kernels (symmetrical) */ 18241ef941fea2534a0d20ba7d71307d35040247decbanthony break; 18251ef941fea2534a0d20ba7d71307d35040247decbanthony case 2: 18261ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("4x1:0,1,1,0"); 18271ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 18281ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 18291ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 18301ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotated kernels */ 18311ef941fea2534a0d20ba7d71307d35040247decbanthony 18321ef941fea2534a0d20ba7d71307d35040247decbanthony /* Kernels to find a stepped 'thick' line, 4 rotates + mirrors */ 18331ef941fea2534a0d20ba7d71307d35040247decbanthony /* Unfortunatally we can not yet rotate a non-square kernel */ 18341ef941fea2534a0d20ba7d71307d35040247decbanthony /* But then we can't flip a non-symetrical kernel either */ 18351ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+1+1:0,1,1,- -,1,1,- -,1,1,0"); 18361ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18371ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18381ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18391ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18401ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+2+1:0,1,1,- -,1,1,- -,1,1,0"); 18411ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18421ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18431ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18441ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18451ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+1+1:-,1,1,0 -,1,1,- 0,1,1,-"); 18461ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18471ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18481ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18491ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18501ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("4x3+2+1:-,1,1,0 -,1,1,- 0,1,1,-"); 18511ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18521ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18531ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18541ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18551ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+1:0,-,- 1,1,1 1,1,1 -,-,0"); 18561ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18571ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18581ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18591ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18601ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+2:0,-,- 1,1,1 1,1,1 -,-,0"); 18611ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18621ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18631ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18641ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18651ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+1:-,-,0 1,1,1 1,1,1 0,-,-"); 18661ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18671ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18681ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18691ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18701ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3x4+1+2:-,-,0 1,1,1 1,1,1 0,-,-"); 187168cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony if (new_kernel == (KernelInfo *) NULL) 187268cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony return(DestroyKernelInfo(kernel)); 187368cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony new_kernel->type = type; 187468cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony LastKernelInfo(kernel)->next = new_kernel; 187568cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony break; 18761ef941fea2534a0d20ba7d71307d35040247decbanthony } 18771ef941fea2534a0d20ba7d71307d35040247decbanthony break; 187868cf70d51e88101b28a7fa0f28ad5d040a1ace12anthony } 18791ef941fea2534a0d20ba7d71307d35040247decbanthony case ConvexHullKernel: 18801ef941fea2534a0d20ba7d71307d35040247decbanthony { 18811ef941fea2534a0d20ba7d71307d35040247decbanthony KernelInfo 18821ef941fea2534a0d20ba7d71307d35040247decbanthony *new_kernel; 18831ef941fea2534a0d20ba7d71307d35040247decbanthony /* first set of 8 kernels */ 18841ef941fea2534a0d20ba7d71307d35040247decbanthony kernel=ParseKernelArray("3: 1,1,- 1,0,- 1,-,0"); 18851ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel == (KernelInfo *) NULL) 18861ef941fea2534a0d20ba7d71307d35040247decbanthony return(kernel); 18871ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->type = type; 18881ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(kernel, 90.0); 18891ef941fea2534a0d20ba7d71307d35040247decbanthony /* append the mirror versions too - no flip function yet */ 18901ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel=ParseKernelArray("3: 1,1,1 1,0,- -,-,0"); 18911ef941fea2534a0d20ba7d71307d35040247decbanthony if (new_kernel == (KernelInfo *) NULL) 18921ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 18931ef941fea2534a0d20ba7d71307d35040247decbanthony new_kernel->type = type; 18941ef941fea2534a0d20ba7d71307d35040247decbanthony ExpandRotateKernelInfo(new_kernel, 90.0); 18951ef941fea2534a0d20ba7d71307d35040247decbanthony LastKernelInfo(kernel)->next = new_kernel; 18961ef941fea2534a0d20ba7d71307d35040247decbanthony break; 1897694934fa79dd310f727588b1d0a7481fa6170f1danthony } 18989a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case SkeletonKernel: 18999a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony { 19009a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony switch ( (int) args->rho ) { 19019a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 1: 19029a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony default: 19039a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* Traditional Skeleton... 19049a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** A cyclically rotated single kernel 19059a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19069a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo("ThinSE:482"); 19079a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19089a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19099a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19109a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandRotateKernelInfo(kernel, 45.0); /* 8 rotations */ 19119a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19129a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 2: 19139a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* HIPR Variation of the cyclic skeleton 19149a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** Corners of the traditional method made more forgiving, 19159a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** but the retain the same cyclic order. 19169a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19179a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo("ThinSE:482; ThinSE:87x90;"); 19189a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19199a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19209a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel->next == (KernelInfo *) NULL) 19219a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(DestroyKernelInfo(kernel)); 19229a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19239a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->type = type; 19249a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotations of the 2 kernels */ 19259a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19269a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 3: 19279a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony /* Dan Bloomberg Skeleton, from his paper on 3x3 thinning SE's 19289a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** "Connectivity-Preserving Morphological Image Thransformations" 19299a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** by Dan S. Bloomberg, available on Leptonica, Selected Papers, 19309a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ** http://www.leptonica.com/papers/conn.pdf 19319a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony */ 19329a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=AcquireKernelInfo( 19339a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony "ThinSE:41; ThinSE:42; ThinSE:43"); 19349a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony if (kernel == (KernelInfo *) NULL) 19359a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony return(kernel); 19369a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->type = type; 19379a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->type = type; 19389a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel->next->next->type = type; 19399a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony ExpandMirrorKernelInfo(kernel); /* 12 kernels total */ 19409a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19419a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony } 19429a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 19439a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony } 1944529482f4b494010a13338a74446c510712f670b3anthony case ThinSEKernel: 1945529482f4b494010a13338a74446c510712f670b3anthony { /* Special kernels for general thinning, while preserving connections 1946529482f4b494010a13338a74446c510712f670b3anthony ** "Connectivity-Preserving Morphological Image Thransformations" 1947529482f4b494010a13338a74446c510712f670b3anthony ** by Dan S. Bloomberg, available on Leptonica, Selected Papers, 1948529482f4b494010a13338a74446c510712f670b3anthony ** http://www.leptonica.com/papers/conn.pdf 1949529482f4b494010a13338a74446c510712f670b3anthony ** And 1950529482f4b494010a13338a74446c510712f670b3anthony ** http://tpgit.github.com/Leptonica/ccthin_8c_source.html 1951529482f4b494010a13338a74446c510712f670b3anthony ** 1952529482f4b494010a13338a74446c510712f670b3anthony ** Note kernels do not specify the origin pixel, allowing them 1953529482f4b494010a13338a74446c510712f670b3anthony ** to be used for both thickening and thinning operations. 1954529482f4b494010a13338a74446c510712f670b3anthony */ 1955529482f4b494010a13338a74446c510712f670b3anthony switch ( (int) args->rho ) { 1956529482f4b494010a13338a74446c510712f670b3anthony /* SE for 4-connected thinning */ 1957529482f4b494010a13338a74446c510712f670b3anthony case 41: /* SE_4_1 */ 1958529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 -,-,1"); 1959529482f4b494010a13338a74446c510712f670b3anthony break; 1960529482f4b494010a13338a74446c510712f670b3anthony case 42: /* SE_4_2 */ 1961529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 -,0,-"); 1962529482f4b494010a13338a74446c510712f670b3anthony break; 1963529482f4b494010a13338a74446c510712f670b3anthony case 43: /* SE_4_3 */ 1964529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,-,1"); 1965529482f4b494010a13338a74446c510712f670b3anthony break; 1966529482f4b494010a13338a74446c510712f670b3anthony case 44: /* SE_4_4 */ 1967529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,0,-"); 1968529482f4b494010a13338a74446c510712f670b3anthony break; 1969529482f4b494010a13338a74446c510712f670b3anthony case 45: /* SE_4_5 */ 1970529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,1 0,-,1 -,0,-"); 1971529482f4b494010a13338a74446c510712f670b3anthony break; 1972529482f4b494010a13338a74446c510712f670b3anthony case 46: /* SE_4_6 */ 1973529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,0,- 0,-,1 -,0,1"); 1974529482f4b494010a13338a74446c510712f670b3anthony break; 1975529482f4b494010a13338a74446c510712f670b3anthony case 47: /* SE_4_7 */ 1976529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,1 0,-,1 -,0,-"); 1977529482f4b494010a13338a74446c510712f670b3anthony break; 1978529482f4b494010a13338a74446c510712f670b3anthony case 48: /* SE_4_8 */ 1979529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,-,1 0,-,1 0,-,1"); 1980529482f4b494010a13338a74446c510712f670b3anthony break; 1981529482f4b494010a13338a74446c510712f670b3anthony case 49: /* SE_4_9 */ 1982529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 -,-,1"); 1983529482f4b494010a13338a74446c510712f670b3anthony break; 1984529482f4b494010a13338a74446c510712f670b3anthony /* SE for 8-connected thinning - negatives of the above */ 1985529482f4b494010a13338a74446c510712f670b3anthony case 81: /* SE_8_0 */ 1986529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 -,1,-"); 1987529482f4b494010a13338a74446c510712f670b3anthony break; 1988529482f4b494010a13338a74446c510712f670b3anthony case 82: /* SE_8_2 */ 1989529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,-,-"); 1990529482f4b494010a13338a74446c510712f670b3anthony break; 1991529482f4b494010a13338a74446c510712f670b3anthony case 83: /* SE_8_3 */ 1992529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 -,1,-"); 1993529482f4b494010a13338a74446c510712f670b3anthony break; 1994529482f4b494010a13338a74446c510712f670b3anthony case 84: /* SE_8_4 */ 1995529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 0,-,-"); 1996529482f4b494010a13338a74446c510712f670b3anthony break; 1997529482f4b494010a13338a74446c510712f670b3anthony case 85: /* SE_8_5 */ 1998529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 0,-,-"); 1999529482f4b494010a13338a74446c510712f670b3anthony break; 2000529482f4b494010a13338a74446c510712f670b3anthony case 86: /* SE_8_6 */ 2001529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,- 0,-,1 0,-,1"); 2002529482f4b494010a13338a74446c510712f670b3anthony break; 2003529482f4b494010a13338a74446c510712f670b3anthony case 87: /* SE_8_7 */ 2004529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,0,-"); 2005529482f4b494010a13338a74446c510712f670b3anthony break; 2006529482f4b494010a13338a74446c510712f670b3anthony case 88: /* SE_8_8 */ 2007529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,- 0,-,1 0,1,-"); 2008529482f4b494010a13338a74446c510712f670b3anthony break; 2009529482f4b494010a13338a74446c510712f670b3anthony case 89: /* SE_8_9 */ 2010529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,1,- 0,-,1 -,1,-"); 2011529482f4b494010a13338a74446c510712f670b3anthony break; 2012529482f4b494010a13338a74446c510712f670b3anthony /* Special combined SE kernels */ 20139a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 423: /* SE_4_2 , SE_4_3 Combined Kernel */ 20149a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=ParseKernelArray("3: -,-,1 0,-,- -,0,-"); 20159a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 20169a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony case 823: /* SE_8_2 , SE_8_3 Combined Kernel */ 20179a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony kernel=ParseKernelArray("3: -,1,- -,-,1 0,-,-"); 20189a89ca47eecfc04e9e6b04767527c692bc09bfe2anthony break; 2019529482f4b494010a13338a74446c510712f670b3anthony case 481: /* SE_48_1 - General Connected Corner Kernel */ 2020529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: -,1,1 0,-,1 0,0,-"); 2021529482f4b494010a13338a74446c510712f670b3anthony break; 2022529482f4b494010a13338a74446c510712f670b3anthony default: 2023529482f4b494010a13338a74446c510712f670b3anthony case 482: /* SE_48_2 - General Edge Kernel */ 2024529482f4b494010a13338a74446c510712f670b3anthony kernel=ParseKernelArray("3: 0,-,1 0,-,1 0,-,1"); 2025529482f4b494010a13338a74446c510712f670b3anthony break; 2026529482f4b494010a13338a74446c510712f670b3anthony } 2027529482f4b494010a13338a74446c510712f670b3anthony if (kernel == (KernelInfo *) NULL) 2028529482f4b494010a13338a74446c510712f670b3anthony return(kernel); 2029529482f4b494010a13338a74446c510712f670b3anthony kernel->type = type; 2030529482f4b494010a13338a74446c510712f670b3anthony RotateKernelInfo(kernel, args->sigma); 2031529482f4b494010a13338a74446c510712f670b3anthony break; 2032529482f4b494010a13338a74446c510712f670b3anthony } 2033529482f4b494010a13338a74446c510712f670b3anthony /* 2034529482f4b494010a13338a74446c510712f670b3anthony Distance Measuring Kernels 2035529482f4b494010a13338a74446c510712f670b3anthony */ 20361ef941fea2534a0d20ba7d71307d35040247decbanthony case ChebyshevKernel: 20371ef941fea2534a0d20ba7d71307d35040247decbanthony { 20381ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 20391ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 20401ef941fea2534a0d20ba7d71307d35040247decbanthony else 20411ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 20421ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 20431ef941fea2534a0d20ba7d71307d35040247decbanthony 20445e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 20451ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height*sizeof(double)); 20461ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel->values == (double *) NULL) 20471ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 20481ef941fea2534a0d20ba7d71307d35040247decbanthony 20491ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 20501ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 20511ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += ( kernel->values[i] = 20521ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*MagickMax(fabs((double)u),fabs((double)v)) ); 20531ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = kernel->values[0]; 20541ef941fea2534a0d20ba7d71307d35040247decbanthony break; 2055c40ac1e79923a1516075ba1197ae4ed90244af9banthony } 20561ef941fea2534a0d20ba7d71307d35040247decbanthony case ManhattanKernel: 20571ef941fea2534a0d20ba7d71307d35040247decbanthony { 20581ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 1.0) 20591ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 20601ef941fea2534a0d20ba7d71307d35040247decbanthony else 20611ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 20621ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 20631ef941fea2534a0d20ba7d71307d35040247decbanthony 20645e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 20651ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->height*sizeof(double)); 20661ef941fea2534a0d20ba7d71307d35040247decbanthony if (kernel->values == (double *) NULL) 20671ef941fea2534a0d20ba7d71307d35040247decbanthony return(DestroyKernelInfo(kernel)); 20681ef941fea2534a0d20ba7d71307d35040247decbanthony 20691ef941fea2534a0d20ba7d71307d35040247decbanthony for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 20701ef941fea2534a0d20ba7d71307d35040247decbanthony for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 20711ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += ( kernel->values[i] = 20721ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*(labs((long) u)+labs((long) v)) ); 20731ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->maximum = kernel->values[0]; 20741ef941fea2534a0d20ba7d71307d35040247decbanthony break; 2075c40ac1e79923a1516075ba1197ae4ed90244af9banthony } 20761ef941fea2534a0d20ba7d71307d35040247decbanthony case OctagonalKernel: 2077602ab9b30b644a78a4057da93d838a77391ec0acanthony { 20781ef941fea2534a0d20ba7d71307d35040247decbanthony if (args->rho < 2.0) 20791ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = 5; /* default/minimum radius = 2 */ 2080602ab9b30b644a78a4057da93d838a77391ec0acanthony else 2081bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->width = kernel->height = ((size_t)args->rho)*2+1; 2082bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 2083602ab9b30b644a78a4057da93d838a77391ec0acanthony 20845e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 2085602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height*sizeof(double)); 2086602ab9b30b644a78a4057da93d838a77391ec0acanthony if (kernel->values == (double *) NULL) 208783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 2088602ab9b30b644a78a4057da93d838a77391ec0acanthony 2089bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 2090bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 20911ef941fea2534a0d20ba7d71307d35040247decbanthony { 20921ef941fea2534a0d20ba7d71307d35040247decbanthony double 20931ef941fea2534a0d20ba7d71307d35040247decbanthony r1 = MagickMax(fabs((double)u),fabs((double)v)), 20941ef941fea2534a0d20ba7d71307d35040247decbanthony r2 = floor((double)(labs((long)u)+labs((long)v)+1)/1.5); 20951ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->positive_range += kernel->values[i] = 20961ef941fea2534a0d20ba7d71307d35040247decbanthony args->sigma*MagickMax(r1,r2); 20971ef941fea2534a0d20ba7d71307d35040247decbanthony } 2098c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 2099602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2100602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2101602ab9b30b644a78a4057da93d838a77391ec0acanthony case EuclideanKernel: 2102602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2103602ab9b30b644a78a4057da93d838a77391ec0acanthony if (args->rho < 1.0) 2104c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony kernel->width = kernel->height = 3; /* default radius = 1 */ 2105602ab9b30b644a78a4057da93d838a77391ec0acanthony else 21061ef941fea2534a0d20ba7d71307d35040247decbanthony kernel->width = kernel->height = ((size_t)args->rho)*2+1; 2107bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2; 2108602ab9b30b644a78a4057da93d838a77391ec0acanthony 21095e0444305cde9e2ef31f16111899f14a257a6a54cristy kernel->values=(double *) AcquireAlignedMemory(kernel->width, 2110602ab9b30b644a78a4057da93d838a77391ec0acanthony kernel->height*sizeof(double)); 2111602ab9b30b644a78a4057da93d838a77391ec0acanthony if (kernel->values == (double *) NULL) 211283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return(DestroyKernelInfo(kernel)); 2113602ab9b30b644a78a4057da93d838a77391ec0acanthony 2114bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++) 2115bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++) 2116c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->positive_range += ( kernel->values[i] = 2117c84dce50867229e4872193e8eed5dbab58eb9f02anthony args->sigma*sqrt((double)(u*u+v*v)) ); 2118c99304fe3c8d9c617da792b40b57c118bb1249afcristy kernel->maximum = kernel->values[0]; 2119602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2120602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2121602ab9b30b644a78a4057da93d838a77391ec0acanthony default: 2122c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony { 2123529482f4b494010a13338a74446c510712f670b3anthony /* No-Op Kernel - Basically just a single pixel on its own */ 21243ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony kernel=ParseKernelArray("1:1"); 2125c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony if (kernel == (KernelInfo *) NULL) 2126c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony return(kernel); 2127529482f4b494010a13338a74446c510712f670b3anthony kernel->type = UndefinedKernel; 2128c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony break; 2129c106172cd6da00b6c8fd6a4c06efdd4aa32c7f06anthony } 2130602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2131602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2132602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 2133602ab9b30b644a78a4057da93d838a77391ec0acanthony} 2134c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony 2135602ab9b30b644a78a4057da93d838a77391ec0acanthony/* 2136602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2137602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2138602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2139602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 21406771f1e8987fa49f52d4176281a2e8524b8e31cbcristy% C l o n e K e r n e l I n f o % 21414fd27e21043be809d66c8202e779255e5b660d2danthony% % 21424fd27e21043be809d66c8202e779255e5b660d2danthony% % 21434fd27e21043be809d66c8202e779255e5b660d2danthony% % 21444fd27e21043be809d66c8202e779255e5b660d2danthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21454fd27e21043be809d66c8202e779255e5b660d2danthony% 21461b2bc0a7da432e6e1cc0480280402df213faa940anthony% CloneKernelInfo() creates a new clone of the given Kernel List so that its 21471b2bc0a7da432e6e1cc0480280402df213faa940anthony% can be modified without effecting the original. The cloned kernel should 214819910ef25dd3d99d1981a9e42c934133170ee714anthony% be destroyed using DestoryKernelInfo() when no longer needed. 21497a01dcf50ce12cb2a789bedff51e9345f022432eanthony% 2150e636559dfadfdb115cc93f223315052a1ee89238cristy% The format of the CloneKernelInfo method is: 21514fd27e21043be809d66c8202e779255e5b660d2danthony% 2152930be614b4595b97cd79ee864a394796740f76adanthony% KernelInfo *CloneKernelInfo(const KernelInfo *kernel) 21534fd27e21043be809d66c8202e779255e5b660d2danthony% 21544fd27e21043be809d66c8202e779255e5b660d2danthony% A description of each parameter follows: 21554fd27e21043be809d66c8202e779255e5b660d2danthony% 21564fd27e21043be809d66c8202e779255e5b660d2danthony% o kernel: the Morphology/Convolution kernel to be cloned 21574fd27e21043be809d66c8202e779255e5b660d2danthony% 21584fd27e21043be809d66c8202e779255e5b660d2danthony*/ 2159ef656913b0b30d713ae94c82c47693c9dc69c9f4cristyMagickExport KernelInfo *CloneKernelInfo(const KernelInfo *kernel) 21604fd27e21043be809d66c8202e779255e5b660d2danthony{ 2161bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 21624fd27e21043be809d66c8202e779255e5b660d2danthony i; 21634fd27e21043be809d66c8202e779255e5b660d2danthony 216419eb64195ef744f61293025952df1e5e6de66524cristy KernelInfo 21657a01dcf50ce12cb2a789bedff51e9345f022432eanthony *new_kernel; 21664fd27e21043be809d66c8202e779255e5b660d2danthony 21674fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel != (KernelInfo *) NULL); 21687a01dcf50ce12cb2a789bedff51e9345f022432eanthony new_kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel)); 21697a01dcf50ce12cb2a789bedff51e9345f022432eanthony if (new_kernel == (KernelInfo *) NULL) 21707a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(new_kernel); 21717a01dcf50ce12cb2a789bedff51e9345f022432eanthony *new_kernel=(*kernel); /* copy values in structure */ 21727a01dcf50ce12cb2a789bedff51e9345f022432eanthony 21737a01dcf50ce12cb2a789bedff51e9345f022432eanthony /* replace the values with a copy of the values */ 21745e0444305cde9e2ef31f16111899f14a257a6a54cristy new_kernel->values=(double *) AcquireAlignedMemory(kernel->width, 217519eb64195ef744f61293025952df1e5e6de66524cristy kernel->height*sizeof(double)); 21767a01dcf50ce12cb2a789bedff51e9345f022432eanthony if (new_kernel->values == (double *) NULL) 21777a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(DestroyKernelInfo(new_kernel)); 2178bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++) 21797a01dcf50ce12cb2a789bedff51e9345f022432eanthony new_kernel->values[i]=kernel->values[i]; 21801b2bc0a7da432e6e1cc0480280402df213faa940anthony 21811b2bc0a7da432e6e1cc0480280402df213faa940anthony /* Also clone the next kernel in the kernel list */ 21821b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL ) { 21831b2bc0a7da432e6e1cc0480280402df213faa940anthony new_kernel->next = CloneKernelInfo(kernel->next); 21841b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( new_kernel->next == (KernelInfo *) NULL ) 21851b2bc0a7da432e6e1cc0480280402df213faa940anthony return(DestroyKernelInfo(new_kernel)); 21861b2bc0a7da432e6e1cc0480280402df213faa940anthony } 21871b2bc0a7da432e6e1cc0480280402df213faa940anthony 21887a01dcf50ce12cb2a789bedff51e9345f022432eanthony return(new_kernel); 21894fd27e21043be809d66c8202e779255e5b660d2danthony} 21904fd27e21043be809d66c8202e779255e5b660d2danthony 21914fd27e21043be809d66c8202e779255e5b660d2danthony/* 21924fd27e21043be809d66c8202e779255e5b660d2danthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21934fd27e21043be809d66c8202e779255e5b660d2danthony% % 21944fd27e21043be809d66c8202e779255e5b660d2danthony% % 21954fd27e21043be809d66c8202e779255e5b660d2danthony% % 219683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% D e s t r o y K e r n e l I n f o % 2197602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2198602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2199602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2200602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2201602ab9b30b644a78a4057da93d838a77391ec0acanthony% 220283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% DestroyKernelInfo() frees the memory used by a Convolution/Morphology 220383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% kernel. 2204602ab9b30b644a78a4057da93d838a77391ec0acanthony% 220583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% The format of the DestroyKernelInfo method is: 2206602ab9b30b644a78a4057da93d838a77391ec0acanthony% 220783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% KernelInfo *DestroyKernelInfo(KernelInfo *kernel) 2208602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2209602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 2210602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2211602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel: the Morphology/Convolution kernel to be destroyed 2212602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2213602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 221483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthonyMagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel) 2215602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 22162be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy assert(kernel != (KernelInfo *) NULL); 22174fd27e21043be809d66c8202e779255e5b660d2danthony 22187a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( kernel->next != (KernelInfo *) NULL ) 22197a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel->next = DestroyKernelInfo(kernel->next); 22207a01dcf50ce12cb2a789bedff51e9345f022432eanthony 22217a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel->values = (double *)RelinquishMagickMemory(kernel->values); 22227a01dcf50ce12cb2a789bedff51e9345f022432eanthony kernel = (KernelInfo *) RelinquishMagickMemory(kernel); 2223602ab9b30b644a78a4057da93d838a77391ec0acanthony return(kernel); 2224602ab9b30b644a78a4057da93d838a77391ec0acanthony} 2225c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony 2226c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony/* 2227c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2228c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2229c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2230c94cdb0501c4bec4f5828f1a585c38f4c374900aanthony% % 2231ce0fd95b65b90e1dc307600bb14b346b777e8137anthony+ E x p a n d M i r r o r K e r n e l I n f o % 22323c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 22333c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 22343c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 22353c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22363c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2237bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% ExpandMirrorKernelInfo() takes a single kernel, and expands it into a 2238bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% sequence of 90-degree rotated kernels but providing a reflected 180 2239bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% rotatation, before the -/+ 90-degree rotations. 2240bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2241bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% This special rotation order produces a better, more symetrical thinning of 2242bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% objects. 2243bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2244bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The format of the ExpandMirrorKernelInfo method is: 2245bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2246bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% void ExpandMirrorKernelInfo(KernelInfo *kernel) 2247bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2248bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% A description of each parameter follows: 2249bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2250bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% o kernel: the Morphology/Convolution kernel 2251bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2252bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% This function is only internel to this module, as it is not finalized, 2253bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% especially with regard to non-orthogonal angles, and rotation of larger 2254bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2D kernels. 2255bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony*/ 2256bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2257bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony#if 0 2258bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void FlopKernelInfo(KernelInfo *kernel) 2259bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony { /* Do a Flop by reversing each row. */ 2260bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony size_t 2261bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony y; 2262bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony register ssize_t 2263bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony x,r; 2264bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony register double 2265bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *k,t; 2266bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2267bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width) 2268bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--) 2269bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony t=k[x], k[x]=k[r], k[r]=t; 2270bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2271bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony kernel->x = kernel->width - kernel->x - 1; 2272bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony angle = fmod(angle+180.0, 360.0); 2273bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony } 2274bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony#endif 2275bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2276bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void ExpandMirrorKernelInfo(KernelInfo *kernel) 2277bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony{ 2278bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony KernelInfo 2279bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *clone, 2280bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony *last; 2281bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2282bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = kernel; 2283bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2284bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2285bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 180); /* flip */ 2286bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2287bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = clone; 2288bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2289bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2290bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 90); /* transpose */ 2291bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2292bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony last = clone; 2293bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2294bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = CloneKernelInfo(last); 2295bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony RotateKernelInfo(clone, 180); /* flop */ 2296bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 2297bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2298bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony return; 2299bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony} 2300bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony 2301bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony/* 2302bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2303bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2304bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2305bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2306ce0fd95b65b90e1dc307600bb14b346b777e8137anthony+ E x p a n d R o t a t e K e r n e l I n f o % 2307bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2308bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2309bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% % 2310bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2311bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% 2312bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% ExpandRotateKernelInfo() takes a kernel list, and expands it by rotating 2313529482f4b494010a13338a74446c510712f670b3anthony% incrementally by the angle given, until the kernel repeats. 23143c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23153c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% WARNING: 45 degree rotations only works for 3x3 kernels. 23163c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% While 90 degree roatations only works for linear and square kernels 23173c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2318bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% The format of the ExpandRotateKernelInfo method is: 23193c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2320bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony% void ExpandRotateKernelInfo(KernelInfo *kernel, double angle) 23213c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23223c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% A description of each parameter follows: 23233c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23243c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% o kernel: the Morphology/Convolution kernel 23253c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23263c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% o angle: angle to rotate in degrees 23273c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 23283c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% This function is only internel to this module, as it is not finalized, 23293c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% especially with regard to non-orthogonal angles, and rotation of larger 23303c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% 2D kernels. 23313c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony*/ 233247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 233347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony/* Internal Routine - Return true if two kernels are the same */ 233447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthonystatic MagickBooleanType SameKernelInfo(const KernelInfo *kernel1, 233547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony const KernelInfo *kernel2) 233647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony{ 2337bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 233847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony i; 23391d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 23401d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* check size and origin location */ 23411d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( kernel1->width != kernel2->width 23421d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->height != kernel2->height 23431d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->x != kernel2->x 23441d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony || kernel1->y != kernel2->y ) 234547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 23461d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 23471d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* check actual kernel values */ 234847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony for (i=0; i < (kernel1->width*kernel1->height); i++) { 2349f0a92fd8deb68d411304359906b12679b675691fglennrp /* Test for Nan equivalence */ 235047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( IsNan(kernel1->values[i]) && !IsNan(kernel2->values[i]) ) 235147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 235247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( IsNan(kernel2->values[i]) && !IsNan(kernel1->values[i]) ) 235347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 2354f0a92fd8deb68d411304359906b12679b675691fglennrp /* Test actual values are equivalent */ 235547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( fabs(kernel1->values[i] - kernel2->values[i]) > MagickEpsilon ) 235647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickFalse; 235747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 23581d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony 235947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return MagickTrue; 236047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony} 236147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 2362bfb635a40fc92bfcbdf36c018a9e64a9182d809canthonystatic void ExpandRotateKernelInfo(KernelInfo *kernel, const double angle) 23633c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony{ 23643c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony KernelInfo 236584d9b5596c0900609dea18795861e2b0936b21c6cristy *clone, 23663c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony *last; 2367a9a61ad96c5112acd968f97b689bd42ca392d70bcristy 23683c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony last = kernel; 236947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while(1) { 237084d9b5596c0900609dea18795861e2b0936b21c6cristy clone = CloneKernelInfo(last); 237184d9b5596c0900609dea18795861e2b0936b21c6cristy RotateKernelInfo(clone, angle); 237284d9b5596c0900609dea18795861e2b0936b21c6cristy if ( SameKernelInfo(kernel, clone) == MagickTrue ) 237347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 2374bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony LastKernelInfo(last)->next = clone; 237584d9b5596c0900609dea18795861e2b0936b21c6cristy last = clone; 23763c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 2377bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony clone = DestroyKernelInfo(clone); /* kernel has repeated - junk the clone */ 237847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return; 23793c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony} 23803c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony 23813c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony/* 23823c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23833c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 23843c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 23853c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony% % 238646a369d839971ab627bdb31a93d8bd63e81b65a3anthony+ C a l c M e t a K e r n a l I n f o % 238746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 238846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 238946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 239046a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 239146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 239246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% CalcKernelMetaData() recalculate the KernelInfo meta-data of this kernel only, 2393dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp% using the kernel values. This should only ne used if it is not possible to 239446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% calculate that meta-data in some easier way. 239546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 239646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% It is important that the meta-data is correct before ScaleKernelInfo() is 239746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% used to perform kernel normalization. 239846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 239946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The format of the CalcKernelMetaData method is: 240046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 240146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% void CalcKernelMetaData(KernelInfo *kernel, const double scale ) 240246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 240346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% A description of each parameter follows: 240446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 240546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o kernel: the Morphology/Convolution kernel to modify 240646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 240746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% WARNING: Minimum and Maximum values are assumed to include zero, even if 240846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% zero is not part of the kernel (as in Gaussian Derived kernels). This 240946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% however is not true for flat-shaped morphological kernels. 241046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 241146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% WARNING: Only the specific kernel pointed to is modified, not a list of 241246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% multiple kernels. 241346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 241446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This is an internal function and not expected to be useful outside this 241546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% module. This could change however. 241646a369d839971ab627bdb31a93d8bd63e81b65a3anthony*/ 241746a369d839971ab627bdb31a93d8bd63e81b65a3anthonystatic void CalcKernelMetaData(KernelInfo *kernel) 241846a369d839971ab627bdb31a93d8bd63e81b65a3anthony{ 2419bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 242046a369d839971ab627bdb31a93d8bd63e81b65a3anthony i; 242146a369d839971ab627bdb31a93d8bd63e81b65a3anthony 242246a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->minimum = kernel->maximum = 0.0; 242346a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->negative_range = kernel->positive_range = 0.0; 242446a369d839971ab627bdb31a93d8bd63e81b65a3anthony for (i=0; i < (kernel->width*kernel->height); i++) 242546a369d839971ab627bdb31a93d8bd63e81b65a3anthony { 242646a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( fabs(kernel->values[i]) < MagickEpsilon ) 242746a369d839971ab627bdb31a93d8bd63e81b65a3anthony kernel->values[i] = 0.0; 242846a369d839971ab627bdb31a93d8bd63e81b65a3anthony ( kernel->values[i] < 0) 242946a369d839971ab627bdb31a93d8bd63e81b65a3anthony ? ( kernel->negative_range += kernel->values[i] ) 243046a369d839971ab627bdb31a93d8bd63e81b65a3anthony : ( kernel->positive_range += kernel->values[i] ); 243146a369d839971ab627bdb31a93d8bd63e81b65a3anthony Minimize(kernel->minimum, kernel->values[i]); 243246a369d839971ab627bdb31a93d8bd63e81b65a3anthony Maximize(kernel->maximum, kernel->values[i]); 243346a369d839971ab627bdb31a93d8bd63e81b65a3anthony } 243446a369d839971ab627bdb31a93d8bd63e81b65a3anthony 243546a369d839971ab627bdb31a93d8bd63e81b65a3anthony return; 243646a369d839971ab627bdb31a93d8bd63e81b65a3anthony} 243746a369d839971ab627bdb31a93d8bd63e81b65a3anthony 243846a369d839971ab627bdb31a93d8bd63e81b65a3anthony/* 243946a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 244046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 244146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 244246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 24439eb4f74649b23c053b308ce1152dce51239450baanthony% M o r p h o l o g y A p p l y % 2444602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2445602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2446602ab9b30b644a78a4057da93d838a77391ec0acanthony% % 2447602ab9b30b644a78a4057da93d838a77391ec0acanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2448602ab9b30b644a78a4057da93d838a77391ec0acanthony% 24499eb4f74649b23c053b308ce1152dce51239450baanthony% MorphologyApply() applies a morphological method, multiple times using 24509eb4f74649b23c053b308ce1152dce51239450baanthony% a list of multiple kernels. 2451602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2452f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% It is basically equivalent to as MorphologyImage() (see below) but 2453e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% without any user controls. This allows internel programs to use this 2454dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp% function, to actually perform a specific task without possible interference 2455e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% by any API user supplied settings. 2456e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% 2457f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% It is MorphologyImage() task to extract any such user controls, and 2458e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% pass them to this function for processing. 24599eb4f74649b23c053b308ce1152dce51239450baanthony% 24609eb4f74649b23c053b308ce1152dce51239450baanthony% More specifically kernels are not normalized/scaled/blended by the 2461e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% 'convolve:scale' Image Artifact (setting), nor is the convolve bias 2462e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% (-bias setting or image->bias) loooked at, but must be supplied from the 2463e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony% function arguments. 2464602ab9b30b644a78a4057da93d838a77391ec0acanthony% 246547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% The format of the MorphologyApply method is: 2466602ab9b30b644a78a4057da93d838a77391ec0acanthony% 24679eb4f74649b23c053b308ce1152dce51239450baanthony% Image *MorphologyApply(const Image *image,MorphologyMethod method, 2468f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% const ssize_t iterations,const KernelInfo *kernel, 2469f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% const CompositeMethod compose,const double bias, 2470f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% ExceptionInfo *exception) 2471602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2472602ab9b30b644a78a4057da93d838a77391ec0acanthony% A description of each parameter follows: 2473602ab9b30b644a78a4057da93d838a77391ec0acanthony% 24748d18850dee4bed193a64866a6d2353eeeb73e145anthony% o image: the source image 2475602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2476602ab9b30b644a78a4057da93d838a77391ec0acanthony% o method: the morphology method to be applied. 2477602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2478602ab9b30b644a78a4057da93d838a77391ec0acanthony% o iterations: apply the operation this many times (or no change). 2479602ab9b30b644a78a4057da93d838a77391ec0acanthony% A value of -1 means loop until no change found. 2480602ab9b30b644a78a4057da93d838a77391ec0acanthony% How this is applied may depend on the morphology method. 2481602ab9b30b644a78a4057da93d838a77391ec0acanthony% Typically this is a value of 1. 2482602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2483602ab9b30b644a78a4057da93d838a77391ec0acanthony% o channel: the channel type. 2484602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2485602ab9b30b644a78a4057da93d838a77391ec0acanthony% o kernel: An array of double representing the morphology kernel. 2486602ab9b30b644a78a4057da93d838a77391ec0acanthony% 248747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% o compose: How to handle or merge multi-kernel results. 24888d18850dee4bed193a64866a6d2353eeeb73e145anthony% If 'UndefinedCompositeOp' use default for the Morphology method. 24898d18850dee4bed193a64866a6d2353eeeb73e145anthony% If 'NoCompositeOp' force image to be re-iterated by each kernel. 24908d18850dee4bed193a64866a6d2353eeeb73e145anthony% Otherwise merge the results using the compose method given. 249147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% 249247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony% o bias: Convolution Output Bias. 2493602ab9b30b644a78a4057da93d838a77391ec0acanthony% 24949eb4f74649b23c053b308ce1152dce51239450baanthony% o exception: return any errors or warnings in this structure. 2495602ab9b30b644a78a4057da93d838a77391ec0acanthony% 2496602ab9b30b644a78a4057da93d838a77391ec0acanthony*/ 2497602ab9b30b644a78a4057da93d838a77391ec0acanthony 24989eb4f74649b23c053b308ce1152dce51239450baanthony/* Apply a Morphology Primative to an image using the given kernel. 2499a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** Two pre-created images must be provided, and no image is created. 2500ea61f01656bb0f9074677452017cc559e54093faanthony** It returns the number of pixels that changed between the images 2501a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** for result convergence determination. 25029eb4f74649b23c053b308ce1152dce51239450baanthony*/ 2503f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristystatic ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image, 2504f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method,const KernelInfo *kernel,const double bias, 2505f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 2506602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 25072be1538b17a2b0ca9a0bd532b8ff2c2813114e24cristy#define MorphologyTag "Morphology/Image" 2508602ab9b30b644a78a4057da93d838a77391ec0acanthony 25095f959473f334e196c6bf39b740c12cb4963fceebcristy CacheView 25104c08aed51c5899665ade97263692328eea4af106cristy *image_view, 25114c08aed51c5899665ade97263692328eea4af106cristy *morphology_view; 25125f959473f334e196c6bf39b740c12cb4963fceebcristy 2513bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t 2514a8843c1f815ffad2568ec592d5b446cb1476aab5anthony y, offx, offy; 2515a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 2516a8843c1f815ffad2568ec592d5b446cb1476aab5anthony size_t 2517db60568e12574785101a4ae8d8da076227a0a889anthony virt_width, 2518602ab9b30b644a78a4057da93d838a77391ec0acanthony changed; 2519602ab9b30b644a78a4057da93d838a77391ec0acanthony 2520602ab9b30b644a78a4057da93d838a77391ec0acanthony MagickBooleanType 2521602ab9b30b644a78a4057da93d838a77391ec0acanthony status; 2522602ab9b30b644a78a4057da93d838a77391ec0acanthony 25235f959473f334e196c6bf39b740c12cb4963fceebcristy MagickOffsetType 25245f959473f334e196c6bf39b740c12cb4963fceebcristy progress; 2525602ab9b30b644a78a4057da93d838a77391ec0acanthony 2526e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(image != (Image *) NULL); 2527e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(image->signature == MagickSignature); 25284c08aed51c5899665ade97263692328eea4af106cristy assert(morphology_image != (Image *) NULL); 25294c08aed51c5899665ade97263692328eea4af106cristy assert(morphology_image->signature == MagickSignature); 2530e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(kernel != (KernelInfo *) NULL); 2531e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(kernel->signature == MagickSignature); 2532e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(exception != (ExceptionInfo *) NULL); 2533e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert(exception->signature == MagickSignature); 2534e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony 2535602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickTrue; 2536602ab9b30b644a78a4057da93d838a77391ec0acanthony changed=0; 2537602ab9b30b644a78a4057da93d838a77391ec0acanthony progress=0; 2538602ab9b30b644a78a4057da93d838a77391ec0acanthony 25394c08aed51c5899665ade97263692328eea4af106cristy image_view=AcquireCacheView(image); 25404c08aed51c5899665ade97263692328eea4af106cristy morphology_view=AcquireCacheView(morphology_image); 25416eac8d74fdd2c99429aba3b8404008909a44261fanthony virt_width=image->columns+kernel->width-1; 254229188a8682a98d4b7882cca434b170517555fc7danthony 2543cc6c836da2a53b6023b716e4973090a6714dc3b0anthony /* Some methods (including convolve) needs use a reflected kernel. 25449eb4f74649b23c053b308ce1152dce51239450baanthony * Adjust 'origin' offsets to loop though kernel as a reflection. 254529188a8682a98d4b7882cca434b170517555fc7danthony */ 2546c99304fe3c8d9c617da792b40b57c118bb1249afcristy offx = kernel->x; 2547c99304fe3c8d9c617da792b40b57c118bb1249afcristy offy = kernel->y; 254829188a8682a98d4b7882cca434b170517555fc7danthony switch(method) { 2549930be614b4595b97cd79ee864a394796740f76adanthony case ConvolveMorphology: 2550930be614b4595b97cd79ee864a394796740f76adanthony case DilateMorphology: 2551930be614b4595b97cd79ee864a394796740f76adanthony case DilateIntensityMorphology: 2552a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /*case DistanceMorphology:*/ 25535ef8e94ff55717be2387d537bd49025780a1a558anthony /* kernel needs to used with reflection about origin */ 2554bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy offx = (ssize_t) kernel->width-offx-1; 2555bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy offy = (ssize_t) kernel->height-offy-1; 255629188a8682a98d4b7882cca434b170517555fc7danthony break; 25575ef8e94ff55717be2387d537bd49025780a1a558anthony case ErodeMorphology: 25585ef8e94ff55717be2387d537bd49025780a1a558anthony case ErodeIntensityMorphology: 25595ef8e94ff55717be2387d537bd49025780a1a558anthony case HitAndMissMorphology: 25605ef8e94ff55717be2387d537bd49025780a1a558anthony case ThinningMorphology: 25615ef8e94ff55717be2387d537bd49025780a1a558anthony case ThickenMorphology: 25623ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony /* kernel is used as is, without reflection */ 25635ef8e94ff55717be2387d537bd49025780a1a558anthony break; 2564930be614b4595b97cd79ee864a394796740f76adanthony default: 25659eb4f74649b23c053b308ce1152dce51239450baanthony assert("Not a Primitive Morphology Method" != (char *) NULL); 2566930be614b4595b97cd79ee864a394796740f76adanthony break; 256729188a8682a98d4b7882cca434b170517555fc7danthony } 256829188a8682a98d4b7882cca434b170517555fc7danthony 25698d18850dee4bed193a64866a6d2353eeeb73e145anthony if ( method == ConvolveMorphology && kernel->width == 1 ) 25708d18850dee4bed193a64866a6d2353eeeb73e145anthony { /* Special handling (for speed) of vertical (blur) kernels. 25718d18850dee4bed193a64866a6d2353eeeb73e145anthony ** This performs its handling in columns rather than in rows. 2572ea61f01656bb0f9074677452017cc559e54093faanthony ** This is only done for convolve as it is the only method that 25738d18850dee4bed193a64866a6d2353eeeb73e145anthony ** generates very large 1-D vertical kernels (such as a 'BlurKernel') 25748d18850dee4bed193a64866a6d2353eeeb73e145anthony ** 25758d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Timing tests (on single CPU laptop) 25768d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Using a vertical 1-d Blue with normal row-by-row (below) 25778d18850dee4bed193a64866a6d2353eeeb73e145anthony ** time convert logo: -morphology Convolve Blur:0x10+90 null: 25788d18850dee4bed193a64866a6d2353eeeb73e145anthony ** 0.807u 25798d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Using this column method 25808d18850dee4bed193a64866a6d2353eeeb73e145anthony ** time convert logo: -morphology Convolve Blur:0x10+90 null: 25818d18850dee4bed193a64866a6d2353eeeb73e145anthony ** 0.620u 25828d18850dee4bed193a64866a6d2353eeeb73e145anthony ** 25838d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Anthony Thyssen, 14 June 2010 25848d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 2585fd1175952254cf1ac848ddb441e483c5e33d517fcristy register ssize_t 2586fd1175952254cf1ac848ddb441e483c5e33d517fcristy x; 2587fd1175952254cf1ac848ddb441e483c5e33d517fcristy 25888d18850dee4bed193a64866a6d2353eeeb73e145anthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 25898d18850dee4bed193a64866a6d2353eeeb73e145anthony#pragma omp parallel for schedule(dynamic,4) shared(progress,status) 25908d18850dee4bed193a64866a6d2353eeeb73e145anthony#endif 25918d18850dee4bed193a64866a6d2353eeeb73e145anthony for (x=0; x < (ssize_t) image->columns; x++) 25928d18850dee4bed193a64866a6d2353eeeb73e145anthony { 25934c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 25948d18850dee4bed193a64866a6d2353eeeb73e145anthony *restrict p; 25958d18850dee4bed193a64866a6d2353eeeb73e145anthony 25964c08aed51c5899665ade97263692328eea4af106cristy register Quantum 25978d18850dee4bed193a64866a6d2353eeeb73e145anthony *restrict q; 25988d18850dee4bed193a64866a6d2353eeeb73e145anthony 25998d18850dee4bed193a64866a6d2353eeeb73e145anthony register ssize_t 26008d18850dee4bed193a64866a6d2353eeeb73e145anthony y; 26018d18850dee4bed193a64866a6d2353eeeb73e145anthony 260255a91cddcdea3aa002893186a773e1704884a9dfcristy ssize_t 26038d18850dee4bed193a64866a6d2353eeeb73e145anthony r; 26048d18850dee4bed193a64866a6d2353eeeb73e145anthony 26058d18850dee4bed193a64866a6d2353eeeb73e145anthony if (status == MagickFalse) 26068d18850dee4bed193a64866a6d2353eeeb73e145anthony continue; 2607c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy p=GetCacheViewVirtualPixels(image_view,x,-offy,1,image->rows+ 2608c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy kernel->height-1,exception); 2609c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy q=GetCacheViewAuthenticPixels(morphology_view,x,0,1, 2610c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy morphology_image->rows,exception); 26114c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 26128d18850dee4bed193a64866a6d2353eeeb73e145anthony { 26138d18850dee4bed193a64866a6d2353eeeb73e145anthony status=MagickFalse; 26148d18850dee4bed193a64866a6d2353eeeb73e145anthony continue; 26158d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2616a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* offset to origin in 'p'. while 'q' points to it directly */ 2617a8843c1f815ffad2568ec592d5b446cb1476aab5anthony r = offy; 26188d18850dee4bed193a64866a6d2353eeeb73e145anthony 26198d18850dee4bed193a64866a6d2353eeeb73e145anthony for (y=0; y < (ssize_t) image->rows; y++) 26208d18850dee4bed193a64866a6d2353eeeb73e145anthony { 262170b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy PixelInfo 262270b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy result; 262370b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy 26248d18850dee4bed193a64866a6d2353eeeb73e145anthony register ssize_t 26258d18850dee4bed193a64866a6d2353eeeb73e145anthony v; 26268d18850dee4bed193a64866a6d2353eeeb73e145anthony 26278d18850dee4bed193a64866a6d2353eeeb73e145anthony register const double 26288d18850dee4bed193a64866a6d2353eeeb73e145anthony *restrict k; 26298d18850dee4bed193a64866a6d2353eeeb73e145anthony 26304c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 26318d18850dee4bed193a64866a6d2353eeeb73e145anthony *restrict k_pixels; 26328d18850dee4bed193a64866a6d2353eeeb73e145anthony 26338d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Copy input image to the output image for unused channels 26348d18850dee4bed193a64866a6d2353eeeb73e145anthony * This removes need for 'cloning' a new image every iteration 26358d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 26364c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image,GetPixelRed(image,p+r* 2637ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 26384c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image,GetPixelGreen(image,p+r* 2639ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 26404c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image,GetPixelBlue(image,p+r* 2641ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 26428d18850dee4bed193a64866a6d2353eeeb73e145anthony if (image->colorspace == CMYKColorspace) 26434c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image,GetPixelBlack(image,p+r* 2644ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 26458d18850dee4bed193a64866a6d2353eeeb73e145anthony 26468d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Set the bias of the weighted average output */ 26478d18850dee4bed193a64866a6d2353eeeb73e145anthony result.red = 26488d18850dee4bed193a64866a6d2353eeeb73e145anthony result.green = 26498d18850dee4bed193a64866a6d2353eeeb73e145anthony result.blue = 26504c08aed51c5899665ade97263692328eea4af106cristy result.alpha = 26514c08aed51c5899665ade97263692328eea4af106cristy result.black = bias; 26528d18850dee4bed193a64866a6d2353eeeb73e145anthony 26538d18850dee4bed193a64866a6d2353eeeb73e145anthony 26548d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Weighted Average of pixels using reflected kernel 26558d18850dee4bed193a64866a6d2353eeeb73e145anthony ** 26568d18850dee4bed193a64866a6d2353eeeb73e145anthony ** NOTE for correct working of this operation for asymetrical 26578d18850dee4bed193a64866a6d2353eeeb73e145anthony ** kernels, the kernel needs to be applied in its reflected form. 26588d18850dee4bed193a64866a6d2353eeeb73e145anthony ** That is its values needs to be reversed. 26598d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 26608d18850dee4bed193a64866a6d2353eeeb73e145anthony k = &kernel->values[ kernel->height-1 ]; 26618d18850dee4bed193a64866a6d2353eeeb73e145anthony k_pixels = p; 2662c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy if ( (image->sync == MagickFalse) || (image->matte == MagickFalse) ) 26638d18850dee4bed193a64866a6d2353eeeb73e145anthony { /* No 'Sync' involved. 26648d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Convolution is simple greyscale channel operation 26658d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 26668d18850dee4bed193a64866a6d2353eeeb73e145anthony for (v=0; v < (ssize_t) kernel->height; v++) { 26678d18850dee4bed193a64866a6d2353eeeb73e145anthony if ( IsNan(*k) ) continue; 26684c08aed51c5899665ade97263692328eea4af106cristy result.red += (*k)*GetPixelRed(image,k_pixels); 26694c08aed51c5899665ade97263692328eea4af106cristy result.green += (*k)*GetPixelGreen(image,k_pixels); 26704c08aed51c5899665ade97263692328eea4af106cristy result.blue += (*k)*GetPixelBlue(image,k_pixels); 26714c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 26724c08aed51c5899665ade97263692328eea4af106cristy result.black+=(*k)*GetPixelBlack(image,k_pixels); 26734c08aed51c5899665ade97263692328eea4af106cristy result.alpha += (*k)*GetPixelAlpha(image,k_pixels); 26748d18850dee4bed193a64866a6d2353eeeb73e145anthony k--; 2675ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+=GetPixelChannels(image); 26768d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2677ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 26784c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image,ClampToQuantum(result.red),q); 2679ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 26804c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image,ClampToQuantum(result.green),q); 2681ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 26824c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image,ClampToQuantum(result.blue),q); 2683ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 26844c08aed51c5899665ade97263692328eea4af106cristy (image->colorspace == CMYKColorspace)) 26854c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image,ClampToQuantum(result.black),q); 2686ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 26874c08aed51c5899665ade97263692328eea4af106cristy (image->matte == MagickTrue)) 26884c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q); 26898d18850dee4bed193a64866a6d2353eeeb73e145anthony } 26908d18850dee4bed193a64866a6d2353eeeb73e145anthony else 26918d18850dee4bed193a64866a6d2353eeeb73e145anthony { /* Channel 'Sync' Flag, and Alpha Channel enabled. 26928d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Weight the color channels with Alpha Channel so that 26938d18850dee4bed193a64866a6d2353eeeb73e145anthony ** transparent pixels are not part of the results. 26948d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 26958d18850dee4bed193a64866a6d2353eeeb73e145anthony MagickRealType 26968d18850dee4bed193a64866a6d2353eeeb73e145anthony alpha, /* alpha weighting of colors : kernel*alpha */ 26978d18850dee4bed193a64866a6d2353eeeb73e145anthony gamma; /* divisor, sum of color weighting values */ 26988d18850dee4bed193a64866a6d2353eeeb73e145anthony 26998d18850dee4bed193a64866a6d2353eeeb73e145anthony gamma=0.0; 27008d18850dee4bed193a64866a6d2353eeeb73e145anthony for (v=0; v < (ssize_t) kernel->height; v++) { 27018d18850dee4bed193a64866a6d2353eeeb73e145anthony if ( IsNan(*k) ) continue; 27024c08aed51c5899665ade97263692328eea4af106cristy alpha=(*k)*(QuantumScale*GetPixelAlpha(image,k_pixels)); 27038d18850dee4bed193a64866a6d2353eeeb73e145anthony gamma += alpha; 27044c08aed51c5899665ade97263692328eea4af106cristy result.red += alpha*GetPixelRed(image,k_pixels); 27054c08aed51c5899665ade97263692328eea4af106cristy result.green += alpha*GetPixelGreen(image,k_pixels); 27064c08aed51c5899665ade97263692328eea4af106cristy result.blue += alpha*GetPixelBlue(image,k_pixels); 27074c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 27084c08aed51c5899665ade97263692328eea4af106cristy result.black += alpha*GetPixelBlack(image,k_pixels); 27094c08aed51c5899665ade97263692328eea4af106cristy result.alpha += (*k)*GetPixelAlpha(image,k_pixels); 27108d18850dee4bed193a64866a6d2353eeeb73e145anthony k--; 2711ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+=GetPixelChannels(image); 27128d18850dee4bed193a64866a6d2353eeeb73e145anthony } 27138d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Sync'ed channels, all channels are modified */ 27148d18850dee4bed193a64866a6d2353eeeb73e145anthony gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); 27154c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image, 27164c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.red),q); 27174c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image, 27184c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.green),q); 27194c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image, 27204c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.blue),q); 27218d18850dee4bed193a64866a6d2353eeeb73e145anthony if (image->colorspace == CMYKColorspace) 27224c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image, 27234c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.black),q); 27244c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(morphology_image, 27254c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(result.alpha),q); 27268d18850dee4bed193a64866a6d2353eeeb73e145anthony } 27278d18850dee4bed193a64866a6d2353eeeb73e145anthony 27288d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Count up changed pixels */ 2729ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(morphology_image,q)) 2730ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(morphology_image,q)) 2731ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(morphology_image,q)) 2732ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(morphology_image,q)) 27334c08aed51c5899665ade97263692328eea4af106cristy || ((image->colorspace == CMYKColorspace) && 2734ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(morphology_image,q)))) 27358d18850dee4bed193a64866a6d2353eeeb73e145anthony changed++; /* The pixel was changed in some way! */ 2736ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p+=GetPixelChannels(image); 2737ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(morphology_image); 27388d18850dee4bed193a64866a6d2353eeeb73e145anthony } /* y */ 27394c08aed51c5899665ade97263692328eea4af106cristy if ( SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 27408d18850dee4bed193a64866a6d2353eeeb73e145anthony status=MagickFalse; 27418d18850dee4bed193a64866a6d2353eeeb73e145anthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 27428d18850dee4bed193a64866a6d2353eeeb73e145anthony { 27438d18850dee4bed193a64866a6d2353eeeb73e145anthony MagickBooleanType 27448d18850dee4bed193a64866a6d2353eeeb73e145anthony proceed; 27458d18850dee4bed193a64866a6d2353eeeb73e145anthony 27468d18850dee4bed193a64866a6d2353eeeb73e145anthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 27478d18850dee4bed193a64866a6d2353eeeb73e145anthony #pragma omp critical (MagickCore_MorphologyImage) 27488d18850dee4bed193a64866a6d2353eeeb73e145anthony#endif 27498d18850dee4bed193a64866a6d2353eeeb73e145anthony proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows); 27508d18850dee4bed193a64866a6d2353eeeb73e145anthony if (proceed == MagickFalse) 27518d18850dee4bed193a64866a6d2353eeeb73e145anthony status=MagickFalse; 27528d18850dee4bed193a64866a6d2353eeeb73e145anthony } 27538d18850dee4bed193a64866a6d2353eeeb73e145anthony } /* x */ 27544c08aed51c5899665ade97263692328eea4af106cristy morphology_image->type=image->type; 27554c08aed51c5899665ade97263692328eea4af106cristy morphology_view=DestroyCacheView(morphology_view); 27564c08aed51c5899665ade97263692328eea4af106cristy image_view=DestroyCacheView(image_view); 2757aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy return(status ? (ssize_t) changed : 0); 27588d18850dee4bed193a64866a6d2353eeeb73e145anthony } 27598d18850dee4bed193a64866a6d2353eeeb73e145anthony 27608d18850dee4bed193a64866a6d2353eeeb73e145anthony /* 27618d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Normal handling of horizontal or rectangular kernels (row by row) 27628d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 2763602ab9b30b644a78a4057da93d838a77391ec0acanthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 2764602ab9b30b644a78a4057da93d838a77391ec0acanthony #pragma omp parallel for schedule(dynamic,4) shared(progress,status) 2765602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 2766bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (y=0; y < (ssize_t) image->rows; y++) 2767602ab9b30b644a78a4057da93d838a77391ec0acanthony { 27684c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 2769602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict p; 2770602ab9b30b644a78a4057da93d838a77391ec0acanthony 27714c08aed51c5899665ade97263692328eea4af106cristy register Quantum 2772602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict q; 2773602ab9b30b644a78a4057da93d838a77391ec0acanthony 2774bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 2775602ab9b30b644a78a4057da93d838a77391ec0acanthony x; 2776602ab9b30b644a78a4057da93d838a77391ec0acanthony 2777bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 2778602ab9b30b644a78a4057da93d838a77391ec0acanthony r; 2779602ab9b30b644a78a4057da93d838a77391ec0acanthony 2780602ab9b30b644a78a4057da93d838a77391ec0acanthony if (status == MagickFalse) 2781602ab9b30b644a78a4057da93d838a77391ec0acanthony continue; 27824c08aed51c5899665ade97263692328eea4af106cristy p=GetCacheViewVirtualPixels(image_view, -offx, y-offy, virt_width, 2783c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy kernel->height, exception); 2784c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy q=GetCacheViewAuthenticPixels(morphology_view,0,y, 2785c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy morphology_image->columns,1,exception); 27864c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 2787602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2788602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 2789602ab9b30b644a78a4057da93d838a77391ec0acanthony continue; 2790602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2791a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* offset to origin in 'p'. while 'q' points to it directly */ 2792db60568e12574785101a4ae8d8da076227a0a889anthony r = virt_width*offy + offx; 279329188a8682a98d4b7882cca434b170517555fc7danthony 2794bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (x=0; x < (ssize_t) image->columns; x++) 2795602ab9b30b644a78a4057da93d838a77391ec0acanthony { 2796bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t 2797602ab9b30b644a78a4057da93d838a77391ec0acanthony v; 2798602ab9b30b644a78a4057da93d838a77391ec0acanthony 2799bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 2800602ab9b30b644a78a4057da93d838a77391ec0acanthony u; 2801602ab9b30b644a78a4057da93d838a77391ec0acanthony 2802602ab9b30b644a78a4057da93d838a77391ec0acanthony register const double 2803602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict k; 2804602ab9b30b644a78a4057da93d838a77391ec0acanthony 28054c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 2806602ab9b30b644a78a4057da93d838a77391ec0acanthony *restrict k_pixels; 2807602ab9b30b644a78a4057da93d838a77391ec0acanthony 28084c08aed51c5899665ade97263692328eea4af106cristy PixelInfo 28095ef8e94ff55717be2387d537bd49025780a1a558anthony result, 28105ef8e94ff55717be2387d537bd49025780a1a558anthony min, 28115ef8e94ff55717be2387d537bd49025780a1a558anthony max; 2812602ab9b30b644a78a4057da93d838a77391ec0acanthony 2813c406ea496196b962e4bc865ed8f6a4491241c6edanthony /* Copy input image to the output image for unused channels 281483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony * This removes need for 'cloning' a new image every iteration 281529188a8682a98d4b7882cca434b170517555fc7danthony */ 28164c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image,GetPixelRed(image,p+r* 2817ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 28184c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image,GetPixelGreen(image,p+r* 2819ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 28204c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image,GetPixelBlue(image,p+r* 2821ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 2822602ab9b30b644a78a4057da93d838a77391ec0acanthony if (image->colorspace == CMYKColorspace) 28234c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image,GetPixelBlack(image,p+r* 2824ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image)),q); 2825602ab9b30b644a78a4057da93d838a77391ec0acanthony 28265ef8e94ff55717be2387d537bd49025780a1a558anthony /* Defaults */ 28275ef8e94ff55717be2387d537bd49025780a1a558anthony min.red = 28285ef8e94ff55717be2387d537bd49025780a1a558anthony min.green = 28295ef8e94ff55717be2387d537bd49025780a1a558anthony min.blue = 28304c08aed51c5899665ade97263692328eea4af106cristy min.alpha = 28314c08aed51c5899665ade97263692328eea4af106cristy min.black = (MagickRealType) QuantumRange; 28325ef8e94ff55717be2387d537bd49025780a1a558anthony max.red = 28335ef8e94ff55717be2387d537bd49025780a1a558anthony max.green = 28345ef8e94ff55717be2387d537bd49025780a1a558anthony max.blue = 28354c08aed51c5899665ade97263692328eea4af106cristy max.alpha = 28364c08aed51c5899665ade97263692328eea4af106cristy max.black = (MagickRealType) 0; 28379eb4f74649b23c053b308ce1152dce51239450baanthony /* default result is the original pixel value */ 2838ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy result.red = (MagickRealType) GetPixelRed(image,p+r*GetPixelChannels(image)); 2839ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy result.green = (MagickRealType) GetPixelGreen(image,p+r*GetPixelChannels(image)); 2840ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy result.blue = (MagickRealType) GetPixelBlue(image,p+r*GetPixelChannels(image)); 28414c08aed51c5899665ade97263692328eea4af106cristy result.black = 0.0; 28424c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 2843ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy result.black = (MagickRealType) GetPixelBlack(image,p+r*GetPixelChannels(image)); 2844ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy result.alpha=(MagickRealType) GetPixelAlpha(image,p+r*GetPixelChannels(image)); 28455ef8e94ff55717be2387d537bd49025780a1a558anthony 2846602ab9b30b644a78a4057da93d838a77391ec0acanthony switch (method) { 2847602ab9b30b644a78a4057da93d838a77391ec0acanthony case ConvolveMorphology: 28488d18850dee4bed193a64866a6d2353eeeb73e145anthony /* Set the bias of the weighted average output */ 28499eb4f74649b23c053b308ce1152dce51239450baanthony result.red = 28509eb4f74649b23c053b308ce1152dce51239450baanthony result.green = 28519eb4f74649b23c053b308ce1152dce51239450baanthony result.blue = 28524c08aed51c5899665ade97263692328eea4af106cristy result.alpha = 28534c08aed51c5899665ade97263692328eea4af106cristy result.black = bias; 2854930be614b4595b97cd79ee864a394796740f76adanthony break; 28554fd27e21043be809d66c8202e779255e5b660d2danthony case DilateIntensityMorphology: 28564fd27e21043be809d66c8202e779255e5b660d2danthony case ErodeIntensityMorphology: 28579eb4f74649b23c053b308ce1152dce51239450baanthony /* use a boolean flag indicating when first match found */ 28589eb4f74649b23c053b308ce1152dce51239450baanthony result.red = 0.0; /* result is not used otherwise */ 28594fd27e21043be809d66c8202e779255e5b660d2danthony break; 2860602ab9b30b644a78a4057da93d838a77391ec0acanthony default: 2861602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2862602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2863602ab9b30b644a78a4057da93d838a77391ec0acanthony 2864602ab9b30b644a78a4057da93d838a77391ec0acanthony switch ( method ) { 2865602ab9b30b644a78a4057da93d838a77391ec0acanthony case ConvolveMorphology: 2866930be614b4595b97cd79ee864a394796740f76adanthony /* Weighted Average of pixels using reflected kernel 2867930be614b4595b97cd79ee864a394796740f76adanthony ** 2868930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE for correct working of this operation for asymetrical 2869930be614b4595b97cd79ee864a394796740f76adanthony ** kernels, the kernel needs to be applied in its reflected form. 2870930be614b4595b97cd79ee864a394796740f76adanthony ** That is its values needs to be reversed. 2871930be614b4595b97cd79ee864a394796740f76adanthony ** 2872930be614b4595b97cd79ee864a394796740f76adanthony ** Correlation is actually the same as this but without reflecting 2873930be614b4595b97cd79ee864a394796740f76adanthony ** the kernel, and thus 'lower-level' that Convolution. However 2874930be614b4595b97cd79ee864a394796740f76adanthony ** as Convolution is the more common method used, and it does not 2875930be614b4595b97cd79ee864a394796740f76adanthony ** really cost us much in terms of processing to use a reflected 28765ef8e94ff55717be2387d537bd49025780a1a558anthony ** kernel, so it is Convolution that is implemented. 2877930be614b4595b97cd79ee864a394796740f76adanthony ** 2878930be614b4595b97cd79ee864a394796740f76adanthony ** Correlation will have its kernel reflected before calling 2879930be614b4595b97cd79ee864a394796740f76adanthony ** this function to do a Convolve. 2880930be614b4595b97cd79ee864a394796740f76adanthony ** 2881930be614b4595b97cd79ee864a394796740f76adanthony ** For more details of Correlation vs Convolution see 2882930be614b4595b97cd79ee864a394796740f76adanthony ** http://www.cs.umd.edu/~djacobs/CMSC426/Convolution.pdf 2883930be614b4595b97cd79ee864a394796740f76adanthony */ 28848d18850dee4bed193a64866a6d2353eeeb73e145anthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 28858d18850dee4bed193a64866a6d2353eeeb73e145anthony k_pixels = p; 2886f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy if ( (image->sync == MagickFalse) || 2887f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy (image->matte == MagickFalse) ) 28888d18850dee4bed193a64866a6d2353eeeb73e145anthony { /* No 'Sync' involved. 28898d18850dee4bed193a64866a6d2353eeeb73e145anthony ** Convolution is simple greyscale channel operation 28908d18850dee4bed193a64866a6d2353eeeb73e145anthony */ 28918d18850dee4bed193a64866a6d2353eeeb73e145anthony for (v=0; v < (ssize_t) kernel->height; v++) { 28928d18850dee4bed193a64866a6d2353eeeb73e145anthony for (u=0; u < (ssize_t) kernel->width; u++, k--) { 28938d18850dee4bed193a64866a6d2353eeeb73e145anthony if ( IsNan(*k) ) continue; 28944c08aed51c5899665ade97263692328eea4af106cristy result.red += (*k)* 2895ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image)); 28964c08aed51c5899665ade97263692328eea4af106cristy result.green += (*k)* 2897ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)); 28984c08aed51c5899665ade97263692328eea4af106cristy result.blue += (*k)* 2899ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)); 29004c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 29014c08aed51c5899665ade97263692328eea4af106cristy result.black += (*k)* 2902ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)); 29034c08aed51c5899665ade97263692328eea4af106cristy result.alpha += (*k)* 2904ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)); 29058d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2906ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 29078d18850dee4bed193a64866a6d2353eeeb73e145anthony } 2908ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 29092b9582a27910c7baaeb04b7e969638328fa70095cristy SetPixelRed(morphology_image,ClampToQuantum(result.red), 29102b9582a27910c7baaeb04b7e969638328fa70095cristy q); 2911ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 29122b9582a27910c7baaeb04b7e969638328fa70095cristy SetPixelGreen(morphology_image,ClampToQuantum(result.green), 29132b9582a27910c7baaeb04b7e969638328fa70095cristy q); 2914ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 29152b9582a27910c7baaeb04b7e969638328fa70095cristy SetPixelBlue(morphology_image,ClampToQuantum(result.blue), 29162b9582a27910c7baaeb04b7e969638328fa70095cristy q); 2917ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 29184c08aed51c5899665ade97263692328eea4af106cristy (image->colorspace == CMYKColorspace)) 29192b9582a27910c7baaeb04b7e969638328fa70095cristy SetPixelBlack(morphology_image,ClampToQuantum(result.black), 29202b9582a27910c7baaeb04b7e969638328fa70095cristy q); 2921ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 29224c08aed51c5899665ade97263692328eea4af106cristy (image->matte == MagickTrue)) 29232b9582a27910c7baaeb04b7e969638328fa70095cristy SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha), 29242b9582a27910c7baaeb04b7e969638328fa70095cristy q); 29258d18850dee4bed193a64866a6d2353eeeb73e145anthony } 29268d18850dee4bed193a64866a6d2353eeeb73e145anthony else 29278d18850dee4bed193a64866a6d2353eeeb73e145anthony { /* Channel 'Sync' Flag, and Alpha Channel enabled. 29285ef8e94ff55717be2387d537bd49025780a1a558anthony ** Weight the color channels with Alpha Channel so that 29295ef8e94ff55717be2387d537bd49025780a1a558anthony ** transparent pixels are not part of the results. 29305ef8e94ff55717be2387d537bd49025780a1a558anthony */ 2931602ab9b30b644a78a4057da93d838a77391ec0acanthony MagickRealType 2932c406ea496196b962e4bc865ed8f6a4491241c6edanthony alpha, /* alpha weighting of colors : kernel*alpha */ 2933c406ea496196b962e4bc865ed8f6a4491241c6edanthony gamma; /* divisor, sum of color weighting values */ 2934602ab9b30b644a78a4057da93d838a77391ec0acanthony 2935602ab9b30b644a78a4057da93d838a77391ec0acanthony gamma=0.0; 2936bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 2937bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k--) { 2938602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( IsNan(*k) ) continue; 2939c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy alpha=(*k)*(QuantumScale*GetPixelAlpha(image,k_pixels+u* 2940ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelChannels(image))); 2941602ab9b30b644a78a4057da93d838a77391ec0acanthony gamma += alpha; 29424c08aed51c5899665ade97263692328eea4af106cristy result.red += alpha* 2943ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image)); 29444c08aed51c5899665ade97263692328eea4af106cristy result.green += alpha* 2945ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)); 29464c08aed51c5899665ade97263692328eea4af106cristy result.blue += alpha* 2947ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)); 29484c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 29494c08aed51c5899665ade97263692328eea4af106cristy result.black+=alpha* 2950ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)); 29514c08aed51c5899665ade97263692328eea4af106cristy result.alpha += (*k)* 2952ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)); 2953602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2954ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 2955602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2956c406ea496196b962e4bc865ed8f6a4491241c6edanthony /* Sync'ed channels, all channels are modified */ 2957602ab9b30b644a78a4057da93d838a77391ec0acanthony gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma); 29584c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image, 29594c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.red),q); 29604c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image, 29614c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.green),q); 29624c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image, 29634c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.blue),q); 2964c406ea496196b962e4bc865ed8f6a4491241c6edanthony if (image->colorspace == CMYKColorspace) 29654c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image, 29664c08aed51c5899665ade97263692328eea4af106cristy ClampToQuantum(gamma*result.black),q); 29674c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q); 2968602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2969602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 2970602ab9b30b644a78a4057da93d838a77391ec0acanthony 29714fd27e21043be809d66c8202e779255e5b660d2danthony case ErodeMorphology: 29725ef8e94ff55717be2387d537bd49025780a1a558anthony /* Minimum Value within kernel neighbourhood 2973930be614b4595b97cd79ee864a394796740f76adanthony ** 2974930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE that the kernel is not reflected for this operation! 2975930be614b4595b97cd79ee864a394796740f76adanthony ** 2976930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE: in normal Greyscale Morphology, the kernel value should 2977930be614b4595b97cd79ee864a394796740f76adanthony ** be added to the real value, this is currently not done, due to 2978930be614b4595b97cd79ee864a394796740f76adanthony ** the nature of the boolean kernels being used. 2979930be614b4595b97cd79ee864a394796740f76adanthony */ 29804fd27e21043be809d66c8202e779255e5b660d2danthony k = kernel->values; 2981602ab9b30b644a78a4057da93d838a77391ec0acanthony k_pixels = p; 2982bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 2983bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k++) { 2984602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( IsNan(*k) || (*k) < 0.5 ) continue; 29854c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.red, (double) 2986ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 29874c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.green, (double) 2988ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 29894c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.blue, (double) 2990ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 29914c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 29924c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.black,(double) 2993ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 29944c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.alpha,(double) 2995ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 2996602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2997ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 2998602ab9b30b644a78a4057da93d838a77391ec0acanthony } 2999602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3000602ab9b30b644a78a4057da93d838a77391ec0acanthony 30014fd27e21043be809d66c8202e779255e5b660d2danthony case DilateMorphology: 30025ef8e94ff55717be2387d537bd49025780a1a558anthony /* Maximum Value within kernel neighbourhood 3003930be614b4595b97cd79ee864a394796740f76adanthony ** 3004930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE for correct working of this operation for asymetrical 3005930be614b4595b97cd79ee864a394796740f76adanthony ** kernels, the kernel needs to be applied in its reflected form. 3006930be614b4595b97cd79ee864a394796740f76adanthony ** That is its values needs to be reversed. 3007930be614b4595b97cd79ee864a394796740f76adanthony ** 3008930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE: in normal Greyscale Morphology, the kernel value should 3009930be614b4595b97cd79ee864a394796740f76adanthony ** be added to the real value, this is currently not done, due to 3010930be614b4595b97cd79ee864a394796740f76adanthony ** the nature of the boolean kernels being used. 3011930be614b4595b97cd79ee864a394796740f76adanthony ** 3012930be614b4595b97cd79ee864a394796740f76adanthony */ 30134fd27e21043be809d66c8202e779255e5b660d2danthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 3014602ab9b30b644a78a4057da93d838a77391ec0acanthony k_pixels = p; 3015bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3016bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3017602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( IsNan(*k) || (*k) < 0.5 ) continue; 30184c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.red, (double) 3019ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 30204c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.green, (double) 3021ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 30224c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.blue, (double) 3023ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 30244c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 30254c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.black, (double) 3026ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 30274c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.alpha,(double) 3028ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 3029602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3030ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3031602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3032602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3033602ab9b30b644a78a4057da93d838a77391ec0acanthony 30345ef8e94ff55717be2387d537bd49025780a1a558anthony case HitAndMissMorphology: 30355ef8e94ff55717be2387d537bd49025780a1a558anthony case ThinningMorphology: 30365ef8e94ff55717be2387d537bd49025780a1a558anthony case ThickenMorphology: 30375ef8e94ff55717be2387d537bd49025780a1a558anthony /* Minimum of Foreground Pixel minus Maxumum of Background Pixels 30385ef8e94ff55717be2387d537bd49025780a1a558anthony ** 30395ef8e94ff55717be2387d537bd49025780a1a558anthony ** NOTE that the kernel is not reflected for this operation, 30405ef8e94ff55717be2387d537bd49025780a1a558anthony ** and consists of both foreground and background pixel 30415ef8e94ff55717be2387d537bd49025780a1a558anthony ** neighbourhoods, 0.0 for background, and 1.0 for foreground 30425ef8e94ff55717be2387d537bd49025780a1a558anthony ** with either Nan or 0.5 values for don't care. 30435ef8e94ff55717be2387d537bd49025780a1a558anthony ** 30444c827ef1be3d42450ff45cedad271e6568be0ea9anthony ** Note that this will never produce a meaningless negative 30454c827ef1be3d42450ff45cedad271e6568be0ea9anthony ** result. Such results can cause Thinning/Thicken to not work 30464c827ef1be3d42450ff45cedad271e6568be0ea9anthony ** correctly when used against a greyscale image. 30475ef8e94ff55717be2387d537bd49025780a1a558anthony */ 30485ef8e94ff55717be2387d537bd49025780a1a558anthony k = kernel->values; 30495ef8e94ff55717be2387d537bd49025780a1a558anthony k_pixels = p; 3050bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3051bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k++) { 30525ef8e94ff55717be2387d537bd49025780a1a558anthony if ( IsNan(*k) ) continue; 30535ef8e94ff55717be2387d537bd49025780a1a558anthony if ( (*k) > 0.7 ) 30545ef8e94ff55717be2387d537bd49025780a1a558anthony { /* minimim of foreground pixels */ 30554c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.red, (double) 3056ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 30574c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.green, (double) 3058ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 30594c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.blue, (double) 3060ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 30615ef8e94ff55717be2387d537bd49025780a1a558anthony if ( image->colorspace == CMYKColorspace) 30624c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.black,(double) 3063ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 30644c08aed51c5899665ade97263692328eea4af106cristy Minimize(min.alpha,(double) 3065ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 30665ef8e94ff55717be2387d537bd49025780a1a558anthony } 30675ef8e94ff55717be2387d537bd49025780a1a558anthony else if ( (*k) < 0.3 ) 30685ef8e94ff55717be2387d537bd49025780a1a558anthony { /* maximum of background pixels */ 30694c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.red, (double) 3070ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 30714c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.green, (double) 3072ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 30734c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.blue, (double) 3074ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 30754c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 30764c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.black, (double) 3077ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 30784c08aed51c5899665ade97263692328eea4af106cristy Maximize(max.alpha,(double) 3079ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 30805ef8e94ff55717be2387d537bd49025780a1a558anthony } 30815ef8e94ff55717be2387d537bd49025780a1a558anthony } 3082ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 30835ef8e94ff55717be2387d537bd49025780a1a558anthony } 30844c827ef1be3d42450ff45cedad271e6568be0ea9anthony /* Pattern Match if difference is positive */ 30855ef8e94ff55717be2387d537bd49025780a1a558anthony min.red -= max.red; Maximize( min.red, 0.0 ); 30865ef8e94ff55717be2387d537bd49025780a1a558anthony min.green -= max.green; Maximize( min.green, 0.0 ); 30875ef8e94ff55717be2387d537bd49025780a1a558anthony min.blue -= max.blue; Maximize( min.blue, 0.0 ); 30884c08aed51c5899665ade97263692328eea4af106cristy min.black -= max.black; Maximize( min.black, 0.0 ); 308970b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy min.alpha -= max.alpha; Maximize( min.alpha, 0.0 ); 30905ef8e94ff55717be2387d537bd49025780a1a558anthony break; 30915ef8e94ff55717be2387d537bd49025780a1a558anthony 30924fd27e21043be809d66c8202e779255e5b660d2danthony case ErodeIntensityMorphology: 3093930be614b4595b97cd79ee864a394796740f76adanthony /* Select Pixel with Minimum Intensity within kernel neighbourhood 3094930be614b4595b97cd79ee864a394796740f76adanthony ** 3095930be614b4595b97cd79ee864a394796740f76adanthony ** WARNING: the intensity test fails for CMYK and does not 3096c406ea496196b962e4bc865ed8f6a4491241c6edanthony ** take into account the moderating effect of the alpha channel 3097930be614b4595b97cd79ee864a394796740f76adanthony ** on the intensity. 3098930be614b4595b97cd79ee864a394796740f76adanthony ** 3099930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE that the kernel is not reflected for this operation! 3100930be614b4595b97cd79ee864a394796740f76adanthony */ 31014fd27e21043be809d66c8202e779255e5b660d2danthony k = kernel->values; 3102602ab9b30b644a78a4057da93d838a77391ec0acanthony k_pixels = p; 3103bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3104bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k++) { 31054fd27e21043be809d66c8202e779255e5b660d2danthony if ( IsNan(*k) || (*k) < 0.5 ) continue; 310629188a8682a98d4b7882cca434b170517555fc7danthony if ( result.red == 0.0 || 3107ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelIntensity(image,k_pixels+u*GetPixelChannels(image)) < GetPixelIntensity(morphology_image,q) ) { 310829188a8682a98d4b7882cca434b170517555fc7danthony /* copy the whole pixel - no channel selection */ 3109c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelRed(morphology_image,GetPixelRed(image, 3110ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3111c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelGreen(morphology_image,GetPixelGreen(image, 3112ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3113c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelBlue(morphology_image,GetPixelBlue(image, 3114ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3115c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelAlpha(morphology_image,GetPixelAlpha(image, 3116ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 311729188a8682a98d4b7882cca434b170517555fc7danthony if ( result.red > 0.0 ) changed++; 311829188a8682a98d4b7882cca434b170517555fc7danthony result.red = 1.0; 311929188a8682a98d4b7882cca434b170517555fc7danthony } 3120602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3121ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3122602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3123602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3124602ab9b30b644a78a4057da93d838a77391ec0acanthony 31254fd27e21043be809d66c8202e779255e5b660d2danthony case DilateIntensityMorphology: 3126930be614b4595b97cd79ee864a394796740f76adanthony /* Select Pixel with Maximum Intensity within kernel neighbourhood 3127930be614b4595b97cd79ee864a394796740f76adanthony ** 3128930be614b4595b97cd79ee864a394796740f76adanthony ** WARNING: the intensity test fails for CMYK and does not 31299eb4f74649b23c053b308ce1152dce51239450baanthony ** take into account the moderating effect of the alpha channel 31309eb4f74649b23c053b308ce1152dce51239450baanthony ** on the intensity (yet). 3131930be614b4595b97cd79ee864a394796740f76adanthony ** 3132930be614b4595b97cd79ee864a394796740f76adanthony ** NOTE for correct working of this operation for asymetrical 3133930be614b4595b97cd79ee864a394796740f76adanthony ** kernels, the kernel needs to be applied in its reflected form. 3134930be614b4595b97cd79ee864a394796740f76adanthony ** That is its values needs to be reversed. 3135930be614b4595b97cd79ee864a394796740f76adanthony */ 31364fd27e21043be809d66c8202e779255e5b660d2danthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 3137602ab9b30b644a78a4057da93d838a77391ec0acanthony k_pixels = p; 3138bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3139bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k--) { 31404fd27e21043be809d66c8202e779255e5b660d2danthony if ( IsNan(*k) || (*k) < 0.5 ) continue; /* boolean kernel */ 314129188a8682a98d4b7882cca434b170517555fc7danthony if ( result.red == 0.0 || 3142ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelIntensity(image,k_pixels+u*GetPixelChannels(image)) > GetPixelIntensity(morphology_image,q) ) { 314329188a8682a98d4b7882cca434b170517555fc7danthony /* copy the whole pixel - no channel selection */ 3144c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelRed(morphology_image,GetPixelRed(image, 3145ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3146c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelGreen(morphology_image,GetPixelGreen(image, 3147ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3148c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelBlue(morphology_image,GetPixelBlue(image, 3149ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 3150c3e9048b352dd133cd2b85ff0de964b3d0dd37abcristy SetPixelAlpha(morphology_image,GetPixelAlpha(image, 3151ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels+u*GetPixelChannels(image)),q); 315229188a8682a98d4b7882cca434b170517555fc7danthony if ( result.red > 0.0 ) changed++; 315329188a8682a98d4b7882cca434b170517555fc7danthony result.red = 1.0; 315429188a8682a98d4b7882cca434b170517555fc7danthony } 3155602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3156ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3157602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3158602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3159a8843c1f815ffad2568ec592d5b446cb1476aab5anthony#if 0 3160db60568e12574785101a4ae8d8da076227a0a889anthony This code has been obsoleted by the MorphologyPrimitiveDirect() function. 3161db60568e12574785101a4ae8d8da076227a0a889anthony However it is still (almost) correct coding for Grayscale Morphology. 3162db60568e12574785101a4ae8d8da076227a0a889anthony That is... 3163db60568e12574785101a4ae8d8da076227a0a889anthony 3164f0a92fd8deb68d411304359906b12679b675691fglennrp GrayErode is equivalent but with kernel values subtracted from pixels 3165db60568e12574785101a4ae8d8da076227a0a889anthony without the kernel rotation 3166f0a92fd8deb68d411304359906b12679b675691fglennrp GreyDilate is equivalent but using Maximum() instead of Minimum() 316757fe7a498c1302232dac8466864e84b12fad0807anthony using kernel rotation 316857fe7a498c1302232dac8466864e84b12fad0807anthony 316957fe7a498c1302232dac8466864e84b12fad0807anthony It has thus been preserved for future implementation of those methods. 3170db60568e12574785101a4ae8d8da076227a0a889anthony 3171602ab9b30b644a78a4057da93d838a77391ec0acanthony case DistanceMorphology: 3172930be614b4595b97cd79ee864a394796740f76adanthony /* Add kernel Value and select the minimum value found. 3173930be614b4595b97cd79ee864a394796740f76adanthony ** The result is a iterative distance from edge of image shape. 3174930be614b4595b97cd79ee864a394796740f76adanthony ** 3175930be614b4595b97cd79ee864a394796740f76adanthony ** All Distance Kernels are symetrical, but that may not always 3176930be614b4595b97cd79ee864a394796740f76adanthony ** be the case. For example how about a distance from left edges? 3177930be614b4595b97cd79ee864a394796740f76adanthony ** To work correctly with asymetrical kernels the reflected kernel 3178930be614b4595b97cd79ee864a394796740f76adanthony ** needs to be applied. 3179930be614b4595b97cd79ee864a394796740f76adanthony */ 318029188a8682a98d4b7882cca434b170517555fc7danthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 3181602ab9b30b644a78a4057da93d838a77391ec0acanthony k_pixels = p; 3182bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (v=0; v < (ssize_t) kernel->height; v++) { 3183bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3184602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( IsNan(*k) ) continue; 3185602ab9b30b644a78a4057da93d838a77391ec0acanthony Minimize(result.red, (*k)+k_pixels[u].red); 3186602ab9b30b644a78a4057da93d838a77391ec0acanthony Minimize(result.green, (*k)+k_pixels[u].green); 3187602ab9b30b644a78a4057da93d838a77391ec0acanthony Minimize(result.blue, (*k)+k_pixels[u].blue); 31884c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.alpha, (*k)+k_pixels[u].alpha); 3189602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( image->colorspace == CMYKColorspace) 31904c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.black,(*k)+GetPixelBlack(p_image,k_indexes+u)); 3191602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3192ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3193602ab9b30b644a78a4057da93d838a77391ec0acanthony } 3194602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3195a8843c1f815ffad2568ec592d5b446cb1476aab5anthony#endif 3196602ab9b30b644a78a4057da93d838a77391ec0acanthony case UndefinedMorphology: 3197602ab9b30b644a78a4057da93d838a77391ec0acanthony default: 3198602ab9b30b644a78a4057da93d838a77391ec0acanthony break; /* Do nothing */ 319983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 32005ef8e94ff55717be2387d537bd49025780a1a558anthony /* Final mathematics of results (combine with original image?) 32015ef8e94ff55717be2387d537bd49025780a1a558anthony ** 32025ef8e94ff55717be2387d537bd49025780a1a558anthony ** NOTE: Difference Morphology operators Edge* and *Hat could also 32035ef8e94ff55717be2387d537bd49025780a1a558anthony ** be done here but works better with iteration as a image difference 32045ef8e94ff55717be2387d537bd49025780a1a558anthony ** in the controling function (below). Thicken and Thinning however 32055ef8e94ff55717be2387d537bd49025780a1a558anthony ** should be done here so thay can be iterated correctly. 32065ef8e94ff55717be2387d537bd49025780a1a558anthony */ 32075ef8e94ff55717be2387d537bd49025780a1a558anthony switch ( method ) { 32085ef8e94ff55717be2387d537bd49025780a1a558anthony case HitAndMissMorphology: 32095ef8e94ff55717be2387d537bd49025780a1a558anthony case ErodeMorphology: 32105ef8e94ff55717be2387d537bd49025780a1a558anthony result = min; /* minimum of neighbourhood */ 32115ef8e94ff55717be2387d537bd49025780a1a558anthony break; 32125ef8e94ff55717be2387d537bd49025780a1a558anthony case DilateMorphology: 32135ef8e94ff55717be2387d537bd49025780a1a558anthony result = max; /* maximum of neighbourhood */ 32145ef8e94ff55717be2387d537bd49025780a1a558anthony break; 32155ef8e94ff55717be2387d537bd49025780a1a558anthony case ThinningMorphology: 32165ef8e94ff55717be2387d537bd49025780a1a558anthony /* subtract pattern match from original */ 32175ef8e94ff55717be2387d537bd49025780a1a558anthony result.red -= min.red; 32185ef8e94ff55717be2387d537bd49025780a1a558anthony result.green -= min.green; 32195ef8e94ff55717be2387d537bd49025780a1a558anthony result.blue -= min.blue; 32204c08aed51c5899665ade97263692328eea4af106cristy result.black -= min.black; 322170b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy result.alpha -= min.alpha; 32225ef8e94ff55717be2387d537bd49025780a1a558anthony break; 32235ef8e94ff55717be2387d537bd49025780a1a558anthony case ThickenMorphology: 32244c827ef1be3d42450ff45cedad271e6568be0ea9anthony /* Add the pattern matchs to the original */ 32254c827ef1be3d42450ff45cedad271e6568be0ea9anthony result.red += min.red; 32264c827ef1be3d42450ff45cedad271e6568be0ea9anthony result.green += min.green; 32274c827ef1be3d42450ff45cedad271e6568be0ea9anthony result.blue += min.blue; 32284c08aed51c5899665ade97263692328eea4af106cristy result.black += min.black; 322970b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy result.alpha += min.alpha; 32305ef8e94ff55717be2387d537bd49025780a1a558anthony break; 32315ef8e94ff55717be2387d537bd49025780a1a558anthony default: 32325ef8e94ff55717be2387d537bd49025780a1a558anthony /* result directly calculated or assigned */ 32335ef8e94ff55717be2387d537bd49025780a1a558anthony break; 32345ef8e94ff55717be2387d537bd49025780a1a558anthony } 32355ef8e94ff55717be2387d537bd49025780a1a558anthony /* Assign the resulting pixel values - Clamping Result */ 323683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony switch ( method ) { 323783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case UndefinedMorphology: 3238c406ea496196b962e4bc865ed8f6a4491241c6edanthony case ConvolveMorphology: 323983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case DilateIntensityMorphology: 324083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case ErodeIntensityMorphology: 3241930be614b4595b97cd79ee864a394796740f76adanthony break; /* full pixel was directly assigned - not a channel method */ 324283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony default: 3243ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 32444c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(morphology_image,ClampToQuantum(result.red),q); 3245ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 32464c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(morphology_image,ClampToQuantum(result.green),q); 3247ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 32484c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(morphology_image,ClampToQuantum(result.blue),q); 3249ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 32504c08aed51c5899665ade97263692328eea4af106cristy (image->colorspace == CMYKColorspace)) 32514c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(morphology_image,ClampToQuantum(result.black),q); 3252ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 32534c08aed51c5899665ade97263692328eea4af106cristy (image->matte == MagickTrue)) 32544c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q); 325583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony break; 325683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 32575ef8e94ff55717be2387d537bd49025780a1a558anthony /* Count up changed pixels */ 3258ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(morphology_image,q)) || 3259ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(morphology_image,q)) || 3260ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(morphology_image,q)) || 3261ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(morphology_image,q)) || 32624c08aed51c5899665ade97263692328eea4af106cristy ((image->colorspace == CMYKColorspace) && 3263ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(morphology_image,q)))) 3264c406ea496196b962e4bc865ed8f6a4491241c6edanthony changed++; /* The pixel was changed in some way! */ 3265ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p+=GetPixelChannels(image); 3266ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(morphology_image); 326783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } /* x */ 32684c08aed51c5899665ade97263692328eea4af106cristy if ( SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse) 3269602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 3270602ab9b30b644a78a4057da93d838a77391ec0acanthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 3271602ab9b30b644a78a4057da93d838a77391ec0acanthony { 3272602ab9b30b644a78a4057da93d838a77391ec0acanthony MagickBooleanType 3273602ab9b30b644a78a4057da93d838a77391ec0acanthony proceed; 3274602ab9b30b644a78a4057da93d838a77391ec0acanthony 3275602ab9b30b644a78a4057da93d838a77391ec0acanthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 3276602ab9b30b644a78a4057da93d838a77391ec0acanthony #pragma omp critical (MagickCore_MorphologyImage) 3277602ab9b30b644a78a4057da93d838a77391ec0acanthony#endif 3278602ab9b30b644a78a4057da93d838a77391ec0acanthony proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows); 3279602ab9b30b644a78a4057da93d838a77391ec0acanthony if (proceed == MagickFalse) 3280602ab9b30b644a78a4057da93d838a77391ec0acanthony status=MagickFalse; 3281602ab9b30b644a78a4057da93d838a77391ec0acanthony } 328283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } /* y */ 32834c08aed51c5899665ade97263692328eea4af106cristy morphology_view=DestroyCacheView(morphology_view); 32844c08aed51c5899665ade97263692328eea4af106cristy image_view=DestroyCacheView(image_view); 3285a8843c1f815ffad2568ec592d5b446cb1476aab5anthony return(status ? (ssize_t)changed : -1); 3286602ab9b30b644a78a4057da93d838a77391ec0acanthony} 3287602ab9b30b644a78a4057da93d838a77391ec0acanthony 3288a8843c1f815ffad2568ec592d5b446cb1476aab5anthony/* This is almost identical to the MorphologyPrimative() function above, 3289a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** but will apply the primitive directly to the image in two passes. 3290a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** 3291a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** That is after each row is 'Sync'ed' into the image, the next row will 3292a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** make use of those values as part of the calculation of the next row. 3293a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** It then repeats, but going in the oppisite (bottom-up) direction. 3294a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** 3295a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** Because of this 'iterative' handling this function can not make use 3296a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** of multi-threaded, parellel processing. 3297a8843c1f815ffad2568ec592d5b446cb1476aab5anthony*/ 3298e698a255629ba03cd125572de7b35b5e21c4ee5danthonystatic ssize_t MorphologyPrimitiveDirect(Image *image, 3299f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method,const KernelInfo *kernel, 3300f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 3301a8843c1f815ffad2568ec592d5b446cb1476aab5anthony{ 3302a8843c1f815ffad2568ec592d5b446cb1476aab5anthony CacheView 3303a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *auth_view, 3304a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *virt_view; 3305a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3306a8843c1f815ffad2568ec592d5b446cb1476aab5anthony MagickBooleanType 3307a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status; 3308a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3309a8843c1f815ffad2568ec592d5b446cb1476aab5anthony MagickOffsetType 3310a8843c1f815ffad2568ec592d5b446cb1476aab5anthony progress; 3311a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3312a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3313a8843c1f815ffad2568ec592d5b446cb1476aab5anthony y, offx, offy; 3314a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3315a8843c1f815ffad2568ec592d5b446cb1476aab5anthony size_t 3316db60568e12574785101a4ae8d8da076227a0a889anthony virt_width, 3317a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed; 3318a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3319a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickTrue; 3320a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed=0; 3321a8843c1f815ffad2568ec592d5b446cb1476aab5anthony progress=0; 3322a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3323a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(image != (Image *) NULL); 3324a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(image->signature == MagickSignature); 3325a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(kernel != (KernelInfo *) NULL); 3326a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(kernel->signature == MagickSignature); 3327a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(exception != (ExceptionInfo *) NULL); 3328a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert(exception->signature == MagickSignature); 3329a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3330a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Some methods (including convolve) needs use a reflected kernel. 3331a8843c1f815ffad2568ec592d5b446cb1476aab5anthony * Adjust 'origin' offsets to loop though kernel as a reflection. 3332a8843c1f815ffad2568ec592d5b446cb1476aab5anthony */ 3333a8843c1f815ffad2568ec592d5b446cb1476aab5anthony offx = kernel->x; 3334a8843c1f815ffad2568ec592d5b446cb1476aab5anthony offy = kernel->y; 3335a8843c1f815ffad2568ec592d5b446cb1476aab5anthony switch(method) { 3336a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3337e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3338a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* kernel needs to used with reflection about origin */ 3339a8843c1f815ffad2568ec592d5b446cb1476aab5anthony offx = (ssize_t) kernel->width-offx-1; 3340a8843c1f815ffad2568ec592d5b446cb1476aab5anthony offy = (ssize_t) kernel->height-offy-1; 3341a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3342a8843c1f815ffad2568ec592d5b446cb1476aab5anthony#if 0 3343a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case ?????Morphology: 3344a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* kernel is used as is, without reflection */ 3345a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3346a8843c1f815ffad2568ec592d5b446cb1476aab5anthony#endif 3347a8843c1f815ffad2568ec592d5b446cb1476aab5anthony default: 3348a8843c1f815ffad2568ec592d5b446cb1476aab5anthony assert("Not a PrimativeDirect Morphology Method" != (char *) NULL); 3349a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3350a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3351a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3352a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* DO NOT THREAD THIS CODE! */ 3353a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* two views into same image (virtual, and actual) */ 3354a8843c1f815ffad2568ec592d5b446cb1476aab5anthony virt_view=AcquireCacheView(image); 3355a8843c1f815ffad2568ec592d5b446cb1476aab5anthony auth_view=AcquireCacheView(image); 3356db60568e12574785101a4ae8d8da076227a0a889anthony virt_width=image->columns+kernel->width-1; 3357a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3358a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (y=0; y < (ssize_t) image->rows; y++) 3359a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 33604c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3361a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict p; 3362a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 33634c08aed51c5899665ade97263692328eea4af106cristy register Quantum 3364a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict q; 3365a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3366a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register ssize_t 3367a8843c1f815ffad2568ec592d5b446cb1476aab5anthony x; 3368a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3369a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3370a8843c1f815ffad2568ec592d5b446cb1476aab5anthony r; 3371a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3372a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* NOTE read virtual pixels, and authentic pixels, from the same image! 3373a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** we read using virtual to get virtual pixel handling, but write back 3374a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** into the same image. 3375a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** 3376a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** Only top half of kernel is processed as we do a single pass downward 3377a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** through the image iterating the distance function as we go. 3378a8843c1f815ffad2568ec592d5b446cb1476aab5anthony */ 3379a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (status == MagickFalse) 3380a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 33814c08aed51c5899665ade97263692328eea4af106cristy p=GetCacheViewVirtualPixels(virt_view,-offx,y-offy,virt_width,(size_t) 33824c08aed51c5899665ade97263692328eea4af106cristy offy+1,exception); 3383db60568e12574785101a4ae8d8da076227a0a889anthony q=GetCacheViewAuthenticPixels(auth_view, 0, y, image->columns, 1, 33844c08aed51c5899665ade97263692328eea4af106cristy exception); 33854c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 3386a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3387a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (status == MagickFalse) 3388a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3389a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3390a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* offset to origin in 'p'. while 'q' points to it directly */ 3391aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy r = (ssize_t) virt_width*offy + offx; 3392a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3393a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (x=0; x < (ssize_t) image->columns; x++) 3394a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 3395a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3396a8843c1f815ffad2568ec592d5b446cb1476aab5anthony v; 3397a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3398a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register ssize_t 3399a8843c1f815ffad2568ec592d5b446cb1476aab5anthony u; 3400a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3401a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register const double 3402a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict k; 3403a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 34044c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3405a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict k_pixels; 3406a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 34074c08aed51c5899665ade97263692328eea4af106cristy PixelInfo 3408a8843c1f815ffad2568ec592d5b446cb1476aab5anthony result; 3409a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3410e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Starting Defaults */ 34114c08aed51c5899665ade97263692328eea4af106cristy GetPixelInfo(image,&result); 34124c08aed51c5899665ade97263692328eea4af106cristy SetPixelInfo(image,q,&result); 3413e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( method != VoronoiMorphology ) 34144c08aed51c5899665ade97263692328eea4af106cristy result.alpha = QuantumRange - result.alpha; 3415a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3416a8843c1f815ffad2568ec592d5b446cb1476aab5anthony switch ( method ) { 3417a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3418a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Add kernel Value and select the minimum value found. */ 3419a8843c1f815ffad2568ec592d5b446cb1476aab5anthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 3420a8843c1f815ffad2568ec592d5b446cb1476aab5anthony k_pixels = p; 3421a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (v=0; v <= (ssize_t) offy; v++) { 3422a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3423a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( IsNan(*k) ) continue; 34244c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.red, (*k)+ 3425ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 34264c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.green, (*k)+ 3427ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 34284c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.blue, (*k)+ 3429ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 34304c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 34314c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.black,(*k)+ 3432ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 34334c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.alpha, (*k)+ 3434ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 3435a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3436ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3437a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3438a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* repeat with the just processed pixels of this row */ 3439db60568e12574785101a4ae8d8da076227a0a889anthony k = &kernel->values[ kernel->width*(kernel->y+1)-1 ]; 3440ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels = q-offx*GetPixelChannels(image); 3441a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (u=0; u < (ssize_t) offx; u++, k--) { 3442a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( x+u-offx < 0 ) continue; /* off the edge! */ 3443a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( IsNan(*k) ) continue; 34444c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.red, (*k)+ 3445ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 34464c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.green, (*k)+ 3447ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 34484c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.blue, (*k)+ 3449ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 34504c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 34514c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.black,(*k)+ 3452ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 34534c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.alpha,(*k)+ 3454ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 3455a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3456a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3457e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3458e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Apply Distance to 'Matte' channel, coping the closest color. 3459e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** 3460e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** This is experimental, and realy the 'alpha' component should 3461e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** be completely separate 'masking' channel. 3462e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 3463e698a255629ba03cd125572de7b35b5e21c4ee5danthony k = &kernel->values[ kernel->width*kernel->height-1 ]; 3464e698a255629ba03cd125572de7b35b5e21c4ee5danthony k_pixels = p; 3465e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (v=0; v <= (ssize_t) offy; v++) { 3466e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3467e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( IsNan(*k) ) continue; 3468ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) ) 3469e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3470ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy SetPixelInfo(image,k_pixels+u*GetPixelChannels(image), 34714a06a14c06f675b6a2052a3c814e7da54877a733cristy &result); 34724c08aed51c5899665ade97263692328eea4af106cristy result.alpha += *k; 3473e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3474e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3475ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3476e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3477e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* repeat with the just processed pixels of this row */ 3478e698a255629ba03cd125572de7b35b5e21c4ee5danthony k = &kernel->values[ kernel->width*(kernel->y+1)-1 ]; 3479ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels = q-offx*GetPixelChannels(image); 3480e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (u=0; u < (ssize_t) offx; u++, k--) { 3481e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( x+u-offx < 0 ) continue; /* off the edge! */ 3482e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( IsNan(*k) ) continue; 3483ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) ) 3484e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3485ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy SetPixelInfo(image,k_pixels+u*GetPixelChannels(image), 34864a06a14c06f675b6a2052a3c814e7da54877a733cristy &result); 34874c08aed51c5899665ade97263692328eea4af106cristy result.alpha += *k; 3488e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3489e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3490e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3491a8843c1f815ffad2568ec592d5b446cb1476aab5anthony default: 3492a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* result directly calculated or assigned */ 3493a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3494a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3495a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Assign the resulting pixel values - Clamping Result */ 3496e698a255629ba03cd125572de7b35b5e21c4ee5danthony switch ( method ) { 3497e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 34984c08aed51c5899665ade97263692328eea4af106cristy SetPixelPixelInfo(image,&result,q); 3499e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3500e698a255629ba03cd125572de7b35b5e21c4ee5danthony default: 3501ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 35024c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(image,ClampToQuantum(result.red),q); 3503ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 35044c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(image,ClampToQuantum(result.green),q); 3505ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 35064c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(image,ClampToQuantum(result.blue),q); 3507ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 35084c08aed51c5899665ade97263692328eea4af106cristy (image->colorspace == CMYKColorspace)) 35094c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(image,ClampToQuantum(result.black),q); 3510ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0 && 35112b9582a27910c7baaeb04b7e969638328fa70095cristy (image->matte == MagickTrue)) 35124c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(image,ClampToQuantum(result.alpha),q); 3513e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3514e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3515a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Count up changed pixels */ 3516ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(image,q)) || 3517ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(image,q)) || 3518ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(image,q)) || 3519ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(image,q)) || 35204c08aed51c5899665ade97263692328eea4af106cristy ((image->colorspace == CMYKColorspace) && 3521ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(image,q)))) 3522a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed++; /* The pixel was changed in some way! */ 3523a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3524ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p+=GetPixelChannels(image); /* increment pixel buffers */ 3525ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(image); 3526a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* x */ 35274fd27e21043be809d66c8202e779255e5b660d2danthony 3528a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( SyncCacheViewAuthenticPixels(auth_view,exception) == MagickFalse) 3529a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3530a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 3531a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( SetImageProgress(image,MorphologyTag,progress++,image->rows) 3532a8843c1f815ffad2568ec592d5b446cb1476aab5anthony == MagickFalse ) 3533a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3534a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3535a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* y */ 3536a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3537a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Do the reversed pass through the image */ 3538a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (y=(ssize_t)image->rows-1; y >= 0; y--) 3539a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 35404c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3541a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict p; 3542a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 35434c08aed51c5899665ade97263692328eea4af106cristy register Quantum 3544a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict q; 3545a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3546a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register ssize_t 3547a8843c1f815ffad2568ec592d5b446cb1476aab5anthony x; 3548a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3549a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3550a8843c1f815ffad2568ec592d5b446cb1476aab5anthony r; 3551a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3552db60568e12574785101a4ae8d8da076227a0a889anthony if (status == MagickFalse) 3553db60568e12574785101a4ae8d8da076227a0a889anthony break; 3554a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* NOTE read virtual pixels, and authentic pixels, from the same image! 3555a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** we read using virtual to get virtual pixel handling, but write back 3556a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** into the same image. 3557a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** 3558a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** Only the bottom half of the kernel will be processes as we 3559a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ** up the image. 3560a8843c1f815ffad2568ec592d5b446cb1476aab5anthony */ 35614c08aed51c5899665ade97263692328eea4af106cristy p=GetCacheViewVirtualPixels(virt_view,-offx,y,virt_width,(size_t) 35624c08aed51c5899665ade97263692328eea4af106cristy kernel->y+1,exception); 3563db60568e12574785101a4ae8d8da076227a0a889anthony q=GetCacheViewAuthenticPixels(auth_view, 0, y, image->columns, 1, 35644c08aed51c5899665ade97263692328eea4af106cristy exception); 35654c08aed51c5899665ade97263692328eea4af106cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 3566a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3567a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (status == MagickFalse) 3568a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3569a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3570a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* adjust positions to end of row */ 3571ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p += (image->columns-1)*GetPixelChannels(image); 3572ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q += (image->columns-1)*GetPixelChannels(image); 3573a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3574a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* offset to origin in 'p'. while 'q' points to it directly */ 3575a8843c1f815ffad2568ec592d5b446cb1476aab5anthony r = offx; 3576a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3577a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (x=(ssize_t)image->columns-1; x >= 0; x--) 3578a8843c1f815ffad2568ec592d5b446cb1476aab5anthony { 3579a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3580a8843c1f815ffad2568ec592d5b446cb1476aab5anthony v; 3581a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3582a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register ssize_t 3583a8843c1f815ffad2568ec592d5b446cb1476aab5anthony u; 3584a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3585a8843c1f815ffad2568ec592d5b446cb1476aab5anthony register const double 3586a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict k; 3587a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 35884c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 3589a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *restrict k_pixels; 3590a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 35914c08aed51c5899665ade97263692328eea4af106cristy PixelInfo 3592a8843c1f815ffad2568ec592d5b446cb1476aab5anthony result; 3593a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3594e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Default - previously modified pixel */ 35954c08aed51c5899665ade97263692328eea4af106cristy GetPixelInfo(image,&result); 35964c08aed51c5899665ade97263692328eea4af106cristy SetPixelInfo(image,q,&result); 3597e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( method != VoronoiMorphology ) 35984c08aed51c5899665ade97263692328eea4af106cristy result.alpha = QuantumRange - result.alpha; 3599a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3600a8843c1f815ffad2568ec592d5b446cb1476aab5anthony switch ( method ) { 3601a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3602a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Add kernel Value and select the minimum value found. */ 3603db60568e12574785101a4ae8d8da076227a0a889anthony k = &kernel->values[ kernel->width*(kernel->y+1)-1 ]; 3604a8843c1f815ffad2568ec592d5b446cb1476aab5anthony k_pixels = p; 3605a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (v=offy; v < (ssize_t) kernel->height; v++) { 3606a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3607a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( IsNan(*k) ) continue; 36084c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.red, (*k)+ 3609ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 36104c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.green, (*k)+ 3611ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 36124c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.blue, (*k)+ 3613ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 3614a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( image->colorspace == CMYKColorspace) 36154c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.black,(*k)+ 3616ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 36174c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.alpha, (*k)+ 3618ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 3619a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3620ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3621a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3622a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* repeat with the just processed pixels of this row */ 3623db60568e12574785101a4ae8d8da076227a0a889anthony k = &kernel->values[ kernel->width*(kernel->y)+kernel->x-1 ]; 3624ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels = q-offx*GetPixelChannels(image); 3625a8843c1f815ffad2568ec592d5b446cb1476aab5anthony for (u=offx+1; u < (ssize_t) kernel->width; u++, k--) { 3626e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( (x+u-offx) >= (ssize_t)image->columns ) continue; 3627a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( IsNan(*k) ) continue; 36284c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.red, (*k)+ 3629ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelRed(image,k_pixels+u*GetPixelChannels(image))); 36304c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.green, (*k)+ 3631ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelGreen(image,k_pixels+u*GetPixelChannels(image))); 36324c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.blue, (*k)+ 3633ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlue(image,k_pixels+u*GetPixelChannels(image))); 3634a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( image->colorspace == CMYKColorspace) 36354c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.black, (*k)+ 3636ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelBlack(image,k_pixels+u*GetPixelChannels(image))); 36374c08aed51c5899665ade97263692328eea4af106cristy Minimize(result.alpha, (*k)+ 3638ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image))); 3639a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3640a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3641e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3642e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Apply Distance to 'Matte' channel, coping the closest color. 3643e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** 3644e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** This is experimental, and realy the 'alpha' component should 3645e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** be completely separate 'masking' channel. 3646e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 3647e698a255629ba03cd125572de7b35b5e21c4ee5danthony k = &kernel->values[ kernel->width*(kernel->y+1)-1 ]; 3648e698a255629ba03cd125572de7b35b5e21c4ee5danthony k_pixels = p; 3649e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (v=offy; v < (ssize_t) kernel->height; v++) { 3650e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (u=0; u < (ssize_t) kernel->width; u++, k--) { 3651e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( IsNan(*k) ) continue; 3652ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) ) 3653e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3654ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy SetPixelInfo(image,k_pixels+u*GetPixelChannels(image), 36554a06a14c06f675b6a2052a3c814e7da54877a733cristy &result); 36564c08aed51c5899665ade97263692328eea4af106cristy result.alpha += *k; 3657e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3658e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3659ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels += virt_width*GetPixelChannels(image); 3660e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3661e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* repeat with the just processed pixels of this row */ 3662e698a255629ba03cd125572de7b35b5e21c4ee5danthony k = &kernel->values[ kernel->width*(kernel->y)+kernel->x-1 ]; 3663ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy k_pixels = q-offx*GetPixelChannels(image); 3664e698a255629ba03cd125572de7b35b5e21c4ee5danthony for (u=offx+1; u < (ssize_t) kernel->width; u++, k--) { 3665e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( (x+u-offx) >= (ssize_t)image->columns ) continue; 3666e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( IsNan(*k) ) continue; 3667ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) ) 3668e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3669ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy SetPixelInfo(image,k_pixels+u*GetPixelChannels(image), 36704a06a14c06f675b6a2052a3c814e7da54877a733cristy &result); 36714c08aed51c5899665ade97263692328eea4af106cristy result.alpha += *k; 3672e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3673e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3674e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3675a8843c1f815ffad2568ec592d5b446cb1476aab5anthony default: 3676a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* result directly calculated or assigned */ 3677a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 3678a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } 3679a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Assign the resulting pixel values - Clamping Result */ 3680e698a255629ba03cd125572de7b35b5e21c4ee5danthony switch ( method ) { 3681e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 36824c08aed51c5899665ade97263692328eea4af106cristy SetPixelPixelInfo(image,&result,q); 3683e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3684e698a255629ba03cd125572de7b35b5e21c4ee5danthony default: 3685ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 36864c08aed51c5899665ade97263692328eea4af106cristy SetPixelRed(image,ClampToQuantum(result.red),q); 3687ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 36884c08aed51c5899665ade97263692328eea4af106cristy SetPixelGreen(image,ClampToQuantum(result.green),q); 3689ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 36904c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlue(image,ClampToQuantum(result.blue),q); 3691ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 36924c08aed51c5899665ade97263692328eea4af106cristy (image->colorspace == CMYKColorspace)) 36934c08aed51c5899665ade97263692328eea4af106cristy SetPixelBlack(image,ClampToQuantum(result.black),q); 3694ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0 && 36952b9582a27910c7baaeb04b7e969638328fa70095cristy (image->matte == MagickTrue)) 36964c08aed51c5899665ade97263692328eea4af106cristy SetPixelAlpha(image,ClampToQuantum(result.alpha),q); 3697e698a255629ba03cd125572de7b35b5e21c4ee5danthony break; 3698e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3699a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Count up changed pixels */ 3700ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ( (GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(image,q)) 3701ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(image,q)) 3702ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(image,q)) 3703ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy || (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(image,q)) 37044c08aed51c5899665ade97263692328eea4af106cristy || ((image->colorspace == CMYKColorspace) && 3705ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(image,q)))) 3706a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed++; /* The pixel was changed in some way! */ 3707a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3708ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p-=GetPixelChannels(image); /* go backward through pixel buffers */ 3709ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q-=GetPixelChannels(image); 3710a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* x */ 3711a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( SyncCacheViewAuthenticPixels(auth_view,exception) == MagickFalse) 3712a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3713a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if (image->progress_monitor != (MagickProgressMonitor) NULL) 3714a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( SetImageProgress(image,MorphologyTag,progress++,image->rows) 3715a8843c1f815ffad2568ec592d5b446cb1476aab5anthony == MagickFalse ) 3716a8843c1f815ffad2568ec592d5b446cb1476aab5anthony status=MagickFalse; 3717a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3718a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* y */ 3719e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3720a8843c1f815ffad2568ec592d5b446cb1476aab5anthony auth_view=DestroyCacheView(auth_view); 3721a8843c1f815ffad2568ec592d5b446cb1476aab5anthony virt_view=DestroyCacheView(virt_view); 3722aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy return(status ? (ssize_t) changed : -1); 3723a8843c1f815ffad2568ec592d5b446cb1476aab5anthony} 3724a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 3725a8843c1f815ffad2568ec592d5b446cb1476aab5anthony/* Apply a Morphology by calling theabove low level primitive application 3726a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** functions. This function handles any iteration loops, composition or 3727a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** re-iteration of results, and compound morphology methods that is based 3728a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** on multiple low-level (staged) morphology methods. 3729a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** 3730a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** Basically this provides the complex grue between the requested morphology 3731a8843c1f815ffad2568ec592d5b446cb1476aab5anthony** method and raw low-level implementation (above). 3732a8843c1f815ffad2568ec592d5b446cb1476aab5anthony*/ 3733cf592636b16d028b14c5fa9dffdc3a94eae7c2f3cristyMagickPrivate Image *MorphologyApply(const Image *image, 3734f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method, const ssize_t iterations, 3735f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const KernelInfo *kernel, const CompositeOperator compose,const double bias, 3736f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy ExceptionInfo *exception) 3737602ab9b30b644a78a4057da93d838a77391ec0acanthony{ 37381cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy CompositeOperator 37391cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy curr_compose; 37401cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy 3741602ab9b30b644a78a4057da93d838a77391ec0acanthony Image 374247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *curr_image, /* Image we are working with or iterating */ 3743a8843c1f815ffad2568ec592d5b446cb1476aab5anthony *work_image, /* secondary image for primitive iteration */ 374447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *save_image, /* saved image - for 'edge' method only */ 374547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *rslt_image; /* resultant image - after multi-kernel handling */ 3746602ab9b30b644a78a4057da93d838a77391ec0acanthony 37474fd27e21043be809d66c8202e779255e5b660d2danthony KernelInfo 374847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *reflected_kernel, /* A reflected copy of the kernel (if needed) */ 374947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *norm_kernel, /* the current normal un-reflected kernel */ 375047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *rflt_kernel, /* the current reflected kernel (if needed) */ 375147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony *this_kernel; /* the kernel being applied */ 37524fd27e21043be809d66c8202e779255e5b660d2danthony 37534fd27e21043be809d66c8202e779255e5b660d2danthony MorphologyMethod 3754a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive; /* the current morphology primitive being applied */ 37559eb4f74649b23c053b308ce1152dce51239450baanthony 37569eb4f74649b23c053b308ce1152dce51239450baanthony CompositeOperator 375747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose; /* multi-kernel compose method for results to use */ 375847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 375947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony MagickBooleanType 3760e698a255629ba03cd125572de7b35b5e21c4ee5danthony special, /* do we use a direct modify function? */ 376147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony verbose; /* verbose output of results */ 37624fd27e21043be809d66c8202e779255e5b660d2danthony 3763bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 3764a8843c1f815ffad2568ec592d5b446cb1476aab5anthony method_loop, /* Loop 1: number of compound method iterations (norm 1) */ 376547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_limit, /* maximum number of compound method iterations */ 376647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number, /* Loop 2: the kernel number being applied */ 3767a8843c1f815ffad2568ec592d5b446cb1476aab5anthony stage_loop, /* Loop 3: primitive loop for compound morphology */ 3768a8843c1f815ffad2568ec592d5b446cb1476aab5anthony stage_limit, /* how many primitives are in this compound */ 3769a8843c1f815ffad2568ec592d5b446cb1476aab5anthony kernel_loop, /* Loop 4: iterate the kernel over image */ 377047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_limit, /* number of times to iterate kernel */ 3771a8843c1f815ffad2568ec592d5b446cb1476aab5anthony count, /* total count of primitive steps applied */ 377247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_changed, /* total count of changed using iterated kernel */ 377347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed; /* total count of changed over method iteration */ 377447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 3775a8843c1f815ffad2568ec592d5b446cb1476aab5anthony ssize_t 3776a8843c1f815ffad2568ec592d5b446cb1476aab5anthony changed; /* number pixels changed by last primitive operation */ 3777a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 377847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony char 377947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony v_info[80]; 37801b2bc0a7da432e6e1cc0480280402df213faa940anthony 3781602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(image != (Image *) NULL); 3782602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(image->signature == MagickSignature); 37834fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel != (KernelInfo *) NULL); 37844fd27e21043be809d66c8202e779255e5b660d2danthony assert(kernel->signature == MagickSignature); 3785602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(exception != (ExceptionInfo *) NULL); 3786602ab9b30b644a78a4057da93d838a77391ec0acanthony assert(exception->signature == MagickSignature); 3787602ab9b30b644a78a4057da93d838a77391ec0acanthony 3788a8843c1f815ffad2568ec592d5b446cb1476aab5anthony count = 0; /* number of low-level morphology primitives performed */ 3789602ab9b30b644a78a4057da93d838a77391ec0acanthony if ( iterations == 0 ) 379047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return((Image *)NULL); /* null operation - nothing to do! */ 3791602ab9b30b644a78a4057da93d838a77391ec0acanthony 3792bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel_limit = (size_t) iterations; 379347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( iterations < 0 ) /* negative interations = infinite (well alomst) */ 3794e698a255629ba03cd125572de7b35b5e21c4ee5danthony kernel_limit = image->columns>image->rows ? image->columns : image->rows; 379528ad1d779b6ca95852e860514185a7a97e06af77anthony 379628ad1d779b6ca95852e860514185a7a97e06af77anthony verbose = IsMagickTrue(GetImageArtifact(image,"verbose")); 37974f1dcb76c95ef6410f2957ca9e7e1d391cee0d02anthony 37989eb4f74649b23c053b308ce1152dce51239450baanthony /* initialise for cleanup */ 379947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; 38001cf06410e6379f3c351adfc39a1b79a252c8e5b6cristy curr_compose = image->compose; 3801aecf4bd539fe0591d67bf1ec961ac68b5490171fcristy (void) curr_compose; 380247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = save_image = rslt_image = (Image *) NULL; 380347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = (KernelInfo *) NULL; 38044fd27e21043be809d66c8202e779255e5b660d2danthony 380547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Initialize specific methods 380647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony * + which loop should use the given iteratations 3807a8843c1f815ffad2568ec592d5b446cb1476aab5anthony * + how many primitives make up the compound morphology 380847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony * + multi-kernel compose method to use (by default) 380947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 381047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_limit = 1; /* just do method once, unless otherwise set */ 3811ea61f01656bb0f9074677452017cc559e54093faanthony stage_limit = 1; /* assume method is not a compound */ 38124ee950098ad0166bbbc85c3a59bc079cd321384aglennrp special = MagickFalse; /* assume it is NOT a direct modify primitive */ 381347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = compose; /* and we are composing multi-kernels as given */ 38149eb4f74649b23c053b308ce1152dce51239450baanthony switch( method ) { 3815a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case SmoothMorphology: /* 4 primitive compound morphology */ 381647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_limit = 4; 3817602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 3818a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case OpenMorphology: /* 2 primitive compound morphology */ 3819930be614b4595b97cd79ee864a394796740f76adanthony case OpenIntensityMorphology: 382047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: 382147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: 38224fd27e21043be809d66c8202e779255e5b660d2danthony case CloseIntensityMorphology: 382347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 382447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: 382547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_limit = 2; 3826602ab9b30b644a78a4057da93d838a77391ec0acanthony break; 38279eb4f74649b23c053b308ce1152dce51239450baanthony case HitAndMissMorphology: 382847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = LightenCompositeOp; /* Union of multi-kernel results */ 38293ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony /* FALL THUR */ 3830c3e48258f3253188894e783dcdfd03562f7ab2c5anthony case ThinningMorphology: 38319eb4f74649b23c053b308ce1152dce51239450baanthony case ThickenMorphology: 38323ca9ec1fec132c7e3c037a6fea16d8fdb9d3f29aanthony method_limit = kernel_limit; /* iterate the whole method */ 3833c3e48258f3253188894e783dcdfd03562f7ab2c5anthony kernel_limit = 1; /* do not do kernel iteration */ 383447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 3835a8843c1f815ffad2568ec592d5b446cb1476aab5anthony case DistanceMorphology: 3836e698a255629ba03cd125572de7b35b5e21c4ee5danthony case VoronoiMorphology: 3837e698a255629ba03cd125572de7b35b5e21c4ee5danthony special = MagickTrue; 3838a8843c1f815ffad2568ec592d5b446cb1476aab5anthony break; 383947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 38409eb4f74649b23c053b308ce1152dce51239450baanthony break; 38419eb4f74649b23c053b308ce1152dce51239450baanthony } 3842602ab9b30b644a78a4057da93d838a77391ec0acanthony 3843e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Apply special methods with special requirments 3844e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** For example, single run only, or post-processing requirements 3845e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 3846e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( special == MagickTrue ) 3847e698a255629ba03cd125572de7b35b5e21c4ee5danthony { 3848e698a255629ba03cd125572de7b35b5e21c4ee5danthony rslt_image=CloneImage(image,0,0,MagickTrue,exception); 3849e698a255629ba03cd125572de7b35b5e21c4ee5danthony if (rslt_image == (Image *) NULL) 3850e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto error_cleanup; 3851574cc26500992189f637cd1cdf93d0654e7df7aecristy if (SetImageStorageClass(rslt_image,DirectClass,exception) == MagickFalse) 3852574cc26500992189f637cd1cdf93d0654e7df7aecristy goto error_cleanup; 3853e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3854e698a255629ba03cd125572de7b35b5e21c4ee5danthony changed = MorphologyPrimitiveDirect(rslt_image, method, 3855f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy kernel, exception); 3856e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3857e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( verbose == MagickTrue ) 38585acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) (void) FormatLocaleFile(stderr, 38591e604812fad85bb96f757a2393015ae3d061c39acristy "%s:%.20g.%.20g #%.20g => Changed %.20g\n", 38601e604812fad85bb96f757a2393015ae3d061c39acristy CommandOptionToMnemonic(MagickMorphologyOptions, method), 38611e604812fad85bb96f757a2393015ae3d061c39acristy 1.0,0.0,1.0, (double) changed); 3862e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3863e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( changed < 0 ) 3864e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto error_cleanup; 3865e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3866e698a255629ba03cd125572de7b35b5e21c4ee5danthony if ( method == VoronoiMorphology ) { 3867e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Preserve the alpha channel of input image - but turned off */ 386863240888c3975789a09c2494a4654b523931df96cristy (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel, 386963240888c3975789a09c2494a4654b523931df96cristy exception); 3870f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy (void) CompositeImage(rslt_image, CopyOpacityCompositeOp, image, 0, 0); 387163240888c3975789a09c2494a4654b523931df96cristy (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel, 387263240888c3975789a09c2494a4654b523931df96cristy exception); 3873e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3874e698a255629ba03cd125572de7b35b5e21c4ee5danthony goto exit_cleanup; 3875e698a255629ba03cd125572de7b35b5e21c4ee5danthony } 3876e698a255629ba03cd125572de7b35b5e21c4ee5danthony 3877c3e48258f3253188894e783dcdfd03562f7ab2c5anthony /* Handle user (caller) specified multi-kernel composition method */ 387847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( compose != UndefinedCompositeOp ) 387947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = compose; /* override default composition for method */ 388047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rslt_compose == UndefinedCompositeOp ) 388147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_compose = NoCompositeOp; /* still not defined! Then re-iterate */ 38824fd27e21043be809d66c8202e779255e5b660d2danthony 3883a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Some methods require a reflected kernel to use with primitives. 3884c3e48258f3253188894e783dcdfd03562f7ab2c5anthony * Create the reflected kernel for those methods. */ 388547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch ( method ) { 388647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CorrelateMorphology: 388747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: 388847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseIntensityMorphology: 388947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 389047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case SmoothMorphology: 389147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = CloneKernelInfo(kernel); 389247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if (reflected_kernel == (KernelInfo *) NULL) 389347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony goto error_cleanup; 389447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony RotateKernelInfo(reflected_kernel,180); 389547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 389647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 389747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 389847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 3899602ab9b30b644a78a4057da93d838a77391ec0acanthony 3900e698a255629ba03cd125572de7b35b5e21c4ee5danthony /* Loops around more primitive morpholgy methods 3901e698a255629ba03cd125572de7b35b5e21c4ee5danthony ** erose, dilate, open, close, smooth, edge, etc... 3902e698a255629ba03cd125572de7b35b5e21c4ee5danthony */ 390347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 1: iterate the compound method */ 390447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_loop = 0; 390547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed = 1; 390647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( method_loop < method_limit && method_changed > 0 ) { 390747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_loop++; 390847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony method_changed = 0; 390947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 391047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 2: iterate over each kernel in a multi-kernel list */ 391147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony norm_kernel = (KernelInfo *) kernel; 3912f2faecf9facdbbb14fcba373365f9f691a9658e0cristy this_kernel = (KernelInfo *) kernel; 391347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rflt_kernel = reflected_kernel; 3914e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony 391547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number = 0; 391647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( norm_kernel != NULL ) { 391747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 391847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Loop 3: Compound Morphology Staging - Select Primative to apply */ 391947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_loop = 0; /* the compound morphology stage number */ 392047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( stage_loop < stage_limit ) { 392147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony stage_loop++; /* The stage of the compound morphology */ 392247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 3923a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Select primitive morphology for this stage of compound method */ 392447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = norm_kernel; /* default use unreflected kernel */ 3925a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = method; /* Assume method is a primitive */ 392647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch( method ) { 392747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case ErodeMorphology: /* just erode */ 392847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeInMorphology: /* erode and image difference */ 3929a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 393047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 393147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case DilateMorphology: /* just dilate */ 393247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeOutMorphology: /* dilate and image difference */ 3933a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 393447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 393547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case OpenMorphology: /* erode then dialate */ 393647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: /* open and image difference */ 3937a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 393847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3939a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 394047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 394147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case OpenIntensityMorphology: 3942a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeIntensityMorphology; 394347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3944a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateIntensityMorphology; 3945e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony break; 394647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseMorphology: /* dilate, then erode */ 394747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: /* close and image difference */ 394847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3949a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 395047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3951a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 395247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 395347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CloseIntensityMorphology: 395447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3955a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateIntensityMorphology; 395647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) 3957a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeIntensityMorphology; 395847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 395947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case SmoothMorphology: /* open, close */ 396047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch ( stage_loop ) { 396147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 1: /* start an open method, which starts with Erode */ 3962a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 396347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 396447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 2: /* now Dilate the Erode */ 3965a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 396647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 396747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 3: /* Reflect kernel a close */ 396847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3969a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 397047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 397147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case 4: /* Finish the Close */ 397247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3973a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 397447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 397547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 397647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 397747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: /* dilate and erode difference */ 3978a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = DilateMorphology; 397947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_loop == 2 ) { 398047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = curr_image; /* save the image difference */ 398147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; 3982a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ErodeMorphology; 398347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 398447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 398547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case CorrelateMorphology: 398647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* A Correlation is a Convolution with a reflected kernel. 398747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** However a Convolution is a weighted sum using a reflected 398847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** kernel. It may seem stange to convert a Correlation into a 398947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Convolution as the Correlation is the simplier method, but 399047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Convolution is much more commonly used, and it makes sense to 399147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** implement it directly so as to avoid the need to duplicate the 399247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** kernel when it is not required (which is typically the 399347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** default). 399447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 399547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony this_kernel = rflt_kernel; /* use the reflected kernel */ 3996a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive = ConvolveMorphology; 399747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 399847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 399947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 400047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 4001e4d8996e5c17ae40a1160f3446956e12ec00bc9canthony assert( this_kernel != (KernelInfo *) NULL ); 40027a01dcf50ce12cb2a789bedff51e9345f022432eanthony 400347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Extra information for debugging compound operations */ 400447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( verbose == MagickTrue ) { 400547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( stage_limit > 1 ) 4006b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy (void) FormatLocaleString(v_info,MaxTextExtent,"%s:%.20g.%.20g -> ", 4007042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickMorphologyOptions,method),(double) 4008e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy method_loop,(double) stage_loop); 4009a8843c1f815ffad2568ec592d5b446cb1476aab5anthony else if ( primitive != method ) 4010b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy (void) FormatLocaleString(v_info, MaxTextExtent, "%s:%.20g -> ", 4011042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickMorphologyOptions, method),(double) 4012e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy method_loop); 401347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else 401447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony v_info[0] = '\0'; 401547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 40169eb4f74649b23c053b308ce1152dce51239450baanthony 4017a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Loop 4: Iterate the kernel with primitive */ 401847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_loop = 0; 401947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_changed = 0; 402047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony changed = 1; 402147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony while ( kernel_loop < kernel_limit && changed > 0 ) { 402247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_loop++; /* the iteration of this kernel */ 40239eb4f74649b23c053b308ce1152dce51239450baanthony 4024a8843c1f815ffad2568ec592d5b446cb1476aab5anthony /* Create a clone as the destination image, if not yet defined */ 40259eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image == (Image *) NULL ) 40269eb4f74649b23c053b308ce1152dce51239450baanthony { 40279eb4f74649b23c053b308ce1152dce51239450baanthony work_image=CloneImage(image,0,0,MagickTrue,exception); 40289eb4f74649b23c053b308ce1152dce51239450baanthony if (work_image == (Image *) NULL) 40299eb4f74649b23c053b308ce1152dce51239450baanthony goto error_cleanup; 4030574cc26500992189f637cd1cdf93d0654e7df7aecristy if (SetImageStorageClass(work_image,DirectClass,exception) == MagickFalse) 4031574cc26500992189f637cd1cdf93d0654e7df7aecristy goto error_cleanup; 4032db60568e12574785101a4ae8d8da076227a0a889anthony /* work_image->type=image->type; ??? */ 40339eb4f74649b23c053b308ce1152dce51239450baanthony } 40349eb4f74649b23c053b308ce1152dce51239450baanthony 4035501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony /* APPLY THE MORPHOLOGICAL PRIMITIVE (curr -> work) */ 40369eb4f74649b23c053b308ce1152dce51239450baanthony count++; 4037e698a255629ba03cd125572de7b35b5e21c4ee5danthony changed = MorphologyPrimitive(curr_image, work_image, primitive, 4038f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy this_kernel, bias, exception); 403947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 404047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( verbose == MagickTrue ) { 404147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( kernel_loop > 1 ) 40425acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line from previous */ 40435acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) (void) FormatLocaleFile(stderr, 40441e604812fad85bb96f757a2393015ae3d061c39acristy "%s%s%s:%.20g.%.20g #%.20g => Changed %.20g", 4045042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy v_info,CommandOptionToMnemonic(MagickMorphologyOptions, 4046a8843c1f815ffad2568ec592d5b446cb1476aab5anthony primitive),(this_kernel == rflt_kernel ) ? "*" : "", 4047e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy (double) (method_loop+kernel_loop-1),(double) kernel_number, 4048e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy (double) count,(double) changed); 404947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 4050a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( changed < 0 ) 4051a8843c1f815ffad2568ec592d5b446cb1476aab5anthony goto error_cleanup; 4052a8843c1f815ffad2568ec592d5b446cb1476aab5anthony kernel_changed += changed; 4053a8843c1f815ffad2568ec592d5b446cb1476aab5anthony method_changed += changed; 4054a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 40559eb4f74649b23c053b308ce1152dce51239450baanthony /* prepare next loop */ 40569eb4f74649b23c053b308ce1152dce51239450baanthony { Image *tmp = work_image; /* swap images for iteration */ 40579eb4f74649b23c053b308ce1152dce51239450baanthony work_image = curr_image; 40589eb4f74649b23c053b308ce1152dce51239450baanthony curr_image = tmp; 40599eb4f74649b23c053b308ce1152dce51239450baanthony } 40609eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image == image ) 406147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = (Image *) NULL; /* replace input 'image' */ 40629eb4f74649b23c053b308ce1152dce51239450baanthony 4063a8843c1f815ffad2568ec592d5b446cb1476aab5anthony } /* End Loop 4: Iterate the kernel with primitive */ 40647a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4065a8843c1f815ffad2568ec592d5b446cb1476aab5anthony if ( verbose == MagickTrue && kernel_changed != (size_t)changed ) 40665acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " Total %.20g",(double) kernel_changed); 406747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( verbose == MagickTrue && stage_loop < stage_limit ) 40685acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line before looping */ 40699eb4f74649b23c053b308ce1152dce51239450baanthony 407047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony#if 0 40715acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "--E-- image=0x%lx\n", (unsigned long)image); 40725acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " curr =0x%lx\n", (unsigned long)curr_image); 40735acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " work =0x%lx\n", (unsigned long)work_image); 40745acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " save =0x%lx\n", (unsigned long)save_image); 40755acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " union=0x%lx\n", (unsigned long)rslt_image); 407647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony#endif 40771b2bc0a7da432e6e1cc0480280402df213faa940anthony 407847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 3: Primative (staging) Loop for Coumpound Methods */ 40791b2bc0a7da432e6e1cc0480280402df213faa940anthony 408047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Final Post-processing for some Compound Methods 408147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** 408247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** The removal of any 'Sync' channel flag in the Image Compositon 408347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** below ensures the methematical compose method is applied in a 408447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** purely mathematical way, and only to the selected channels. 408547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** Turn off SVG composition 'alpha blending'. 408647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 408747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony switch( method ) { 408847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeOutMorphology: 408947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeInMorphology: 409047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case TopHatMorphology: 409147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case BottomHatMorphology: 40929eb4f74649b23c053b308ce1152dce51239450baanthony if ( verbose == MagickTrue ) 40935acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n%s: Difference with original image", 4094042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickMorphologyOptions, method) ); 4095f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy curr_image->sync=MagickFalse; 4096f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy (void) CompositeImage(curr_image,DifferenceCompositeOp,image,0,0); 409747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 409847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony case EdgeMorphology: 409947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( verbose == MagickTrue ) 41005acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n%s: Difference of Dilate and Erode", 4101042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickMorphologyOptions, method) ); 4102f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy curr_image->sync=MagickFalse; 4103f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy (void) CompositeImage(curr_image,DifferenceCompositeOp,save_image,0, 4104f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy 0); 410547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = DestroyImage(save_image); /* finished with save image */ 410647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 410747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony default: 410847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony break; 4109602ab9b30b644a78a4057da93d838a77391ec0acanthony } 41109eb4f74649b23c053b308ce1152dce51239450baanthony 411147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* multi-kernel handling: re-iterate, or compose results */ 411247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( kernel->next == (KernelInfo *) NULL ) 4113c3e48258f3253188894e783dcdfd03562f7ab2c5anthony rslt_image = curr_image; /* just return the resulting image */ 411447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else if ( rslt_compose == NoCompositeOp ) 4115c3e48258f3253188894e783dcdfd03562f7ab2c5anthony { if ( verbose == MagickTrue ) { 4116c3e48258f3253188894e783dcdfd03562f7ab2c5anthony if ( this_kernel->next != (KernelInfo *) NULL ) 41175acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (re-iterate)"); 4118c3e48258f3253188894e783dcdfd03562f7ab2c5anthony else 41195acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (done)"); 4120c3e48258f3253188894e783dcdfd03562f7ab2c5anthony } 4121c3e48258f3253188894e783dcdfd03562f7ab2c5anthony rslt_image = curr_image; /* return result, and re-iterate */ 41229eb4f74649b23c053b308ce1152dce51239450baanthony } 412347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else if ( rslt_image == (Image *) NULL) 412447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony { if ( verbose == MagickTrue ) 41255acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (save for compose)"); 412647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_image = curr_image; 412747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; /* continue with original image */ 41289eb4f74649b23c053b308ce1152dce51239450baanthony } 412947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony else 4130ea61f01656bb0f9074677452017cc559e54093faanthony { /* Add the new 'current' result to the composition 413147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** 413247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** The removal of any 'Sync' channel flag in the Image Compositon 413347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** below ensures the methematical compose method is applied in a 413447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony ** purely mathematical way, and only to the selected channels. 4135ea61f01656bb0f9074677452017cc559e54093faanthony ** IE: Turn off SVG composition 'alpha blending'. 413647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 413747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( verbose == MagickTrue ) 41385acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (compose \"%s\")", 4139042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) ); 4140f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy rslt_image->sync=MagickFalse; 4141f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy (void) CompositeImage(rslt_image, rslt_compose, curr_image, 0, 0); 41420bd8549b4c1659eb72b12eae65f948e0e6e43c4banthony curr_image = DestroyImage(curr_image); 414347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = (Image *) image; /* continue with original image */ 414447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } 414547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( verbose == MagickTrue ) 41465acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n"); 41474fd27e21043be809d66c8202e779255e5b660d2danthony 414847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* loop to the next kernel in a multi-kernel list */ 414947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony norm_kernel = norm_kernel->next; 415047f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rflt_kernel != (KernelInfo *) NULL ) 415147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rflt_kernel = rflt_kernel->next; 415247f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony kernel_number++; 415347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 2: Loop over each kernel */ 41549eb4f74649b23c053b308ce1152dce51239450baanthony 415547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony } /* End Loop 1: compound method interation */ 4156602ab9b30b644a78a4057da93d838a77391ec0acanthony 41579eb4f74649b23c053b308ce1152dce51239450baanthony goto exit_cleanup; 41581b2bc0a7da432e6e1cc0480280402df213faa940anthony 415947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony /* Yes goto's are bad, but it makes cleanup lot more efficient */ 41601b2bc0a7da432e6e1cc0480280402df213faa940anthonyerror_cleanup: 4161ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image == rslt_image ) 4162ea61f01656bb0f9074677452017cc559e54093faanthony curr_image = (Image *) NULL; 416347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( rslt_image != (Image *) NULL ) 416447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony rslt_image = DestroyImage(rslt_image); 41651b2bc0a7da432e6e1cc0480280402df213faa940anthonyexit_cleanup: 4166ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image == rslt_image || curr_image == image ) 4167ea61f01656bb0f9074677452017cc559e54093faanthony curr_image = (Image *) NULL; 4168ea61f01656bb0f9074677452017cc559e54093faanthony if ( curr_image != (Image *) NULL ) 416947f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony curr_image = DestroyImage(curr_image); 41709eb4f74649b23c053b308ce1152dce51239450baanthony if ( work_image != (Image *) NULL ) 417147f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony work_image = DestroyImage(work_image); 41729eb4f74649b23c053b308ce1152dce51239450baanthony if ( save_image != (Image *) NULL ) 417347f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony save_image = DestroyImage(save_image); 417447f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony if ( reflected_kernel != (KernelInfo *) NULL ) 417547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony reflected_kernel = DestroyKernelInfo(reflected_kernel); 417647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony return(rslt_image); 41779eb4f74649b23c053b308ce1152dce51239450baanthony} 4178a8843c1f815ffad2568ec592d5b446cb1476aab5anthony 41799eb4f74649b23c053b308ce1152dce51239450baanthony 41809eb4f74649b23c053b308ce1152dce51239450baanthony/* 41819eb4f74649b23c053b308ce1152dce51239450baanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 41829eb4f74649b23c053b308ce1152dce51239450baanthony% % 41839eb4f74649b23c053b308ce1152dce51239450baanthony% % 41849eb4f74649b23c053b308ce1152dce51239450baanthony% % 4185f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% M o r p h o l o g y I m a g e % 41869eb4f74649b23c053b308ce1152dce51239450baanthony% % 41879eb4f74649b23c053b308ce1152dce51239450baanthony% % 41889eb4f74649b23c053b308ce1152dce51239450baanthony% % 41899eb4f74649b23c053b308ce1152dce51239450baanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 41909eb4f74649b23c053b308ce1152dce51239450baanthony% 4191f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% MorphologyImage() applies a user supplied kernel to the image 41929eb4f74649b23c053b308ce1152dce51239450baanthony% according to the given mophology method. 41939eb4f74649b23c053b308ce1152dce51239450baanthony% 41949eb4f74649b23c053b308ce1152dce51239450baanthony% This function applies any and all user defined settings before calling 41959eb4f74649b23c053b308ce1152dce51239450baanthony% the above internal function MorphologyApply(). 41969eb4f74649b23c053b308ce1152dce51239450baanthony% 41979eb4f74649b23c053b308ce1152dce51239450baanthony% User defined settings include... 419846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% * Output Bias for Convolution and correlation ("-bias") 419946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% * Kernel Scale/normalize settings ("-set 'option:convolve:scale'") 420046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This can also includes the addition of a scaled unity kernel. 420146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% * Show Kernel being applied ("-set option:showkernel 1") 42029eb4f74649b23c053b308ce1152dce51239450baanthony% 42039eb4f74649b23c053b308ce1152dce51239450baanthony% The format of the MorphologyImage method is: 42049eb4f74649b23c053b308ce1152dce51239450baanthony% 42059eb4f74649b23c053b308ce1152dce51239450baanthony% Image *MorphologyImage(const Image *image,MorphologyMethod method, 4206bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% const ssize_t iterations,KernelInfo *kernel,ExceptionInfo *exception) 42079eb4f74649b23c053b308ce1152dce51239450baanthony% 4208f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy% Image *MorphologyImage(const Image *image, const ChannelType 4209bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% channel,MorphologyMethod method,const ssize_t iterations, 42109eb4f74649b23c053b308ce1152dce51239450baanthony% KernelInfo *kernel,ExceptionInfo *exception) 42119eb4f74649b23c053b308ce1152dce51239450baanthony% 42129eb4f74649b23c053b308ce1152dce51239450baanthony% A description of each parameter follows: 42139eb4f74649b23c053b308ce1152dce51239450baanthony% 42149eb4f74649b23c053b308ce1152dce51239450baanthony% o image: the image. 42159eb4f74649b23c053b308ce1152dce51239450baanthony% 42169eb4f74649b23c053b308ce1152dce51239450baanthony% o method: the morphology method to be applied. 42179eb4f74649b23c053b308ce1152dce51239450baanthony% 42189eb4f74649b23c053b308ce1152dce51239450baanthony% o iterations: apply the operation this many times (or no change). 42199eb4f74649b23c053b308ce1152dce51239450baanthony% A value of -1 means loop until no change found. 42209eb4f74649b23c053b308ce1152dce51239450baanthony% How this is applied may depend on the morphology method. 42219eb4f74649b23c053b308ce1152dce51239450baanthony% Typically this is a value of 1. 42229eb4f74649b23c053b308ce1152dce51239450baanthony% 42239eb4f74649b23c053b308ce1152dce51239450baanthony% o kernel: An array of double representing the morphology kernel. 42249eb4f74649b23c053b308ce1152dce51239450baanthony% Warning: kernel may be normalized for the Convolve method. 42259eb4f74649b23c053b308ce1152dce51239450baanthony% 42269eb4f74649b23c053b308ce1152dce51239450baanthony% o exception: return any errors or warnings in this structure. 42279eb4f74649b23c053b308ce1152dce51239450baanthony% 42289eb4f74649b23c053b308ce1152dce51239450baanthony*/ 4229f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristyMagickExport Image *MorphologyImage(const Image *image, 4230f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const MorphologyMethod method,const ssize_t iterations, 4231f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy const KernelInfo *kernel,ExceptionInfo *exception) 42329eb4f74649b23c053b308ce1152dce51239450baanthony{ 42339eb4f74649b23c053b308ce1152dce51239450baanthony KernelInfo 42349eb4f74649b23c053b308ce1152dce51239450baanthony *curr_kernel; 42359eb4f74649b23c053b308ce1152dce51239450baanthony 423647f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony CompositeOperator 423747f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony compose; 423847f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony 42399eb4f74649b23c053b308ce1152dce51239450baanthony Image 42409eb4f74649b23c053b308ce1152dce51239450baanthony *morphology_image; 42419eb4f74649b23c053b308ce1152dce51239450baanthony 42429eb4f74649b23c053b308ce1152dce51239450baanthony 424346a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Apply Convolve/Correlate Normalization and Scaling Factors. 424446a369d839971ab627bdb31a93d8bd63e81b65a3anthony * This is done BEFORE the ShowKernelInfo() function is called so that 424546a369d839971ab627bdb31a93d8bd63e81b65a3anthony * users can see the results of the 'option:convolve:scale' option. 42469eb4f74649b23c053b308ce1152dce51239450baanthony */ 42479eb4f74649b23c053b308ce1152dce51239450baanthony curr_kernel = (KernelInfo *) kernel; 4248f71ca294b7a21e80549dab84941ab149f7cdb300anthony if ( method == ConvolveMorphology || method == CorrelateMorphology ) 42499eb4f74649b23c053b308ce1152dce51239450baanthony { 425028ad1d779b6ca95852e860514185a7a97e06af77anthony const char 425128ad1d779b6ca95852e860514185a7a97e06af77anthony *artifact; 42529eb4f74649b23c053b308ce1152dce51239450baanthony artifact = GetImageArtifact(image,"convolve:scale"); 4253e8d2f55369b0c848618327cd2e6f2291ec4e4b2canthony if ( artifact != (const char *)NULL ) { 42549eb4f74649b23c053b308ce1152dce51239450baanthony if ( curr_kernel == kernel ) 42559eb4f74649b23c053b308ce1152dce51239450baanthony curr_kernel = CloneKernelInfo(kernel); 42569eb4f74649b23c053b308ce1152dce51239450baanthony if (curr_kernel == (KernelInfo *) NULL) { 42579eb4f74649b23c053b308ce1152dce51239450baanthony curr_kernel=DestroyKernelInfo(curr_kernel); 42589eb4f74649b23c053b308ce1152dce51239450baanthony return((Image *) NULL); 42599eb4f74649b23c053b308ce1152dce51239450baanthony } 426046a369d839971ab627bdb31a93d8bd63e81b65a3anthony ScaleGeometryKernelInfo(curr_kernel, artifact); 42619eb4f74649b23c053b308ce1152dce51239450baanthony } 42629eb4f74649b23c053b308ce1152dce51239450baanthony } 42639eb4f74649b23c053b308ce1152dce51239450baanthony 42649eb4f74649b23c053b308ce1152dce51239450baanthony /* display the (normalized) kernel via stderr */ 426528ad1d779b6ca95852e860514185a7a97e06af77anthony if ( IsMagickTrue(GetImageArtifact(image,"showkernel")) 426628ad1d779b6ca95852e860514185a7a97e06af77anthony || IsMagickTrue(GetImageArtifact(image,"convolve:showkernel")) 426728ad1d779b6ca95852e860514185a7a97e06af77anthony || IsMagickTrue(GetImageArtifact(image,"morphology:showkernel")) ) 42689eb4f74649b23c053b308ce1152dce51239450baanthony ShowKernelInfo(curr_kernel); 42699eb4f74649b23c053b308ce1152dce51239450baanthony 42703206678d008425bc56dd2dbad002f2bb26299dc2anthony /* Override the default handling of multi-kernel morphology results 42713206678d008425bc56dd2dbad002f2bb26299dc2anthony * If 'Undefined' use the default method 42723206678d008425bc56dd2dbad002f2bb26299dc2anthony * If 'None' (default for 'Convolve') re-iterate previous result 42733206678d008425bc56dd2dbad002f2bb26299dc2anthony * Otherwise merge resulting images using compose method given. 42743206678d008425bc56dd2dbad002f2bb26299dc2anthony * Default for 'HitAndMiss' is 'Lighten'. 427547f5d0605b372bda1dc04e401c6ac8cfc4a89dadanthony */ 427628ad1d779b6ca95852e860514185a7a97e06af77anthony { const char 427728ad1d779b6ca95852e860514185a7a97e06af77anthony *artifact; 427828ad1d779b6ca95852e860514185a7a97e06af77anthony artifact = GetImageArtifact(image,"morphology:compose"); 427928ad1d779b6ca95852e860514185a7a97e06af77anthony compose = UndefinedCompositeOp; /* use default for method */ 428028ad1d779b6ca95852e860514185a7a97e06af77anthony if ( artifact != (const char *) NULL) 428170b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions, 428270b5ea135e0cb4ed3c564fab9a15a7b1b53f1d9bcristy MagickFalse,artifact); 428328ad1d779b6ca95852e860514185a7a97e06af77anthony } 42849eb4f74649b23c053b308ce1152dce51239450baanthony /* Apply the Morphology */ 4285f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy morphology_image = MorphologyApply(image, method, iterations, 4286f4ad9df69835f9ed5c687a9f93e8a53e23a3258fcristy curr_kernel, compose, image->bias, exception); 42879eb4f74649b23c053b308ce1152dce51239450baanthony 42889eb4f74649b23c053b308ce1152dce51239450baanthony /* Cleanup and Exit */ 42899eb4f74649b23c053b308ce1152dce51239450baanthony if ( curr_kernel != kernel ) 42901b2bc0a7da432e6e1cc0480280402df213faa940anthony curr_kernel=DestroyKernelInfo(curr_kernel); 42919eb4f74649b23c053b308ce1152dce51239450baanthony return(morphology_image); 42929eb4f74649b23c053b308ce1152dce51239450baanthony} 429383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 429483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony/* 429583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 429683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 429783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 429883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 42994fd27e21043be809d66c8202e779255e5b660d2danthony+ R o t a t e K e r n e l I n f o % 430083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 430183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 430283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 430383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 430483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 430546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% RotateKernelInfo() rotates the kernel by the angle given. 430646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 430746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% Currently it is restricted to 90 degree angles, of either 1D kernels 430846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% or square kernels. And 'circular' rotations of 45 degrees for 3x3 kernels. 430946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% It will ignore usless rotations for specific 'named' built-in kernels. 431083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 43114fd27e21043be809d66c8202e779255e5b660d2danthony% The format of the RotateKernelInfo method is: 431283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 43134fd27e21043be809d66c8202e779255e5b660d2danthony% void RotateKernelInfo(KernelInfo *kernel, double angle) 431483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 431583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A description of each parameter follows: 431683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 431783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o kernel: the Morphology/Convolution kernel 431883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 431983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o angle: angle to rotate in degrees 432083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 432146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% This function is currently internal to this module only, but can be exported 432246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% to other modules if needed. 432383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony*/ 43244fd27e21043be809d66c8202e779255e5b660d2danthonystatic void RotateKernelInfo(KernelInfo *kernel, double angle) 432583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony{ 43261b2bc0a7da432e6e1cc0480280402df213faa940anthony /* angle the lower kernels first */ 43271b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 43281b2bc0a7da432e6e1cc0480280402df213faa940anthony RotateKernelInfo(kernel->next, angle); 43291b2bc0a7da432e6e1cc0480280402df213faa940anthony 433083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* WARNING: Currently assumes the kernel (rightly) is horizontally symetrical 433183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony ** 433283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony ** TODO: expand beyond simple 90 degree rotates, flips and flops 433383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony */ 433483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 433583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* Modulus the angle */ 433683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle = fmod(angle, 360.0); 433783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( angle < 0 ) 433883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle += 360.0; 433983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 43403c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 337.5 < angle || angle <= 22.5 ) 434143c4925e5305a26e48d68f7893e94f55d0831c39anthony return; /* Near zero angle - no change! - At least not at this time */ 434283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 43433dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony /* Handle special cases */ 434483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony switch (kernel->type) { 434583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These built-in kernels are cylindrical kernels, rotating is useless */ 434683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case GaussianKernel: 4347501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case DoGKernel: 4348501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony case LoGKernel: 434983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case DiskKernel: 43503dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case PeaksKernel: 43513dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case LaplacianKernel: 435283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case ChebyshevKernel: 4353bee715c4c0fd9efe6e21d8627ae8664434df7750anthony case ManhattanKernel: 435483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case EuclideanKernel: 435583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 435683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 435783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These may be rotatable at non-90 angles in the future */ 435883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* but simply rotating them in multiples of 90 degrees is useless */ 435983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case SquareKernel: 436083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case DiamondKernel: 436183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case PlusKernel: 43623dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony case CrossKernel: 436383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 436483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 436583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* These only allows a +/-90 degree rotation (by transpose) */ 436683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony /* A 180 degree rotation is useless */ 436783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony case BlurKernel: 436883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 135.0 < angle && angle <= 225.0 ) 436983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 437083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 225.0 < angle && angle <= 315.0 ) 437183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony angle -= 180; 437283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony break; 437383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 43743dd0f620e7a1d12f747ce167844cd7269bfa9f12anthony default: 437583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony break; 437683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 437757fe7a498c1302232dac8466864e84b12fad0807anthony /* Attempt rotations by 45 degrees -- 3x3 kernels only */ 43783c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 ) 43793c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { 43803c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( kernel->width == 3 && kernel->height == 3 ) 43813c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { /* Rotate a 3x3 square by 45 degree angle */ 43823c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony MagickRealType t = kernel->values[0]; 438343c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[0] = kernel->values[3]; 438443c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[3] = kernel->values[6]; 438543c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[6] = kernel->values[7]; 438643c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[7] = kernel->values[8]; 438743c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[8] = kernel->values[5]; 438843c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[5] = kernel->values[2]; 438943c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[2] = kernel->values[1]; 439043c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[1] = t; 43911d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* rotate non-centered origin */ 43921d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( kernel->x != 1 || kernel->y != 1 ) { 4393bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t x,y; 4394bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy x = (ssize_t) kernel->x-1; 4395bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy y = (ssize_t) kernel->y-1; 43961d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony if ( x == y ) x = 0; 43971d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( x == 0 ) x = -y; 43981d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( x == -y ) y = 0; 43991d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony else if ( y == 0 ) y = x; 4400ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->x = (ssize_t) x+1; 4401ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->y = (ssize_t) y+1; 44021d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 440343c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+315.0, 360.0); /* angle reduced 45 degrees */ 440443c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+45.0, 360.0); 44053c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 44063c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else 44073c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony perror("Unable to rotate non-3x3 kernel by 45 degrees"); 44083c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 44093c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( 45.0 < fmod(angle, 180.0) && fmod(angle,180.0) <= 135.0 ) 44103c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { 44113c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony if ( kernel->width == 1 || kernel->height == 1 ) 44124c08aed51c5899665ade97263692328eea4af106cristy { /* Do a transpose of a 1 dimensional kernel, 4413bfb635a40fc92bfcbdf36c018a9e64a9182d809canthony ** which results in a fast 90 degree rotation of some type. 44143c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony */ 4415bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t 44163c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony t; 4417bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy t = (ssize_t) kernel->width; 44183c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->width = kernel->height; 4419bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->height = (size_t) t; 44203c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony t = kernel->x; 44213c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->x = kernel->y; 44223c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony kernel->y = t; 442343c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( kernel->width == 1 ) { 442443c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+270.0, 360.0); /* angle reduced 90 degrees */ 442543c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+90.0, 360.0); 442643c4925e5305a26e48d68f7893e94f55d0831c39anthony } else { 442743c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+90.0, 360.0); /* angle increased 90 degrees */ 442843c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+270.0, 360.0); 442943c4925e5305a26e48d68f7893e94f55d0831c39anthony } 44303c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 44313c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else if ( kernel->width == kernel->height ) 44323c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony { /* Rotate a square array of values by 90 degrees */ 4433bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy { register size_t 44341d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony i,j,x,y; 44351d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony register MagickRealType 44361d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony *k,t; 44371d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k=kernel->values; 44381d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony for( i=0, x=kernel->width-1; i<=x; i++, x--) 44391d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony for( j=0, y=kernel->height-1; j<y; j++, y--) 44401d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony { t = k[i+j*kernel->width]; 44411d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[i+j*kernel->width] = k[j+x*kernel->width]; 44421d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[j+x*kernel->width] = k[x+y*kernel->width]; 44431d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[x+y*kernel->width] = k[y+i*kernel->width]; 44441d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony k[y+i*kernel->width] = t; 44451d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 44461d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 44471d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony /* rotate the origin - relative to center of array */ 4448bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy { register ssize_t x,y; 4449eaedf06777741da32408da72c1e512975c600c48cristy x = (ssize_t) (kernel->x*2-kernel->width+1); 4450eaedf06777741da32408da72c1e512975c600c48cristy y = (ssize_t) (kernel->y*2-kernel->height+1); 4451ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->x = (ssize_t) ( -y +(ssize_t) kernel->width-1)/2; 4452ecd0ab5350482e4a2ea003705e3e0b2120b66384cristy kernel->y = (ssize_t) ( +x +(ssize_t) kernel->height-1)/2; 44531d45eb9d30cfb0cb4a15d3c2d0fcfe6d72a53664anthony } 445443c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle+270.0, 360.0); /* angle reduced 90 degrees */ 445543c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+90.0, 360.0); 44563c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 44573c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony else 44583c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony perror("Unable to rotate a non-square, non-linear kernel 90 degrees"); 44593c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony } 446083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony if ( 135.0 < angle && angle <= 225.0 ) 446183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony { 446243c4925e5305a26e48d68f7893e94f55d0831c39anthony /* For a 180 degree rotation - also know as a reflection 446343c4925e5305a26e48d68f7893e94f55d0831c39anthony * This is actually a very very common operation! 446443c4925e5305a26e48d68f7893e94f55d0831c39anthony * Basically all that is needed is a reversal of the kernel data! 446543c4925e5305a26e48d68f7893e94f55d0831c39anthony * And a reflection of the origon 446643c4925e5305a26e48d68f7893e94f55d0831c39anthony */ 4467bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 446883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony i,j; 446983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony register double 447083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony *k,t; 447183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 447283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony k=kernel->values; 447383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony for ( i=0, j=kernel->width*kernel->height-1; i<j; i++, j--) 447483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony t=k[i], k[i]=k[j], k[j]=t; 447583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 4476bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->x = (ssize_t) kernel->width - kernel->x - 1; 4477bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy kernel->y = (ssize_t) kernel->height - kernel->y - 1; 447843c4925e5305a26e48d68f7893e94f55d0831c39anthony angle = fmod(angle-180.0, 360.0); /* angle+180 degrees */ 447943c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->angle = fmod(kernel->angle+180.0, 360.0); 448083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 44813c10fc8b1dff7f2c7c0681e154c7cb7cdef2b835anthony /* At this point angle should at least between -45 (315) and +45 degrees 448283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony * In the future some form of non-orthogonal angled rotates could be 448383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony * performed here, posibily with a linear kernel restriction. 448483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony */ 448583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 448683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony return; 448783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony} 448883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony 448983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony/* 449083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 449183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 449283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 449383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 449446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% S c a l e G e o m e t r y K e r n e l I n f o % 449546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 449646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 449746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 449846a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 449946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 450046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% ScaleGeometryKernelInfo() takes a geometry argument string, typically 450146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% provided as a "-set option:convolve:scale {geometry}" user setting, 450246a369d839971ab627bdb31a93d8bd63e81b65a3anthony% and modifies the kernel according to the parsed arguments of that setting. 450346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 450446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The first argument (and any normalization flags) are passed to 450546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% ScaleKernelInfo() to scale/normalize the kernel. The second argument 450646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% is then passed to UnityAddKernelInfo() to add a scled unity kernel 450746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% into the scaled/normalized kernel. 450846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 4509ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% The format of the ScaleGeometryKernelInfo method is: 451046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 4511ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% void ScaleGeometryKernelInfo(KernelInfo *kernel, 4512ceff20ad7a403eeb4cfc034b38e157ce9601bc2ccristy% const double scaling_factor,const MagickStatusType normalize_flags) 451346a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 451446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% A description of each parameter follows: 451546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 451646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o kernel: the Morphology/Convolution kernel to modify 451746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 451846a369d839971ab627bdb31a93d8bd63e81b65a3anthony% o geometry: 451946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The geometry string to parse, typically from the user provided 452046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% "-set option:convolve:scale {geometry}" setting. 452146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% 452246a369d839971ab627bdb31a93d8bd63e81b65a3anthony*/ 452346a369d839971ab627bdb31a93d8bd63e81b65a3anthonyMagickExport void ScaleGeometryKernelInfo (KernelInfo *kernel, 452446a369d839971ab627bdb31a93d8bd63e81b65a3anthony const char *geometry) 452546a369d839971ab627bdb31a93d8bd63e81b65a3anthony{ 452646a369d839971ab627bdb31a93d8bd63e81b65a3anthony GeometryFlags 452746a369d839971ab627bdb31a93d8bd63e81b65a3anthony flags; 452846a369d839971ab627bdb31a93d8bd63e81b65a3anthony GeometryInfo 452946a369d839971ab627bdb31a93d8bd63e81b65a3anthony args; 453046a369d839971ab627bdb31a93d8bd63e81b65a3anthony 453146a369d839971ab627bdb31a93d8bd63e81b65a3anthony SetGeometryInfo(&args); 453246a369d839971ab627bdb31a93d8bd63e81b65a3anthony flags = (GeometryFlags) ParseGeometry(geometry, &args); 453346a369d839971ab627bdb31a93d8bd63e81b65a3anthony 453446a369d839971ab627bdb31a93d8bd63e81b65a3anthony#if 0 453546a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* For Debugging Geometry Input */ 45365acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", 453746a369d839971ab627bdb31a93d8bd63e81b65a3anthony flags, args.rho, args.sigma, args.xi, args.psi ); 453846a369d839971ab627bdb31a93d8bd63e81b65a3anthony#endif 453946a369d839971ab627bdb31a93d8bd63e81b65a3anthony 454046a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & PercentValue) != 0 ) /* Handle Percentage flag*/ 454146a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.rho *= 0.01, args.sigma *= 0.01; 454246a369d839971ab627bdb31a93d8bd63e81b65a3anthony 454346a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & RhoValue) == 0 ) /* Set Defaults for missing args */ 454446a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.rho = 1.0; 454546a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & SigmaValue) == 0 ) 454646a369d839971ab627bdb31a93d8bd63e81b65a3anthony args.sigma = 0.0; 454746a369d839971ab627bdb31a93d8bd63e81b65a3anthony 454846a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Scale/Normalize the input kernel */ 454946a369d839971ab627bdb31a93d8bd63e81b65a3anthony ScaleKernelInfo(kernel, args.rho, flags); 455046a369d839971ab627bdb31a93d8bd63e81b65a3anthony 455146a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Add Unity Kernel, for blending with original */ 455246a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( (flags & SigmaValue) != 0 ) 455346a369d839971ab627bdb31a93d8bd63e81b65a3anthony UnityAddKernelInfo(kernel, args.sigma); 455446a369d839971ab627bdb31a93d8bd63e81b65a3anthony 455546a369d839971ab627bdb31a93d8bd63e81b65a3anthony return; 455646a369d839971ab627bdb31a93d8bd63e81b65a3anthony} 455746a369d839971ab627bdb31a93d8bd63e81b65a3anthony/* 455846a369d839971ab627bdb31a93d8bd63e81b65a3anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 455946a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 456046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 456146a369d839971ab627bdb31a93d8bd63e81b65a3anthony% % 45626771f1e8987fa49f52d4176281a2e8524b8e31cbcristy% S c a l e K e r n e l I n f o % 4563cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4564cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4565cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4566cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4567cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 45681b2bc0a7da432e6e1cc0480280402df213faa940anthony% ScaleKernelInfo() scales the given kernel list by the given amount, with or 45691b2bc0a7da432e6e1cc0480280402df213faa940anthony% without normalization of the sum of the kernel values (as per given flags). 4570999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4571999bb2c20aa9d42875bb5adba44951988d4ae354anthony% By default (no flags given) the values within the kernel is scaled 45721b2bc0a7da432e6e1cc0480280402df213faa940anthony% directly using given scaling factor without change. 4573999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 457446a369d839971ab627bdb31a93d8bd63e81b65a3anthony% If either of the two 'normalize_flags' are given the kernel will first be 457546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% normalized and then further scaled by the scaling factor value given. 4576999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4577999bb2c20aa9d42875bb5adba44951988d4ae354anthony% Kernel normalization ('normalize_flags' given) is designed to ensure that 4578999bb2c20aa9d42875bb5adba44951988d4ae354anthony% any use of the kernel scaling factor with 'Convolve' or 'Correlate' 45791b2bc0a7da432e6e1cc0480280402df213faa940anthony% morphology methods will fall into -1.0 to +1.0 range. Note that for 45801b2bc0a7da432e6e1cc0480280402df213faa940anthony% non-HDRI versions of IM this may cause images to have any negative results 45811b2bc0a7da432e6e1cc0480280402df213faa940anthony% clipped, unless some 'bias' is used. 4582999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4583999bb2c20aa9d42875bb5adba44951988d4ae354anthony% More specifically. Kernels which only contain positive values (such as a 4584999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 'Gaussian' kernel) will be scaled so that those values sum to +1.0, 45851b2bc0a7da432e6e1cc0480280402df213faa940anthony% ensuring a 0.0 to +1.0 output range for non-HDRI images. 4586999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4587999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For Kernels that contain some negative values, (such as 'Sharpen' kernels) 4588999bb2c20aa9d42875bb5adba44951988d4ae354anthony% the kernel will be scaled by the absolute of the sum of kernel values, so 4589999bb2c20aa9d42875bb5adba44951988d4ae354anthony% that it will generally fall within the +/- 1.0 range. 4590cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4591999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For kernels whose values sum to zero, (such as 'Laplician' kernels) kernel 4592999bb2c20aa9d42875bb5adba44951988d4ae354anthony% will be scaled by just the sum of the postive values, so that its output 4593999bb2c20aa9d42875bb5adba44951988d4ae354anthony% range will again fall into the +/- 1.0 range. 4594cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4595999bb2c20aa9d42875bb5adba44951988d4ae354anthony% For special kernels designed for locating shapes using 'Correlate', (often 4596999bb2c20aa9d42875bb5adba44951988d4ae354anthony% only containing +1 and -1 values, representing foreground/brackground 4597999bb2c20aa9d42875bb5adba44951988d4ae354anthony% matching) a special normalization method is provided to scale the positive 45981e7f7bcae3c8dc9e7a4f8bfb1fbe5980ef15d145glennrp% values separately to those of the negative values, so the kernel will be 4599999bb2c20aa9d42875bb5adba44951988d4ae354anthony% forced to become a zero-sum kernel better suited to such searches. 4600999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 46011b2bc0a7da432e6e1cc0480280402df213faa940anthony% WARNING: Correct normalization of the kernel assumes that the '*_range' 4602999bb2c20aa9d42875bb5adba44951988d4ae354anthony% attributes within the kernel structure have been correctly set during the 4603999bb2c20aa9d42875bb5adba44951988d4ae354anthony% kernels creation. 4604999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4605999bb2c20aa9d42875bb5adba44951988d4ae354anthony% NOTE: The values used for 'normalize_flags' have been selected specifically 460646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% to match the use of geometry options, so that '!' means NormalizeValue, '^' 460746a369d839971ab627bdb31a93d8bd63e81b65a3anthony% means CorrelateNormalizeValue. All other GeometryFlags values are ignored. 4608cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 46094fd27e21043be809d66c8202e779255e5b660d2danthony% The format of the ScaleKernelInfo method is: 4610cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4611999bb2c20aa9d42875bb5adba44951988d4ae354anthony% void ScaleKernelInfo(KernelInfo *kernel, const double scaling_factor, 4612999bb2c20aa9d42875bb5adba44951988d4ae354anthony% const MagickStatusType normalize_flags ) 4613cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4614cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% A description of each parameter follows: 4615cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4616cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% o kernel: the Morphology/Convolution kernel 4617cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4618999bb2c20aa9d42875bb5adba44951988d4ae354anthony% o scaling_factor: 4619999bb2c20aa9d42875bb5adba44951988d4ae354anthony% multiply all values (after normalization) by this factor if not 4620999bb2c20aa9d42875bb5adba44951988d4ae354anthony% zero. If the kernel is normalized regardless of any flags. 4621999bb2c20aa9d42875bb5adba44951988d4ae354anthony% 4622999bb2c20aa9d42875bb5adba44951988d4ae354anthony% o normalize_flags: 4623999bb2c20aa9d42875bb5adba44951988d4ae354anthony% GeometryFlags defining normalization method to use. 4624999bb2c20aa9d42875bb5adba44951988d4ae354anthony% specifically: NormalizeValue, CorrelateNormalizeValue, 4625999bb2c20aa9d42875bb5adba44951988d4ae354anthony% and/or PercentValue 4626cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4627cc6c836da2a53b6023b716e4973090a6714dc3b0anthony*/ 46286771f1e8987fa49f52d4176281a2e8524b8e31cbcristyMagickExport void ScaleKernelInfo(KernelInfo *kernel, 46296771f1e8987fa49f52d4176281a2e8524b8e31cbcristy const double scaling_factor,const GeometryFlags normalize_flags) 4630cc6c836da2a53b6023b716e4973090a6714dc3b0anthony{ 4631bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 4632cc6c836da2a53b6023b716e4973090a6714dc3b0anthony i; 4633cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4634999bb2c20aa9d42875bb5adba44951988d4ae354anthony register double 4635999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale, 4636999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale; 4637999bb2c20aa9d42875bb5adba44951988d4ae354anthony 463846a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 46391b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 46401b2bc0a7da432e6e1cc0480280402df213faa940anthony ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags); 46411b2bc0a7da432e6e1cc0480280402df213faa940anthony 464246a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Normalization of Kernel */ 4643999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = 1.0; 4644999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( (normalize_flags&NormalizeValue) != 0 ) { 4645999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( fabs(kernel->positive_range + kernel->negative_range) > MagickEpsilon ) 4646f4e0031305baeb01c89cfd2842cbbec021883550anthony /* non-zero-summing kernel (generally positive) */ 4647999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = fabs(kernel->positive_range + kernel->negative_range); 4648cc6c836da2a53b6023b716e4973090a6714dc3b0anthony else 4649f4e0031305baeb01c89cfd2842cbbec021883550anthony /* zero-summing kernel */ 4650f4e0031305baeb01c89cfd2842cbbec021883550anthony pos_scale = kernel->positive_range; 4651999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 465246a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Force kernel into a normalized zero-summing kernel */ 4653999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) { 4654999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = ( fabs(kernel->positive_range) > MagickEpsilon ) 4655999bb2c20aa9d42875bb5adba44951988d4ae354anthony ? kernel->positive_range : 1.0; 4656999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale = ( fabs(kernel->negative_range) > MagickEpsilon ) 4657999bb2c20aa9d42875bb5adba44951988d4ae354anthony ? -kernel->negative_range : 1.0; 4658999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 4659999bb2c20aa9d42875bb5adba44951988d4ae354anthony else 4660999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale = pos_scale; 4661999bb2c20aa9d42875bb5adba44951988d4ae354anthony 4662999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* finialize scaling_factor for positive and negative components */ 4663999bb2c20aa9d42875bb5adba44951988d4ae354anthony pos_scale = scaling_factor/pos_scale; 4664999bb2c20aa9d42875bb5adba44951988d4ae354anthony neg_scale = scaling_factor/neg_scale; 4665cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4666bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++) 4667cc6c836da2a53b6023b716e4973090a6714dc3b0anthony if ( ! IsNan(kernel->values[i]) ) 4668999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale; 4669999bb2c20aa9d42875bb5adba44951988d4ae354anthony 4670999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* convolution output range */ 4671999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->positive_range *= pos_scale; 4672999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->negative_range *= neg_scale; 4673999bb2c20aa9d42875bb5adba44951988d4ae354anthony /* maximum and minimum values in kernel */ 4674999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale; 4675999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale; 4676999bb2c20aa9d42875bb5adba44951988d4ae354anthony 467746a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* swap kernel settings if user's scaling factor is negative */ 4678999bb2c20aa9d42875bb5adba44951988d4ae354anthony if ( scaling_factor < MagickEpsilon ) { 4679999bb2c20aa9d42875bb5adba44951988d4ae354anthony double t; 4680999bb2c20aa9d42875bb5adba44951988d4ae354anthony t = kernel->positive_range; 4681999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->positive_range = kernel->negative_range; 4682999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->negative_range = t; 4683999bb2c20aa9d42875bb5adba44951988d4ae354anthony t = kernel->maximum; 4684999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->maximum = kernel->minimum; 4685999bb2c20aa9d42875bb5adba44951988d4ae354anthony kernel->minimum = 1; 4686999bb2c20aa9d42875bb5adba44951988d4ae354anthony } 4687cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4688cc6c836da2a53b6023b716e4973090a6714dc3b0anthony return; 4689cc6c836da2a53b6023b716e4973090a6714dc3b0anthony} 4690cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4691cc6c836da2a53b6023b716e4973090a6714dc3b0anthony/* 4692cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4693cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4694cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4695cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 469646a369d839971ab627bdb31a93d8bd63e81b65a3anthony% S h o w K e r n e l I n f o % 469783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 469883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 469983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% % 470083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 470183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 47024fd27e21043be809d66c8202e779255e5b660d2danthony% ShowKernelInfo() outputs the details of the given kernel defination to 47034fd27e21043be809d66c8202e779255e5b660d2danthony% standard error, generally due to a users 'showkernel' option request. 470483ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 470583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% The format of the ShowKernel method is: 470683ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 470757fe7a498c1302232dac8466864e84b12fad0807anthony% void ShowKernelInfo(const KernelInfo *kernel) 470883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 470983ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% A description of each parameter follows: 471083ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 471183ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% o kernel: the Morphology/Convolution kernel 471283ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony% 471383ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony*/ 471457fe7a498c1302232dac8466864e84b12fad0807anthonyMagickExport void ShowKernelInfo(const KernelInfo *kernel) 471583ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony{ 471657fe7a498c1302232dac8466864e84b12fad0807anthony const KernelInfo 47177a01dcf50ce12cb2a789bedff51e9345f022432eanthony *k; 47187a01dcf50ce12cb2a789bedff51e9345f022432eanthony 4719bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 47207a01dcf50ce12cb2a789bedff51e9345f022432eanthony c, i, u, v; 47217a01dcf50ce12cb2a789bedff51e9345f022432eanthony 47227a01dcf50ce12cb2a789bedff51e9345f022432eanthony for (c=0, k=kernel; k != (KernelInfo *) NULL; c++, k=k->next ) { 47237a01dcf50ce12cb2a789bedff51e9345f022432eanthony 47245acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Kernel"); 47257a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( kernel->next != (KernelInfo *) NULL ) 47265acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " #%lu", (unsigned long) c ); 47275acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " \"%s", 4728042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickKernelOptions, k->type) ); 472943c4925e5305a26e48d68f7893e94f55d0831c39anthony if ( fabs(k->angle) > MagickEpsilon ) 47305acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "@%lg", k->angle); 47315acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\" of size %lux%lu%+ld%+ld",(unsigned long) 47321e604812fad85bb96f757a2393015ae3d061c39acristy k->width,(unsigned long) k->height,(long) k->x,(long) k->y); 47335acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, 47347a01dcf50ce12cb2a789bedff51e9345f022432eanthony " with values from %.*lg to %.*lg\n", 47357a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->minimum, 47367a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->maximum); 47375acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Forming a output range from %.*lg to %.*lg", 47387a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->negative_range, 473946a369d839971ab627bdb31a93d8bd63e81b65a3anthony GetMagickPrecision(), k->positive_range); 474046a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( fabs(k->positive_range+k->negative_range) < MagickEpsilon ) 47415acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Zero-Summing)\n"); 474246a369d839971ab627bdb31a93d8bd63e81b65a3anthony else if ( fabs(k->positive_range+k->negative_range-1.0) < MagickEpsilon ) 47435acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Normalized)\n"); 474446a369d839971ab627bdb31a93d8bd63e81b65a3anthony else 47455acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (Sum %.*lg)\n", 474646a369d839971ab627bdb31a93d8bd63e81b65a3anthony GetMagickPrecision(), k->positive_range+k->negative_range); 474743c4925e5305a26e48d68f7893e94f55d0831c39anthony for (i=v=0; v < k->height; v++) { 47485acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%2lu:", (unsigned long) v ); 474943c4925e5305a26e48d68f7893e94f55d0831c39anthony for (u=0; u < k->width; u++, i++) 47507a01dcf50ce12cb2a789bedff51e9345f022432eanthony if ( IsNan(k->values[i]) ) 47515acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr," %*s", GetMagickPrecision()+3, "nan"); 47527a01dcf50ce12cb2a789bedff51e9345f022432eanthony else 47535acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr," %*.*lg", GetMagickPrecision()+3, 47547a01dcf50ce12cb2a789bedff51e9345f022432eanthony GetMagickPrecision(), k->values[i]); 47555acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr,"\n"); 47567a01dcf50ce12cb2a789bedff51e9345f022432eanthony } 475783ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony } 475883ba99b334176f4c6f9c8ab3ce3ae74d54f55208anthony} 4759cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4760cc6c836da2a53b6023b716e4973090a6714dc3b0anthony/* 4761cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4762cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4763cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4764cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 476543c4925e5305a26e48d68f7893e94f55d0831c39anthony% U n i t y A d d K e r n a l I n f o % 476643c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 476743c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 476843c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 476943c4925e5305a26e48d68f7893e94f55d0831c39anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 477043c4925e5305a26e48d68f7893e94f55d0831c39anthony% 477143c4925e5305a26e48d68f7893e94f55d0831c39anthony% UnityAddKernelInfo() Adds a given amount of the 'Unity' Convolution Kernel 477243c4925e5305a26e48d68f7893e94f55d0831c39anthony% to the given pre-scaled and normalized Kernel. This in effect adds that 477343c4925e5305a26e48d68f7893e94f55d0831c39anthony% amount of the original image into the resulting convolution kernel. This 477443c4925e5305a26e48d68f7893e94f55d0831c39anthony% value is usually provided by the user as a percentage value in the 477543c4925e5305a26e48d68f7893e94f55d0831c39anthony% 'convolve:scale' setting. 477643c4925e5305a26e48d68f7893e94f55d0831c39anthony% 4777501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% The resulting effect is to convert the defined kernels into blended 4778501c2f94b2d119d9e9d9e7d2dd4c5713726c500danthony% soft-blurs, unsharp kernels or into sharpening kernels. 477943c4925e5305a26e48d68f7893e94f55d0831c39anthony% 478046a369d839971ab627bdb31a93d8bd63e81b65a3anthony% The format of the UnityAdditionKernelInfo method is: 478143c4925e5305a26e48d68f7893e94f55d0831c39anthony% 478243c4925e5305a26e48d68f7893e94f55d0831c39anthony% void UnityAdditionKernelInfo(KernelInfo *kernel, const double scale ) 478343c4925e5305a26e48d68f7893e94f55d0831c39anthony% 478443c4925e5305a26e48d68f7893e94f55d0831c39anthony% A description of each parameter follows: 478543c4925e5305a26e48d68f7893e94f55d0831c39anthony% 478643c4925e5305a26e48d68f7893e94f55d0831c39anthony% o kernel: the Morphology/Convolution kernel 478743c4925e5305a26e48d68f7893e94f55d0831c39anthony% 478843c4925e5305a26e48d68f7893e94f55d0831c39anthony% o scale: 478943c4925e5305a26e48d68f7893e94f55d0831c39anthony% scaling factor for the unity kernel to be added to 479043c4925e5305a26e48d68f7893e94f55d0831c39anthony% the given kernel. 479143c4925e5305a26e48d68f7893e94f55d0831c39anthony% 479243c4925e5305a26e48d68f7893e94f55d0831c39anthony*/ 479343c4925e5305a26e48d68f7893e94f55d0831c39anthonyMagickExport void UnityAddKernelInfo(KernelInfo *kernel, 479443c4925e5305a26e48d68f7893e94f55d0831c39anthony const double scale) 479543c4925e5305a26e48d68f7893e94f55d0831c39anthony{ 479646a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 479746a369d839971ab627bdb31a93d8bd63e81b65a3anthony if ( kernel->next != (KernelInfo *) NULL) 479846a369d839971ab627bdb31a93d8bd63e81b65a3anthony UnityAddKernelInfo(kernel->next, scale); 479943c4925e5305a26e48d68f7893e94f55d0831c39anthony 480046a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* Add the scaled unity kernel to the existing kernel */ 480143c4925e5305a26e48d68f7893e94f55d0831c39anthony kernel->values[kernel->x+kernel->y*kernel->width] += scale; 480246a369d839971ab627bdb31a93d8bd63e81b65a3anthony CalcKernelMetaData(kernel); /* recalculate the meta-data */ 480343c4925e5305a26e48d68f7893e94f55d0831c39anthony 480443c4925e5305a26e48d68f7893e94f55d0831c39anthony return; 480543c4925e5305a26e48d68f7893e94f55d0831c39anthony} 480643c4925e5305a26e48d68f7893e94f55d0831c39anthony 480743c4925e5305a26e48d68f7893e94f55d0831c39anthony/* 480843c4925e5305a26e48d68f7893e94f55d0831c39anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 480943c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 481043c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 481143c4925e5305a26e48d68f7893e94f55d0831c39anthony% % 481243c4925e5305a26e48d68f7893e94f55d0831c39anthony% Z e r o K e r n e l N a n s % 4813cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4814cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4815cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% % 4816cc6c836da2a53b6023b716e4973090a6714dc3b0anthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4817cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4818cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% ZeroKernelNans() replaces any special 'nan' value that may be present in 4819cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% the kernel with a zero value. This is typically done when the kernel will 4820cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% be used in special hardware (GPU) convolution processors, to simply 4821cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% matters. 4822cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4823cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% The format of the ZeroKernelNans method is: 4824cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 482546a369d839971ab627bdb31a93d8bd63e81b65a3anthony% void ZeroKernelNans (KernelInfo *kernel) 4826cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4827cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% A description of each parameter follows: 4828cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4829cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% o kernel: the Morphology/Convolution kernel 4830cc6c836da2a53b6023b716e4973090a6714dc3b0anthony% 4831cc6c836da2a53b6023b716e4973090a6714dc3b0anthony*/ 4832cf592636b16d028b14c5fa9dffdc3a94eae7c2f3cristyMagickPrivate void ZeroKernelNans(KernelInfo *kernel) 4833cc6c836da2a53b6023b716e4973090a6714dc3b0anthony{ 4834bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 4835cc6c836da2a53b6023b716e4973090a6714dc3b0anthony i; 4836cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 483746a369d839971ab627bdb31a93d8bd63e81b65a3anthony /* do the other kernels in a multi-kernel list first */ 48381b2bc0a7da432e6e1cc0480280402df213faa940anthony if ( kernel->next != (KernelInfo *) NULL) 48391b2bc0a7da432e6e1cc0480280402df213faa940anthony ZeroKernelNans(kernel->next); 48401b2bc0a7da432e6e1cc0480280402df213faa940anthony 484143c4925e5305a26e48d68f7893e94f55d0831c39anthony for (i=0; i < (kernel->width*kernel->height); i++) 4842cc6c836da2a53b6023b716e4973090a6714dc3b0anthony if ( IsNan(kernel->values[i]) ) 4843cc6c836da2a53b6023b716e4973090a6714dc3b0anthony kernel->values[i] = 0.0; 4844cc6c836da2a53b6023b716e4973090a6714dc3b0anthony 4845cc6c836da2a53b6023b716e4973090a6714dc3b0anthony return; 4846cc6c836da2a53b6023b716e4973090a6714dc3b0anthony} 4847