13e2860cb0796fe77659325ec3d540d8766d54f49cristy/* 23e2860cb0796fe77659325ec3d540d8766d54f49cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 33e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 43e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 53e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 63e2860cb0796fe77659325ec3d540d8766d54f49cristy% FFFFF EEEEE AAA TTTTT U U RRRR EEEEE % 73e2860cb0796fe77659325ec3d540d8766d54f49cristy% F E A A T U U R R E % 83e2860cb0796fe77659325ec3d540d8766d54f49cristy% FFF EEE AAAAA T U U RRRR EEE % 93e2860cb0796fe77659325ec3d540d8766d54f49cristy% F E A A T U U R R E % 103e2860cb0796fe77659325ec3d540d8766d54f49cristy% F EEEEE A A T UUU R R EEEEE % 113e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 123e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 133e2860cb0796fe77659325ec3d540d8766d54f49cristy% MagickCore Image Feature Methods % 143e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 153e2860cb0796fe77659325ec3d540d8766d54f49cristy% Software Design % 16de984cdc3631106b1cbbb8d3972b76a0fc27e8e8cristy% Cristy % 173e2860cb0796fe77659325ec3d540d8766d54f49cristy% July 1992 % 183e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 193e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 207ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 213e2860cb0796fe77659325ec3d540d8766d54f49cristy% dedicated to making software imaging solutions freely available. % 223e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 233e2860cb0796fe77659325ec3d540d8766d54f49cristy% You may not use this file except in compliance with the License. You may % 243e2860cb0796fe77659325ec3d540d8766d54f49cristy% obtain a copy of the License at % 253e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 263e2860cb0796fe77659325ec3d540d8766d54f49cristy% http://www.imagemagick.org/script/license.php % 273e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 283e2860cb0796fe77659325ec3d540d8766d54f49cristy% Unless required by applicable law or agreed to in writing, software % 293e2860cb0796fe77659325ec3d540d8766d54f49cristy% distributed under the License is distributed on an "AS IS" BASIS, % 303e2860cb0796fe77659325ec3d540d8766d54f49cristy% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 313e2860cb0796fe77659325ec3d540d8766d54f49cristy% See the License for the specific language governing permissions and % 323e2860cb0796fe77659325ec3d540d8766d54f49cristy% limitations under the License. % 333e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 343e2860cb0796fe77659325ec3d540d8766d54f49cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 353e2860cb0796fe77659325ec3d540d8766d54f49cristy% 363e2860cb0796fe77659325ec3d540d8766d54f49cristy% 373e2860cb0796fe77659325ec3d540d8766d54f49cristy% 383e2860cb0796fe77659325ec3d540d8766d54f49cristy*/ 393e2860cb0796fe77659325ec3d540d8766d54f49cristy 403e2860cb0796fe77659325ec3d540d8766d54f49cristy/* 413e2860cb0796fe77659325ec3d540d8766d54f49cristy Include declarations. 423e2860cb0796fe77659325ec3d540d8766d54f49cristy*/ 434c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h" 444c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/animate.h" 450f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy#include "MagickCore/artifact.h" 464c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/blob.h" 474c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/blob-private.h" 484c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache.h" 494c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache-private.h" 504c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache-view.h" 5131e75937db91fd53e7deb9e3544646d0459f2196cristy#include "MagickCore/channel.h" 524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/client.h" 534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color.h" 544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color-private.h" 554c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/colorspace.h" 564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/colorspace-private.h" 574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/composite.h" 584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/composite-private.h" 594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/compress.h" 604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/constitute.h" 614c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/display.h" 624c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/draw.h" 634c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/enhance.h" 644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h" 654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h" 664c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/feature.h" 674c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/gem.h" 684c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/geometry.h" 694c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/list.h" 704c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h" 714c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/magic.h" 724c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/magick.h" 73c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy#include "MagickCore/matrix.h" 744c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h" 754c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/module.h" 764c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor.h" 774c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h" 78c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy#include "MagickCore/morphology-private.h" 794c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/option.h" 804c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/paint.h" 814c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h" 824c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/profile.h" 830f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy#include "MagickCore/property.h" 844c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantize.h" 854c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum-private.h" 864c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/random_.h" 87ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy#include "MagickCore/resource_.h" 884c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/segment.h" 894c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/semaphore.h" 904c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/signature-private.h" 914c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h" 924c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/thread-private.h" 934c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/timer.h" 944c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/utility.h" 954c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/version.h" 963e2860cb0796fe77659325ec3d540d8766d54f49cristy 973e2860cb0796fe77659325ec3d540d8766d54f49cristy/* 983e2860cb0796fe77659325ec3d540d8766d54f49cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 993e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 1003e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 1013e2860cb0796fe77659325ec3d540d8766d54f49cristy% % 102c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% C a n n y E d g e I m a g e % 103c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% % 104c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% % 105c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% % 106c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 107c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 108c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% CannyEdgeImage() uses a multi-stage algorithm to detect a wide range of 109c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% edges in images. 110c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 111233483c36e4f75e4337766b87cae1ab13d8b92a8cristy% The format of the CannyEdgeImage method is: 112c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 113c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% Image *CannyEdgeImage(const Image *image,const double radius, 114c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% const double sigma,const double lower_percent, 115c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% const double upper_percent,ExceptionInfo *exception) 116c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 117c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% A description of each parameter follows: 118c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 119c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% o image: the image. 120c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 121c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% o radius: the radius of the gaussian smoothing filter. 122c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 123c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% o sigma: the sigma of the gaussian smoothing filter. 124c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 125c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% o lower_precent: percentage of edge pixels in the lower threshold. 126c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 127c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% o upper_percent: percentage of edge pixels in the upper threshold. 128c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 129c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% o exception: return any errors or warnings in this structure. 130c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 131c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy*/ 132c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 133c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristytypedef struct _CannyInfo 134c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy{ 135c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy double 136c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy magnitude, 137c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy intensity; 138c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 139c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy int 140c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy orientation; 141c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 142c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy ssize_t 143c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy x, 144c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy y; 145c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy} CannyInfo; 146c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 147c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristystatic inline MagickBooleanType IsAuthenticPixel(const Image *image, 148c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy const ssize_t x,const ssize_t y) 149c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy{ 150c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if ((x < 0) || (x >= (ssize_t) image->columns)) 151c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse); 152c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if ((y < 0) || (y >= (ssize_t) image->rows)) 153c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse); 154c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickTrue); 155c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy} 156c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 157c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristystatic MagickBooleanType TraceEdges(Image *edge_image,CacheView *edge_view, 158c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy MatrixInfo *canny_cache,const ssize_t x,const ssize_t y, 159c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy const double lower_threshold,ExceptionInfo *exception) 160c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy{ 161c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy CannyInfo 162c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge, 163c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel; 164c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 165c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy MagickBooleanType 166c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status; 167c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 168c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy register Quantum 169c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy *q; 170c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 171c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy register ssize_t 172c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy i; 173c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 174c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy q=GetCacheViewAuthenticPixels(edge_view,x,y,1,1,exception); 175c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (q == (Quantum *) NULL) 176c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse); 177c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy *q=QuantumRange; 178c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=SyncCacheViewAuthenticPixels(edge_view,exception); 179c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (status == MagickFalse) 180c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse);; 181c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (GetMatrixElement(canny_cache,0,0,&edge) == MagickFalse) 182c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse); 183c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge.x=x; 184c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge.y=y; 185c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (SetMatrixElement(canny_cache,0,0,&edge) == MagickFalse) 186c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse); 187c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (i=1; i != 0; ) 188c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 189c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy ssize_t 190c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy v; 191c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 192c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy i--; 193c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=GetMatrixElement(canny_cache,i,0,&edge); 194c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (status == MagickFalse) 195c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse); 196c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (v=(-1); v <= 1; v++) 197c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 198c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy ssize_t 199c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy u; 200c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 201c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (u=(-1); u <= 1; u++) 202c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 203c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if ((u == 0) && (v == 0)) 204c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy continue; 205c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (IsAuthenticPixel(edge_image,edge.x+u,edge.y+v) == MagickFalse) 206c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy continue; 207c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 208c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Not an edge if gradient value is below the lower threshold. 209c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 210c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy q=GetCacheViewAuthenticPixels(edge_view,edge.x+u,edge.y+v,1,1, 211c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy exception); 212c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (q == (Quantum *) NULL) 213c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse); 214c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=GetMatrixElement(canny_cache,edge.x+u,edge.y+v,&pixel); 215c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (status == MagickFalse) 216c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse); 217c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if ((GetPixelIntensity(edge_image,q) == 0.0) && 218c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (pixel.intensity >= lower_threshold)) 219c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 220c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy *q=QuantumRange; 221c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=SyncCacheViewAuthenticPixels(edge_view,exception); 222c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (status == MagickFalse) 223c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse); 224c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge.x+=u; 225c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge.y+=v; 226c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=SetMatrixElement(canny_cache,i,0,&edge); 227c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (status == MagickFalse) 228c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickFalse); 229c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy i++; 230c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 231c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 232c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 233c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 234c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(MagickTrue); 235c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy} 236c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 237c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristyMagickExport Image *CannyEdgeImage(const Image *image,const double radius, 238c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy const double sigma,const double lower_percent,const double upper_percent, 239c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy ExceptionInfo *exception) 240c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy{ 2418fbcf1ad6a1d07a92ef39435f679143697be4edacristy#define CannyEdgeImageTag "CannyEdge/Image" 2428fbcf1ad6a1d07a92ef39435f679143697be4edacristy 243c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy CacheView 244c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy *edge_view; 245c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 246c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy CannyInfo 247aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk element; 248c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 249c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy char 250151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy geometry[MagickPathExtent]; 251c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 252c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy double 253c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy lower_threshold, 254c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy max, 255c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy min, 256c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy upper_threshold; 257c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 258c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Image 259c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy *edge_image; 260c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 261c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy KernelInfo 262c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy *kernel_info; 263c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 264c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy MagickBooleanType 265c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status; 266c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 2678fbcf1ad6a1d07a92ef39435f679143697be4edacristy MagickOffsetType 2688fbcf1ad6a1d07a92ef39435f679143697be4edacristy progress; 2698fbcf1ad6a1d07a92ef39435f679143697be4edacristy 270c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy MatrixInfo 271c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy *canny_cache; 272c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 273c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy ssize_t 274c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy y; 275c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 276c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy assert(image != (const Image *) NULL); 277e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(image->signature == MagickCoreSignature); 278c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (image->debug != MagickFalse) 279c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 280c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy assert(exception != (ExceptionInfo *) NULL); 281e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(exception->signature == MagickCoreSignature); 282c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 283c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Filter out noise. 284c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 285151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy (void) FormatLocaleString(geometry,MagickPathExtent, 286c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy "blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma); 2872c57b74e160f9b605d74dec24081309f28b83899cristy kernel_info=AcquireKernelInfo(geometry,exception); 288c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (kernel_info == (KernelInfo *) NULL) 289c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); 29094190b79d7abf8261e3a1af37aa7a7f86757b2d6Dusan Veljko edge_image=ConvolveImage(image, kernel_info, exception); 291c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy kernel_info=DestroyKernelInfo(kernel_info); 292c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (edge_image == (Image *) NULL) 293c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return((Image *) NULL); 294c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (SetImageColorspace(edge_image,GRAYColorspace,exception) == MagickFalse) 295c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 296c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge_image=DestroyImage(edge_image); 297c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return((Image *) NULL); 298c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 29931e75937db91fd53e7deb9e3544646d0459f2196cristy (void) SetImageAlphaChannel(edge_image,OffAlphaChannel,exception); 300c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 301c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Find the intensity gradient of the image. 302c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 303c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy canny_cache=AcquireMatrixInfo(edge_image->columns,edge_image->rows, 304c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy sizeof(CannyInfo),exception); 305c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (canny_cache == (MatrixInfo *) NULL) 306c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 307c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge_image=DestroyImage(edge_image); 308c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return((Image *) NULL); 309c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 310c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=MagickTrue; 311c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge_view=AcquireVirtualCacheView(edge_image,exception); 312c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 313c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy #pragma omp parallel for schedule(static,4) shared(status) \ 314c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy magick_threads(edge_image,edge_image,edge_image->rows,1) 315c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy#endif 316c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (y=0; y < (ssize_t) edge_image->rows; y++) 317c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 318c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy register const Quantum 31905d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict p; 320c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 321c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy register ssize_t 322c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy x; 323c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 324c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (status == MagickFalse) 325c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy continue; 326c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy p=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns+1,2, 327c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy exception); 328c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (p == (const Quantum *) NULL) 329c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 330c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=MagickFalse; 331c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy continue; 332c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 333c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (x=0; x < (ssize_t) edge_image->columns; x++) 334c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 335c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy CannyInfo 336c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel; 337c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 338c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy double 339c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy dx, 340c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy dy; 341c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 342c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy register const Quantum 34305d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict kernel_pixels; 344c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 345c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy ssize_t 346c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy v; 347c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 348c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy static double 349c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Gx[2][2] = 350c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 351c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { -1.0, +1.0 }, 352c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { -1.0, +1.0 } 353c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy }, 354c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Gy[2][2] = 355c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 356c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { +1.0, +1.0 }, 357c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { -1.0, -1.0 } 358c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy }; 359c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 360c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) ResetMagickMemory(&pixel,0,sizeof(pixel)); 361c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy dx=0.0; 362c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy dy=0.0; 363c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy kernel_pixels=p; 364c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (v=0; v < 2; v++) 365c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 366c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy ssize_t 367c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy u; 368c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 369c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (u=0; u < 2; u++) 370c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 371c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy double 372c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy intensity; 373c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 374c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy intensity=GetPixelIntensity(edge_image,kernel_pixels+u); 375c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy dx+=0.5*Gx[v][u]*intensity; 376c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy dy+=0.5*Gy[v][u]*intensity; 377c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 378c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy kernel_pixels+=edge_image->columns+1; 379c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 380c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel.magnitude=hypot(dx,dy); 381c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel.orientation=0; 382c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (fabs(dx) > MagickEpsilon) 383c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 384c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy double 385c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy slope; 386c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 387c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy slope=dy/dx; 388c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (slope < 0.0) 389c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 390c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (slope < -2.41421356237) 391c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel.orientation=0; 392c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy else 393c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (slope < -0.414213562373) 394c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel.orientation=1; 395c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy else 396c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel.orientation=2; 397c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 398c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy else 399c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 400c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (slope > 2.41421356237) 401c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel.orientation=0; 402c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy else 403c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (slope > 0.414213562373) 404c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel.orientation=3; 405c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy else 406c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel.orientation=2; 407c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 408c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 409c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (SetMatrixElement(canny_cache,x,y,&pixel) == MagickFalse) 410c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy continue; 411c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy p+=GetPixelChannels(edge_image); 412c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 413c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 414c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge_view=DestroyCacheView(edge_view); 415c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 416c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Non-maxima suppression, remove pixels that are not considered to be part 417c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy of an edge. 418c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 4198fbcf1ad6a1d07a92ef39435f679143697be4edacristy progress=0; 420aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk (void) GetMatrixElement(canny_cache,0,0,&element); 421aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk max=element.intensity; 422aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk min=element.intensity; 423c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge_view=AcquireAuthenticCacheView(edge_image,exception); 424c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 425c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy #pragma omp parallel for schedule(static,4) shared(status) \ 426c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy magick_threads(edge_image,edge_image,edge_image->rows,1) 427c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy#endif 428c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (y=0; y < (ssize_t) edge_image->rows; y++) 429c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 430c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy register Quantum 43105d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict q; 432c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 433c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy register ssize_t 434c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy x; 435c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 436c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (status == MagickFalse) 437c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy continue; 438c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy q=GetCacheViewAuthenticPixels(edge_view,0,y,edge_image->columns,1, 439c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy exception); 440c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (q == (Quantum *) NULL) 441c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 442c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=MagickFalse; 443c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy continue; 444c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 445c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (x=0; x < (ssize_t) edge_image->columns; x++) 446c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 447c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy CannyInfo 448c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy alpha_pixel, 449c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy beta_pixel, 450c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel; 451c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 452c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) GetMatrixElement(canny_cache,x,y,&pixel); 453c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy switch (pixel.orientation) 454c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 455c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy case 0: 456b6ecf44155ec6e79fac7d9c51ed5f56962f6eda4dirk default: 457c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 458c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 459c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 0 degrees, north and south. 460c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 461c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) GetMatrixElement(canny_cache,x,y-1,&alpha_pixel); 462c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) GetMatrixElement(canny_cache,x,y+1,&beta_pixel); 463c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy break; 464c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 465c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy case 1: 466c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 467c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 468c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 45 degrees, northwest and southeast. 469c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 470c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) GetMatrixElement(canny_cache,x-1,y-1,&alpha_pixel); 471c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) GetMatrixElement(canny_cache,x+1,y+1,&beta_pixel); 472c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy break; 473c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 474c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy case 2: 475c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 476c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 477c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 90 degrees, east and west. 478c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 479c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) GetMatrixElement(canny_cache,x-1,y,&alpha_pixel); 480c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) GetMatrixElement(canny_cache,x+1,y,&beta_pixel); 481c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy break; 482c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 483c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy case 3: 484c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 485c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 486c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 135 degrees, northeast and southwest. 487c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 488c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) GetMatrixElement(canny_cache,x+1,y-1,&beta_pixel); 489c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) GetMatrixElement(canny_cache,x-1,y+1,&alpha_pixel); 490c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy break; 491c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 492c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 493c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel.intensity=pixel.magnitude; 494c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if ((pixel.magnitude < alpha_pixel.magnitude) || 495c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (pixel.magnitude < beta_pixel.magnitude)) 496c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel.intensity=0; 497c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (void) SetMatrixElement(canny_cache,x,y,&pixel); 498c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 499c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy #pragma omp critical (MagickCore_CannyEdgeImage) 500c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy#endif 501c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 502c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (pixel.intensity < min) 503c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy min=pixel.intensity; 504c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (pixel.intensity > max) 505c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy max=pixel.intensity; 506c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 507c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy *q=0; 508c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy q+=GetPixelChannels(edge_image); 509c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 510c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (SyncCacheViewAuthenticPixels(edge_view,exception) == MagickFalse) 511c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=MagickFalse; 512c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 513c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge_view=DestroyCacheView(edge_view); 514c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 515c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Estimate hysteresis threshold. 516c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 517c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy lower_threshold=lower_percent*(max-min)+min; 518c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy upper_threshold=upper_percent*(max-min)+min; 519c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 520c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Hysteresis threshold. 521c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 522c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge_view=AcquireAuthenticCacheView(edge_image,exception); 523c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (y=0; y < (ssize_t) edge_image->rows; y++) 524c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 525c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy register ssize_t 526c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy x; 527c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 528c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (status == MagickFalse) 529c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy continue; 530c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy for (x=0; x < (ssize_t) edge_image->columns; x++) 531c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy { 532c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy CannyInfo 533c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy pixel; 534c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 535c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy register const Quantum 53605d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict p; 537c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 538c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 539c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Edge if pixel gradient higher than upper threshold. 540c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 541c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy p=GetCacheViewVirtualPixels(edge_view,x,y,1,1,exception); 542c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (p == (const Quantum *) NULL) 543c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy continue; 544c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=GetMatrixElement(canny_cache,x,y,&pixel); 545c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if (status == MagickFalse) 546c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy continue; 547c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy if ((GetPixelIntensity(edge_image,p) == 0.0) && 548c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy (pixel.intensity >= upper_threshold)) 549c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy status=TraceEdges(edge_image,edge_view,canny_cache,x,y,lower_threshold, 550c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy exception); 551c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 5528fbcf1ad6a1d07a92ef39435f679143697be4edacristy if (image->progress_monitor != (MagickProgressMonitor) NULL) 5538fbcf1ad6a1d07a92ef39435f679143697be4edacristy { 5548fbcf1ad6a1d07a92ef39435f679143697be4edacristy MagickBooleanType 5558fbcf1ad6a1d07a92ef39435f679143697be4edacristy proceed; 5568fbcf1ad6a1d07a92ef39435f679143697be4edacristy 5578fbcf1ad6a1d07a92ef39435f679143697be4edacristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 5588fbcf1ad6a1d07a92ef39435f679143697be4edacristy #pragma omp critical (MagickCore_CannyEdgeImage) 5598fbcf1ad6a1d07a92ef39435f679143697be4edacristy#endif 5608fbcf1ad6a1d07a92ef39435f679143697be4edacristy proceed=SetImageProgress(image,CannyEdgeImageTag,progress++, 5618fbcf1ad6a1d07a92ef39435f679143697be4edacristy image->rows); 5628fbcf1ad6a1d07a92ef39435f679143697be4edacristy if (proceed == MagickFalse) 5638fbcf1ad6a1d07a92ef39435f679143697be4edacristy status=MagickFalse; 5648fbcf1ad6a1d07a92ef39435f679143697be4edacristy } 565c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy } 566c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy edge_view=DestroyCacheView(edge_view); 567c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy /* 568c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy Free resources. 569c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy */ 570c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy canny_cache=DestroyMatrixInfo(canny_cache); 571c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy return(edge_image); 572c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy} 573c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy 574c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy/* 575c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 576c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% % 577c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% % 578c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% % 5792fc10e5aedab9144531a4668dc7526e3caf514e1cristy% G e t I m a g e F e a t u r e s % 580c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% % 581c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% % 582c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% % 583c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 584c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 5852fc10e5aedab9144531a4668dc7526e3caf514e1cristy% GetImageFeatures() returns features for each channel in the image in 5862fc10e5aedab9144531a4668dc7526e3caf514e1cristy% each of four directions (horizontal, vertical, left and right diagonals) 5872fc10e5aedab9144531a4668dc7526e3caf514e1cristy% for the specified distance. The features include the angular second 5882fc10e5aedab9144531a4668dc7526e3caf514e1cristy% moment, contrast, correlation, sum of squares: variance, inverse difference 5892fc10e5aedab9144531a4668dc7526e3caf514e1cristy% moment, sum average, sum varience, sum entropy, entropy, difference variance,% difference entropy, information measures of correlation 1, information 5902fc10e5aedab9144531a4668dc7526e3caf514e1cristy% measures of correlation 2, and maximum correlation coefficient. You can 5912fc10e5aedab9144531a4668dc7526e3caf514e1cristy% access the red channel contrast, for example, like this: 5922fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 5932fc10e5aedab9144531a4668dc7526e3caf514e1cristy% channel_features=GetImageFeatures(image,1,exception); 5942fc10e5aedab9144531a4668dc7526e3caf514e1cristy% contrast=channel_features[RedPixelChannel].contrast[0]; 5952fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 5962fc10e5aedab9144531a4668dc7526e3caf514e1cristy% Use MagickRelinquishMemory() to free the features buffer. 597c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 5982fc10e5aedab9144531a4668dc7526e3caf514e1cristy% The format of the GetImageFeatures method is: 599c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 6002fc10e5aedab9144531a4668dc7526e3caf514e1cristy% ChannelFeatures *GetImageFeatures(const Image *image, 6012fc10e5aedab9144531a4668dc7526e3caf514e1cristy% const size_t distance,ExceptionInfo *exception) 602c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 603c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% A description of each parameter follows: 604c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 605c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% o image: the image. 606c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 6072fc10e5aedab9144531a4668dc7526e3caf514e1cristy% o distance: the distance. 608c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 609c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% o exception: return any errors or warnings in this structure. 610c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy% 611c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy*/ 6120f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6132fc10e5aedab9144531a4668dc7526e3caf514e1cristystatic inline double MagickLog10(const double x) 614c1510626cf0bd77ecc1a9681bd1e0f599108d1b3cristy{ 6152fc10e5aedab9144531a4668dc7526e3caf514e1cristy#define Log10Epsilon (1.0e-11) 6160f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6172fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (fabs(x) < Log10Epsilon) 6182fc10e5aedab9144531a4668dc7526e3caf514e1cristy return(log10(Log10Epsilon)); 6192fc10e5aedab9144531a4668dc7526e3caf514e1cristy return(log10(fabs(x))); 6202fc10e5aedab9144531a4668dc7526e3caf514e1cristy} 6210f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6222fc10e5aedab9144531a4668dc7526e3caf514e1cristyMagickExport ChannelFeatures *GetImageFeatures(const Image *image, 6232fc10e5aedab9144531a4668dc7526e3caf514e1cristy const size_t distance,ExceptionInfo *exception) 6242fc10e5aedab9144531a4668dc7526e3caf514e1cristy{ 6252fc10e5aedab9144531a4668dc7526e3caf514e1cristy typedef struct _ChannelStatistics 6262fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 6272fc10e5aedab9144531a4668dc7526e3caf514e1cristy PixelInfo 6282fc10e5aedab9144531a4668dc7526e3caf514e1cristy direction[4]; /* horizontal, vertical, left and right diagonals */ 6292fc10e5aedab9144531a4668dc7526e3caf514e1cristy } ChannelStatistics; 6300f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6312fc10e5aedab9144531a4668dc7526e3caf514e1cristy CacheView 6322fc10e5aedab9144531a4668dc7526e3caf514e1cristy *image_view; 6330f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6342fc10e5aedab9144531a4668dc7526e3caf514e1cristy ChannelFeatures 6352fc10e5aedab9144531a4668dc7526e3caf514e1cristy *channel_features; 6360f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6372fc10e5aedab9144531a4668dc7526e3caf514e1cristy ChannelStatistics 6382fc10e5aedab9144531a4668dc7526e3caf514e1cristy **cooccurrence, 6392fc10e5aedab9144531a4668dc7526e3caf514e1cristy correlation, 6402fc10e5aedab9144531a4668dc7526e3caf514e1cristy *density_x, 6412fc10e5aedab9144531a4668dc7526e3caf514e1cristy *density_xy, 6422fc10e5aedab9144531a4668dc7526e3caf514e1cristy *density_y, 6432fc10e5aedab9144531a4668dc7526e3caf514e1cristy entropy_x, 6442fc10e5aedab9144531a4668dc7526e3caf514e1cristy entropy_xy, 6452fc10e5aedab9144531a4668dc7526e3caf514e1cristy entropy_xy1, 6462fc10e5aedab9144531a4668dc7526e3caf514e1cristy entropy_xy2, 6472fc10e5aedab9144531a4668dc7526e3caf514e1cristy entropy_y, 6482fc10e5aedab9144531a4668dc7526e3caf514e1cristy mean, 6492fc10e5aedab9144531a4668dc7526e3caf514e1cristy **Q, 6502fc10e5aedab9144531a4668dc7526e3caf514e1cristy *sum, 6512fc10e5aedab9144531a4668dc7526e3caf514e1cristy sum_squares, 6522fc10e5aedab9144531a4668dc7526e3caf514e1cristy variance; 6530f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6542fc10e5aedab9144531a4668dc7526e3caf514e1cristy PixelPacket 6552fc10e5aedab9144531a4668dc7526e3caf514e1cristy gray, 6562fc10e5aedab9144531a4668dc7526e3caf514e1cristy *grays; 6570f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6580f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy MagickBooleanType 6590f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy status; 6600f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6612fc10e5aedab9144531a4668dc7526e3caf514e1cristy register ssize_t 662aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk i, 663aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk r; 6640f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6652fc10e5aedab9144531a4668dc7526e3caf514e1cristy size_t 6662fc10e5aedab9144531a4668dc7526e3caf514e1cristy length; 6670f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6682fc10e5aedab9144531a4668dc7526e3caf514e1cristy unsigned int 6692fc10e5aedab9144531a4668dc7526e3caf514e1cristy number_grays; 6700f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 6712fc10e5aedab9144531a4668dc7526e3caf514e1cristy assert(image != (Image *) NULL); 672e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(image->signature == MagickCoreSignature); 6730f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy if (image->debug != MagickFalse) 6740f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 6752fc10e5aedab9144531a4668dc7526e3caf514e1cristy if ((image->columns < (distance+1)) || (image->rows < (distance+1))) 6762fc10e5aedab9144531a4668dc7526e3caf514e1cristy return((ChannelFeatures *) NULL); 67750debe5028731f7b7218c99c9c70e87ae5d43832Cristy length=MaxPixelChannels+1UL; 6782fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features=(ChannelFeatures *) AcquireQuantumMemory(length, 6792fc10e5aedab9144531a4668dc7526e3caf514e1cristy sizeof(*channel_features)); 6802fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (channel_features == (ChannelFeatures *) NULL) 6812fc10e5aedab9144531a4668dc7526e3caf514e1cristy ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 6822fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) ResetMagickMemory(channel_features,0,length* 6832fc10e5aedab9144531a4668dc7526e3caf514e1cristy sizeof(*channel_features)); 6840f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy /* 6852fc10e5aedab9144531a4668dc7526e3caf514e1cristy Form grays. 6860f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy */ 6872fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*grays)); 6882fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (grays == (PixelPacket *) NULL) 6892fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 6902fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features=(ChannelFeatures *) RelinquishMagickMemory( 6912fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features); 6922fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) ThrowMagickException(exception,GetMagickModule(), 6932fc10e5aedab9144531a4668dc7526e3caf514e1cristy ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 6942fc10e5aedab9144531a4668dc7526e3caf514e1cristy return(channel_features); 6952fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 6962fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (i=0; i <= (ssize_t) MaxMap; i++) 6972fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 6982fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[i].red=(~0U); 6992fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[i].green=(~0U); 7002fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[i].blue=(~0U); 7012fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[i].alpha=(~0U); 7022fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[i].black=(~0U); 7032fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 7040f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy status=MagickTrue; 7050f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy image_view=AcquireVirtualCacheView(image,exception); 7062fc10e5aedab9144531a4668dc7526e3caf514e1cristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 7072fc10e5aedab9144531a4668dc7526e3caf514e1cristy #pragma omp parallel for schedule(static,4) shared(status) \ 7082fc10e5aedab9144531a4668dc7526e3caf514e1cristy magick_threads(image,image,image->rows,1) 7092fc10e5aedab9144531a4668dc7526e3caf514e1cristy#endif 710aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk for (r=0; r < (ssize_t) image->rows; r++) 7110f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy { 7120f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy register const Quantum 71305d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict p; 7140f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 7150f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy register ssize_t 7160f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy x; 7170f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy 7180f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy if (status == MagickFalse) 7190f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy continue; 720aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk p=GetCacheViewVirtualPixels(image_view,0,r,image->columns,1,exception); 7212fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (p == (const Quantum *) NULL) 7220f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy { 7230f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy status=MagickFalse; 7240f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy continue; 7250f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy } 7260f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy for (x=0; x < (ssize_t) image->columns; x++) 7270f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy { 7282fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[ScaleQuantumToMap(GetPixelRed(image,p))].red= 7292fc10e5aedab9144531a4668dc7526e3caf514e1cristy ScaleQuantumToMap(GetPixelRed(image,p)); 7302fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[ScaleQuantumToMap(GetPixelGreen(image,p))].green= 7312fc10e5aedab9144531a4668dc7526e3caf514e1cristy ScaleQuantumToMap(GetPixelGreen(image,p)); 7322fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[ScaleQuantumToMap(GetPixelBlue(image,p))].blue= 7332fc10e5aedab9144531a4668dc7526e3caf514e1cristy ScaleQuantumToMap(GetPixelBlue(image,p)); 7342fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (image->colorspace == CMYKColorspace) 7352fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[ScaleQuantumToMap(GetPixelBlack(image,p))].black= 7362fc10e5aedab9144531a4668dc7526e3caf514e1cristy ScaleQuantumToMap(GetPixelBlack(image,p)); 73717f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 7382fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[ScaleQuantumToMap(GetPixelAlpha(image,p))].alpha= 7392fc10e5aedab9144531a4668dc7526e3caf514e1cristy ScaleQuantumToMap(GetPixelAlpha(image,p)); 7400f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy p+=GetPixelChannels(image); 7410f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy } 7420f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy } 7430f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy image_view=DestroyCacheView(image_view); 7440f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy if (status == MagickFalse) 7450f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy { 7462fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays=(PixelPacket *) RelinquishMagickMemory(grays); 7472fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features=(ChannelFeatures *) RelinquishMagickMemory( 7482fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features); 7492fc10e5aedab9144531a4668dc7526e3caf514e1cristy return(channel_features); 7500f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy } 7512fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) ResetMagickMemory(&gray,0,sizeof(gray)); 7522fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (i=0; i <= (ssize_t) MaxMap; i++) 7532fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 7542fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (grays[i].red != ~0U) 7552fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[gray.red++].red=grays[i].red; 7562fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (grays[i].green != ~0U) 7572fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[gray.green++].green=grays[i].green; 7582fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (grays[i].blue != ~0U) 7592fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[gray.blue++].blue=grays[i].blue; 7602fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (image->colorspace == CMYKColorspace) 7612fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (grays[i].black != ~0U) 7622fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[gray.black++].black=grays[i].black; 76317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 7642fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (grays[i].alpha != ~0U) 7652fc10e5aedab9144531a4668dc7526e3caf514e1cristy grays[gray.alpha++].alpha=grays[i].alpha; 7662fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 7670f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy /* 7682fc10e5aedab9144531a4668dc7526e3caf514e1cristy Allocate spatial dependence matrix. 7690f09a8ceb30556f22c8800ed7ff8faa260e4f6dccristy */ 7702fc10e5aedab9144531a4668dc7526e3caf514e1cristy number_grays=gray.red; 7712fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (gray.green > number_grays) 7722fc10e5aedab9144531a4668dc7526e3caf514e1cristy number_grays=gray.green; 7732fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (gray.blue > number_grays) 7742fc10e5aedab9144531a4668dc7526e3caf514e1cristy number_grays=gray.blue; 7752fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (image->colorspace == CMYKColorspace) 7762fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (gray.black > number_grays) 7772fc10e5aedab9144531a4668dc7526e3caf514e1cristy number_grays=gray.black; 77817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 7792fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (gray.alpha > number_grays) 7802fc10e5aedab9144531a4668dc7526e3caf514e1cristy number_grays=gray.alpha; 7812fc10e5aedab9144531a4668dc7526e3caf514e1cristy cooccurrence=(ChannelStatistics **) AcquireQuantumMemory(number_grays, 7822fc10e5aedab9144531a4668dc7526e3caf514e1cristy sizeof(*cooccurrence)); 7832fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_x=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1), 7842fc10e5aedab9144531a4668dc7526e3caf514e1cristy sizeof(*density_x)); 7852fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_xy=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1), 7862fc10e5aedab9144531a4668dc7526e3caf514e1cristy sizeof(*density_xy)); 7872fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_y=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1), 7882fc10e5aedab9144531a4668dc7526e3caf514e1cristy sizeof(*density_y)); 7892fc10e5aedab9144531a4668dc7526e3caf514e1cristy Q=(ChannelStatistics **) AcquireQuantumMemory(number_grays,sizeof(*Q)); 7902fc10e5aedab9144531a4668dc7526e3caf514e1cristy sum=(ChannelStatistics *) AcquireQuantumMemory(number_grays,sizeof(*sum)); 7912fc10e5aedab9144531a4668dc7526e3caf514e1cristy if ((cooccurrence == (ChannelStatistics **) NULL) || 7922fc10e5aedab9144531a4668dc7526e3caf514e1cristy (density_x == (ChannelStatistics *) NULL) || 7932fc10e5aedab9144531a4668dc7526e3caf514e1cristy (density_xy == (ChannelStatistics *) NULL) || 7942fc10e5aedab9144531a4668dc7526e3caf514e1cristy (density_y == (ChannelStatistics *) NULL) || 7952fc10e5aedab9144531a4668dc7526e3caf514e1cristy (Q == (ChannelStatistics **) NULL) || 7962fc10e5aedab9144531a4668dc7526e3caf514e1cristy (sum == (ChannelStatistics *) NULL)) 797f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy { 798ffa10d0fe53ef0f0db63ee506c52695595976b99cristy if (Q != (ChannelStatistics **) NULL) 799ffa10d0fe53ef0f0db63ee506c52695595976b99cristy { 800bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) number_grays; i++) 801ffa10d0fe53ef0f0db63ee506c52695595976b99cristy Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]); 802ffa10d0fe53ef0f0db63ee506c52695595976b99cristy Q=(ChannelStatistics **) RelinquishMagickMemory(Q); 803ffa10d0fe53ef0f0db63ee506c52695595976b99cristy } 804ffa10d0fe53ef0f0db63ee506c52695595976b99cristy if (sum != (ChannelStatistics *) NULL) 805ffa10d0fe53ef0f0db63ee506c52695595976b99cristy sum=(ChannelStatistics *) RelinquishMagickMemory(sum); 806ffa10d0fe53ef0f0db63ee506c52695595976b99cristy if (density_y != (ChannelStatistics *) NULL) 807ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y); 808ffa10d0fe53ef0f0db63ee506c52695595976b99cristy if (density_xy != (ChannelStatistics *) NULL) 809ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy); 810ffa10d0fe53ef0f0db63ee506c52695595976b99cristy if (density_x != (ChannelStatistics *) NULL) 811ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x); 812ffa10d0fe53ef0f0db63ee506c52695595976b99cristy if (cooccurrence != (ChannelStatistics **) NULL) 813ffa10d0fe53ef0f0db63ee506c52695595976b99cristy { 814bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) number_grays; i++) 815ffa10d0fe53ef0f0db63ee506c52695595976b99cristy cooccurrence[i]=(ChannelStatistics *) 816ffa10d0fe53ef0f0db63ee506c52695595976b99cristy RelinquishMagickMemory(cooccurrence[i]); 817ffa10d0fe53ef0f0db63ee506c52695595976b99cristy cooccurrence=(ChannelStatistics **) RelinquishMagickMemory( 818ffa10d0fe53ef0f0db63ee506c52695595976b99cristy cooccurrence); 819ffa10d0fe53ef0f0db63ee506c52695595976b99cristy } 820101ab708b0574518ac5715da4d3915400e9df79acristy grays=(PixelPacket *) RelinquishMagickMemory(grays); 821f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy channel_features=(ChannelFeatures *) RelinquishMagickMemory( 822f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy channel_features); 823e18977973bff5866de9aa6ed097aea40e27570d6cristy (void) ThrowMagickException(exception,GetMagickModule(), 824efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 825f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy return(channel_features); 826f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy } 827ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(&correlation,0,sizeof(correlation)); 82877173e5c9ab59c80128f74d92b01da7e8a64de8dcristy (void) ResetMagickMemory(density_x,0,2*(number_grays+1)*sizeof(*density_x)); 82977173e5c9ab59c80128f74d92b01da7e8a64de8dcristy (void) ResetMagickMemory(density_xy,0,2*(number_grays+1)*sizeof(*density_xy)); 83077173e5c9ab59c80128f74d92b01da7e8a64de8dcristy (void) ResetMagickMemory(density_y,0,2*(number_grays+1)*sizeof(*density_y)); 831ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(&mean,0,sizeof(mean)); 832ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(sum,0,number_grays*sizeof(*sum)); 833ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(&sum_squares,0,sizeof(sum_squares)); 834ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(density_xy,0,2*number_grays*sizeof(*density_xy)); 835ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(&entropy_x,0,sizeof(entropy_x)); 836ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(&entropy_xy,0,sizeof(entropy_xy)); 837ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(&entropy_xy1,0,sizeof(entropy_xy1)); 838ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(&entropy_xy2,0,sizeof(entropy_xy2)); 839ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(&entropy_y,0,sizeof(entropy_y)); 840ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (void) ResetMagickMemory(&variance,0,sizeof(variance)); 841bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) number_grays; i++) 842f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy { 8437396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[i]=(ChannelStatistics *) AcquireQuantumMemory(number_grays, 8447396d88d575791c136bc6d060e613bdfbfb58f95cristy sizeof(**cooccurrence)); 845ffa10d0fe53ef0f0db63ee506c52695595976b99cristy Q[i]=(ChannelStatistics *) AcquireQuantumMemory(number_grays,sizeof(**Q)); 846ffa10d0fe53ef0f0db63ee506c52695595976b99cristy if ((cooccurrence[i] == (ChannelStatistics *) NULL) || 847ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (Q[i] == (ChannelStatistics *) NULL)) 848f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy break; 8497396d88d575791c136bc6d060e613bdfbfb58f95cristy (void) ResetMagickMemory(cooccurrence[i],0,number_grays* 8503749be456a491c22c19b273d1871e896bd8eae79cristy sizeof(**cooccurrence)); 8513749be456a491c22c19b273d1871e896bd8eae79cristy (void) ResetMagickMemory(Q[i],0,number_grays*sizeof(**Q)); 852f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy } 853bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy if (i < (ssize_t) number_grays) 854f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy { 855f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy for (i--; i >= 0; i--) 856ffa10d0fe53ef0f0db63ee506c52695595976b99cristy { 857ffa10d0fe53ef0f0db63ee506c52695595976b99cristy if (Q[i] != (ChannelStatistics *) NULL) 858ffa10d0fe53ef0f0db63ee506c52695595976b99cristy Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]); 859ffa10d0fe53ef0f0db63ee506c52695595976b99cristy if (cooccurrence[i] != (ChannelStatistics *) NULL) 860ffa10d0fe53ef0f0db63ee506c52695595976b99cristy cooccurrence[i]=(ChannelStatistics *) 861ffa10d0fe53ef0f0db63ee506c52695595976b99cristy RelinquishMagickMemory(cooccurrence[i]); 862ffa10d0fe53ef0f0db63ee506c52695595976b99cristy } 863ffa10d0fe53ef0f0db63ee506c52695595976b99cristy Q=(ChannelStatistics **) RelinquishMagickMemory(Q); 8647396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence); 865ffa10d0fe53ef0f0db63ee506c52695595976b99cristy sum=(ChannelStatistics *) RelinquishMagickMemory(sum); 866ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y); 867ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy); 868ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x); 869101ab708b0574518ac5715da4d3915400e9df79acristy grays=(PixelPacket *) RelinquishMagickMemory(grays); 870f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy channel_features=(ChannelFeatures *) RelinquishMagickMemory( 871f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy channel_features); 872e18977973bff5866de9aa6ed097aea40e27570d6cristy (void) ThrowMagickException(exception,GetMagickModule(), 873efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 874f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy return(channel_features); 875f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy } 876f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy /* 877f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy Initialize spatial dependence matrix. 878f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy */ 879f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy status=MagickTrue; 88046ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy image_view=AcquireVirtualCacheView(image,exception); 881aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk for (r=0; r < (ssize_t) image->rows; r++) 882f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy { 8834c08aed51c5899665ade97263692328eea4af106cristy register const Quantum 88405d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict p; 885f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy 886bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 887f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy x; 888f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy 8897e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy ssize_t 8909d314ff2c17a77996c05413c2013880387e50f0ecristy offset, 8919d314ff2c17a77996c05413c2013880387e50f0ecristy u, 8929d314ff2c17a77996c05413c2013880387e50f0ecristy v; 8937e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy 894f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy if (status == MagickFalse) 895f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy continue; 896aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk p=GetCacheViewVirtualPixels(image_view,-(ssize_t) distance,r,image->columns+ 897a1d2bd306531d35abea0440a3008714d36b5c50ccristy 2*distance,distance+2,exception); 8984c08aed51c5899665ade97263692328eea4af106cristy if (p == (const Quantum *) NULL) 899f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy { 900f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy status=MagickFalse; 901f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy continue; 902f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy } 9038a11cb146177680bfc1b7d89a8cd0c8f2befe468cristy p+=distance*GetPixelChannels(image);; 904bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (x=0; x < (ssize_t) image->columns; x++) 905f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy { 906f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy for (i=0; i < 4; i++) 907f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy { 9087e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy switch (i) 9097e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy { 9107e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy case 0: 911549a37e6cd4593dcb997230cd3584c5afead5552cristy default: 9127e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy { 9137e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy /* 9147396d88d575791c136bc6d060e613bdfbfb58f95cristy Horizontal adjacency. 9157e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy */ 9167e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy offset=(ssize_t) distance; 9177e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy break; 9187e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy } 9197e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy case 1: 9207e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy { 9217e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy /* 9227396d88d575791c136bc6d060e613bdfbfb58f95cristy Vertical adjacency. 9237e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy */ 9247396d88d575791c136bc6d060e613bdfbfb58f95cristy offset=(ssize_t) (image->columns+2*distance); 9257e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy break; 9267e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy } 9277e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy case 2: 9287e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy { 9297e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy /* 9307396d88d575791c136bc6d060e613bdfbfb58f95cristy Right diagonal adjacency. 9317e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy */ 932d99b096901994c291fdd5b648c5ec9c12d675947cristy offset=(ssize_t) ((image->columns+2*distance)-distance); 9337e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy break; 9347e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy } 9357e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy case 3: 9367e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy { 9377e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy /* 9387396d88d575791c136bc6d060e613bdfbfb58f95cristy Left diagonal adjacency. 9397e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy */ 940d99b096901994c291fdd5b648c5ec9c12d675947cristy offset=(ssize_t) ((image->columns+2*distance)+distance); 9417e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy break; 9427e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy } 9437e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy } 9447e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy u=0; 9457e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy v=0; 9464c08aed51c5899665ade97263692328eea4af106cristy while (grays[u].red != ScaleQuantumToMap(GetPixelRed(image,p))) 9477e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy u++; 948ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy while (grays[v].red != ScaleQuantumToMap(GetPixelRed(image,p+offset*GetPixelChannels(image)))) 9497e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy v++; 9507396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[u][v].direction[i].red++; 9517396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[v][u].direction[i].red++; 9527e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy u=0; 9537e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy v=0; 9544c08aed51c5899665ade97263692328eea4af106cristy while (grays[u].green != ScaleQuantumToMap(GetPixelGreen(image,p))) 9557e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy u++; 956ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy while (grays[v].green != ScaleQuantumToMap(GetPixelGreen(image,p+offset*GetPixelChannels(image)))) 9577e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy v++; 9587396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[u][v].direction[i].green++; 9597396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[v][u].direction[i].green++; 9607e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy u=0; 9617e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy v=0; 9624c08aed51c5899665ade97263692328eea4af106cristy while (grays[u].blue != ScaleQuantumToMap(GetPixelBlue(image,p))) 9637e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy u++; 964ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy while (grays[v].blue != ScaleQuantumToMap(GetPixelBlue(image,p+offset*GetPixelChannels(image)))) 9657e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy v++; 9667396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[u][v].direction[i].blue++; 9677396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[v][u].direction[i].blue++; 96853a727d91e1edeb3a67fa7d923db42974bba3b64cristy if (image->colorspace == CMYKColorspace) 9697e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy { 9707e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy u=0; 9717e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy v=0; 9724c08aed51c5899665ade97263692328eea4af106cristy while (grays[u].black != ScaleQuantumToMap(GetPixelBlack(image,p))) 9737e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy u++; 974ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy while (grays[v].black != ScaleQuantumToMap(GetPixelBlack(image,p+offset*GetPixelChannels(image)))) 9757e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy v++; 9764c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[u][v].direction[i].black++; 9774c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[v][u].direction[i].black++; 9787e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy } 97917f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 9807e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy { 9817e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy u=0; 9827e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy v=0; 9834c08aed51c5899665ade97263692328eea4af106cristy while (grays[u].alpha != ScaleQuantumToMap(GetPixelAlpha(image,p))) 9847e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy u++; 985ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy while (grays[v].alpha != ScaleQuantumToMap(GetPixelAlpha(image,p+offset*GetPixelChannels(image)))) 9867e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy v++; 9874c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[u][v].direction[i].alpha++; 9884c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[v][u].direction[i].alpha++; 9897e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy } 990f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy } 991ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy p+=GetPixelChannels(image); 992f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy } 993f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy } 994101ab708b0574518ac5715da4d3915400e9df79acristy grays=(PixelPacket *) RelinquishMagickMemory(grays); 995f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy image_view=DestroyCacheView(image_view); 996f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy if (status == MagickFalse) 997f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy { 998bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) number_grays; i++) 9997396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[i]=(ChannelStatistics *) 10007396d88d575791c136bc6d060e613bdfbfb58f95cristy RelinquishMagickMemory(cooccurrence[i]); 10017396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence); 1002f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy channel_features=(ChannelFeatures *) RelinquishMagickMemory( 1003f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy channel_features); 1004e18977973bff5866de9aa6ed097aea40e27570d6cristy (void) ThrowMagickException(exception,GetMagickModule(), 1005efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 1006f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy return(channel_features); 1007f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy } 1008f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy /* 10097e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy Normalize spatial dependence matrix. 10107e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy */ 1011bd82207b3816471fba4de916fca7336f38b70493cristy for (i=0; i < 4; i++) 10127e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy { 1013549a37e6cd4593dcb997230cd3584c5afead5552cristy double 1014549a37e6cd4593dcb997230cd3584c5afead5552cristy normalize; 1015549a37e6cd4593dcb997230cd3584c5afead5552cristy 101653a727d91e1edeb3a67fa7d923db42974bba3b64cristy register ssize_t 101753a727d91e1edeb3a67fa7d923db42974bba3b64cristy y; 101853a727d91e1edeb3a67fa7d923db42974bba3b64cristy 1019bd82207b3816471fba4de916fca7336f38b70493cristy switch (i) 10207e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy { 1021bd82207b3816471fba4de916fca7336f38b70493cristy case 0: 1022bd82207b3816471fba4de916fca7336f38b70493cristy default: 1023bd82207b3816471fba4de916fca7336f38b70493cristy { 1024bd82207b3816471fba4de916fca7336f38b70493cristy /* 10257396d88d575791c136bc6d060e613bdfbfb58f95cristy Horizontal adjacency. 1026bd82207b3816471fba4de916fca7336f38b70493cristy */ 1027bd82207b3816471fba4de916fca7336f38b70493cristy normalize=2.0*image->rows*(image->columns-distance); 1028bd82207b3816471fba4de916fca7336f38b70493cristy break; 1029bd82207b3816471fba4de916fca7336f38b70493cristy } 1030bd82207b3816471fba4de916fca7336f38b70493cristy case 1: 1031bd82207b3816471fba4de916fca7336f38b70493cristy { 1032bd82207b3816471fba4de916fca7336f38b70493cristy /* 10337396d88d575791c136bc6d060e613bdfbfb58f95cristy Vertical adjacency. 1034bd82207b3816471fba4de916fca7336f38b70493cristy */ 10357396d88d575791c136bc6d060e613bdfbfb58f95cristy normalize=2.0*(image->rows-distance)*image->columns; 1036bd82207b3816471fba4de916fca7336f38b70493cristy break; 1037bd82207b3816471fba4de916fca7336f38b70493cristy } 1038bd82207b3816471fba4de916fca7336f38b70493cristy case 2: 1039bd82207b3816471fba4de916fca7336f38b70493cristy { 1040bd82207b3816471fba4de916fca7336f38b70493cristy /* 10417396d88d575791c136bc6d060e613bdfbfb58f95cristy Right diagonal adjacency. 1042bd82207b3816471fba4de916fca7336f38b70493cristy */ 10437396d88d575791c136bc6d060e613bdfbfb58f95cristy normalize=2.0*(image->rows-distance)*(image->columns-distance); 1044bd82207b3816471fba4de916fca7336f38b70493cristy break; 1045bd82207b3816471fba4de916fca7336f38b70493cristy } 1046bd82207b3816471fba4de916fca7336f38b70493cristy case 3: 1047bd82207b3816471fba4de916fca7336f38b70493cristy { 1048bd82207b3816471fba4de916fca7336f38b70493cristy /* 10497396d88d575791c136bc6d060e613bdfbfb58f95cristy Left diagonal adjacency. 1050bd82207b3816471fba4de916fca7336f38b70493cristy */ 1051bd82207b3816471fba4de916fca7336f38b70493cristy normalize=2.0*(image->rows-distance)*(image->columns-distance); 1052bd82207b3816471fba4de916fca7336f38b70493cristy break; 1053bd82207b3816471fba4de916fca7336f38b70493cristy } 1054bd82207b3816471fba4de916fca7336f38b70493cristy } 10553e3ec3afbb0782697f201cbe30a56794c10dc7efcristy normalize=PerceptibleReciprocal(normalize); 1056bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (y=0; y < (ssize_t) number_grays; y++) 1057bd82207b3816471fba4de916fca7336f38b70493cristy { 1058bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 1059bd82207b3816471fba4de916fca7336f38b70493cristy x; 1060bd82207b3816471fba4de916fca7336f38b70493cristy 1061bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (x=0; x < (ssize_t) number_grays; x++) 10627e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy { 106353a727d91e1edeb3a67fa7d923db42974bba3b64cristy cooccurrence[x][y].direction[i].red*=normalize; 106453a727d91e1edeb3a67fa7d923db42974bba3b64cristy cooccurrence[x][y].direction[i].green*=normalize; 106553a727d91e1edeb3a67fa7d923db42974bba3b64cristy cooccurrence[x][y].direction[i].blue*=normalize; 1066549a37e6cd4593dcb997230cd3584c5afead5552cristy if (image->colorspace == CMYKColorspace) 10674c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].black*=normalize; 106817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 10694c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha*=normalize; 1070549a37e6cd4593dcb997230cd3584c5afead5552cristy } 1071549a37e6cd4593dcb997230cd3584c5afead5552cristy } 1072549a37e6cd4593dcb997230cd3584c5afead5552cristy } 1073549a37e6cd4593dcb997230cd3584c5afead5552cristy /* 1074549a37e6cd4593dcb997230cd3584c5afead5552cristy Compute texture features. 1075549a37e6cd4593dcb997230cd3584c5afead5552cristy */ 10763a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 1077ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp parallel for schedule(static,4) shared(status) \ 10785e6b259130f9dbe0da4666f734937017babe573acristy magick_threads(image,image,number_grays,1) 10793a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy#endif 1080bd82207b3816471fba4de916fca7336f38b70493cristy for (i=0; i < 4; i++) 1081549a37e6cd4593dcb997230cd3584c5afead5552cristy { 1082bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 1083bd82207b3816471fba4de916fca7336f38b70493cristy y; 1084549a37e6cd4593dcb997230cd3584c5afead5552cristy 1085bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (y=0; y < (ssize_t) number_grays; y++) 1086549a37e6cd4593dcb997230cd3584c5afead5552cristy { 1087bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 1088bd82207b3816471fba4de916fca7336f38b70493cristy x; 1089bd82207b3816471fba4de916fca7336f38b70493cristy 1090bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (x=0; x < (ssize_t) number_grays; x++) 1091549a37e6cd4593dcb997230cd3584c5afead5552cristy { 1092549a37e6cd4593dcb997230cd3584c5afead5552cristy /* 10933a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy Angular second moment: measure of homogeneity of the image. 1094549a37e6cd4593dcb997230cd3584c5afead5552cristy */ 1095d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].angular_second_moment[i]+= 10967396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[x][y].direction[i].red* 10977396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[x][y].direction[i].red; 1098d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].angular_second_moment[i]+= 10997396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[x][y].direction[i].green* 11007396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[x][y].direction[i].green; 1101d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].angular_second_moment[i]+= 11027396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[x][y].direction[i].blue* 11037396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[x][y].direction[i].blue; 1104549a37e6cd4593dcb997230cd3584c5afead5552cristy if (image->colorspace == CMYKColorspace) 1105d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].angular_second_moment[i]+= 11064c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].black* 11074c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].black; 110817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1109d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].angular_second_moment[i]+= 11104c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha* 11114c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha; 11127396d88d575791c136bc6d060e613bdfbfb58f95cristy /* 11137396d88d575791c136bc6d060e613bdfbfb58f95cristy Correlation: measure of linear-dependencies in the image. 11147396d88d575791c136bc6d060e613bdfbfb58f95cristy */ 11157396d88d575791c136bc6d060e613bdfbfb58f95cristy sum[y].direction[i].red+=cooccurrence[x][y].direction[i].red; 11167396d88d575791c136bc6d060e613bdfbfb58f95cristy sum[y].direction[i].green+=cooccurrence[x][y].direction[i].green; 1117cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy sum[y].direction[i].blue+=cooccurrence[x][y].direction[i].blue; 1118cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy if (image->colorspace == CMYKColorspace) 11194c08aed51c5899665ade97263692328eea4af106cristy sum[y].direction[i].black+=cooccurrence[x][y].direction[i].black; 112017f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 11214c08aed51c5899665ade97263692328eea4af106cristy sum[y].direction[i].alpha+=cooccurrence[x][y].direction[i].alpha; 1122cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy correlation.direction[i].red+=x*y*cooccurrence[x][y].direction[i].red; 11237396d88d575791c136bc6d060e613bdfbfb58f95cristy correlation.direction[i].green+=x*y* 11247396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[x][y].direction[i].green; 11257396d88d575791c136bc6d060e613bdfbfb58f95cristy correlation.direction[i].blue+=x*y* 11267396d88d575791c136bc6d060e613bdfbfb58f95cristy cooccurrence[x][y].direction[i].blue; 11277396d88d575791c136bc6d060e613bdfbfb58f95cristy if (image->colorspace == CMYKColorspace) 11284c08aed51c5899665ade97263692328eea4af106cristy correlation.direction[i].black+=x*y* 11294c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].black; 113017f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 11314c08aed51c5899665ade97263692328eea4af106cristy correlation.direction[i].alpha+=x*y* 11324c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha; 1133cf5e649a2c6de215ffc88ee00987090773ba0722cristy /* 1134cf5e649a2c6de215ffc88ee00987090773ba0722cristy Inverse Difference Moment. 1135cf5e649a2c6de215ffc88ee00987090773ba0722cristy */ 1136d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].inverse_difference_moment[i]+= 1137cf5e649a2c6de215ffc88ee00987090773ba0722cristy cooccurrence[x][y].direction[i].red/((y-x)*(y-x)+1); 1138d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].inverse_difference_moment[i]+= 1139cf5e649a2c6de215ffc88ee00987090773ba0722cristy cooccurrence[x][y].direction[i].green/((y-x)*(y-x)+1); 1140d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].inverse_difference_moment[i]+= 1141cf5e649a2c6de215ffc88ee00987090773ba0722cristy cooccurrence[x][y].direction[i].blue/((y-x)*(y-x)+1); 1142cf5e649a2c6de215ffc88ee00987090773ba0722cristy if (image->colorspace == CMYKColorspace) 1143d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].inverse_difference_moment[i]+= 11444c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].black/((y-x)*(y-x)+1); 114517f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1146d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].inverse_difference_moment[i]+= 11474c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha/((y-x)*(y-x)+1); 1148e18977973bff5866de9aa6ed097aea40e27570d6cristy /* 1149e18977973bff5866de9aa6ed097aea40e27570d6cristy Sum average. 1150e18977973bff5866de9aa6ed097aea40e27570d6cristy */ 1151ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[y+x+2].direction[i].red+= 1152e18977973bff5866de9aa6ed097aea40e27570d6cristy cooccurrence[x][y].direction[i].red; 1153ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[y+x+2].direction[i].green+= 1154e18977973bff5866de9aa6ed097aea40e27570d6cristy cooccurrence[x][y].direction[i].green; 1155ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[y+x+2].direction[i].blue+= 1156e18977973bff5866de9aa6ed097aea40e27570d6cristy cooccurrence[x][y].direction[i].blue; 1157e18977973bff5866de9aa6ed097aea40e27570d6cristy if (image->colorspace == CMYKColorspace) 11584c08aed51c5899665ade97263692328eea4af106cristy density_xy[y+x+2].direction[i].black+= 11594c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].black; 116017f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 11614c08aed51c5899665ade97263692328eea4af106cristy density_xy[y+x+2].direction[i].alpha+= 11624c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha; 1163e18977973bff5866de9aa6ed097aea40e27570d6cristy /* 1164e18977973bff5866de9aa6ed097aea40e27570d6cristy Entropy. 1165e18977973bff5866de9aa6ed097aea40e27570d6cristy */ 1166d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].entropy[i]-= 1167e18977973bff5866de9aa6ed097aea40e27570d6cristy cooccurrence[x][y].direction[i].red* 11680633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(cooccurrence[x][y].direction[i].red); 1169d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].entropy[i]-= 1170e18977973bff5866de9aa6ed097aea40e27570d6cristy cooccurrence[x][y].direction[i].green* 11710633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(cooccurrence[x][y].direction[i].green); 1172d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].entropy[i]-= 1173e18977973bff5866de9aa6ed097aea40e27570d6cristy cooccurrence[x][y].direction[i].blue* 11740633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(cooccurrence[x][y].direction[i].blue); 1175e18977973bff5866de9aa6ed097aea40e27570d6cristy if (image->colorspace == CMYKColorspace) 1176d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].entropy[i]-= 11774c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].black* 11780633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(cooccurrence[x][y].direction[i].black); 117917f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1180d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].entropy[i]-= 11814c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha* 11820633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(cooccurrence[x][y].direction[i].alpha); 1183e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy /* 1184e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy Information Measures of Correlation. 1185e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy */ 1186ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_x[x].direction[i].red+=cooccurrence[x][y].direction[i].red; 1187ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_x[x].direction[i].green+=cooccurrence[x][y].direction[i].green; 1188ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_x[x].direction[i].blue+=cooccurrence[x][y].direction[i].blue; 118917f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 11904c08aed51c5899665ade97263692328eea4af106cristy density_x[x].direction[i].alpha+= 11914c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha; 11924c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 11934c08aed51c5899665ade97263692328eea4af106cristy density_x[x].direction[i].black+= 11944c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].black; 1195ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_y[y].direction[i].red+=cooccurrence[x][y].direction[i].red; 1196ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_y[y].direction[i].green+=cooccurrence[x][y].direction[i].green; 1197ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_y[y].direction[i].blue+=cooccurrence[x][y].direction[i].blue; 1198e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy if (image->colorspace == CMYKColorspace) 11994c08aed51c5899665ade97263692328eea4af106cristy density_y[y].direction[i].black+= 12004c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].black; 120117f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 12024c08aed51c5899665ade97263692328eea4af106cristy density_y[y].direction[i].alpha+= 12034c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha; 12047e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy } 1205cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy mean.direction[i].red+=y*sum[y].direction[i].red; 1206cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy sum_squares.direction[i].red+=y*y*sum[y].direction[i].red; 1207cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy mean.direction[i].green+=y*sum[y].direction[i].green; 1208cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy sum_squares.direction[i].green+=y*y*sum[y].direction[i].green; 1209cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy mean.direction[i].blue+=y*sum[y].direction[i].blue; 1210cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy sum_squares.direction[i].blue+=y*y*sum[y].direction[i].blue; 1211cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy if (image->colorspace == CMYKColorspace) 1212cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy { 12134c08aed51c5899665ade97263692328eea4af106cristy mean.direction[i].black+=y*sum[y].direction[i].black; 12144c08aed51c5899665ade97263692328eea4af106cristy sum_squares.direction[i].black+=y*y*sum[y].direction[i].black; 1215cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy } 121617f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 121753a727d91e1edeb3a67fa7d923db42974bba3b64cristy { 12184c08aed51c5899665ade97263692328eea4af106cristy mean.direction[i].alpha+=y*sum[y].direction[i].alpha; 12194c08aed51c5899665ade97263692328eea4af106cristy sum_squares.direction[i].alpha+=y*y*sum[y].direction[i].alpha; 122053a727d91e1edeb3a67fa7d923db42974bba3b64cristy } 12217e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy } 1222cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy /* 1223cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy Correlation: measure of linear-dependencies in the image. 1224cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy */ 1225d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].correlation[i]= 1226cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy (correlation.direction[i].red-mean.direction[i].red* 1227cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy mean.direction[i].red)/(sqrt(sum_squares.direction[i].red- 1228cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy (mean.direction[i].red*mean.direction[i].red))*sqrt( 1229cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy sum_squares.direction[i].red-(mean.direction[i].red* 1230cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy mean.direction[i].red))); 1231d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].correlation[i]= 1232cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy (correlation.direction[i].green-mean.direction[i].green* 1233cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy mean.direction[i].green)/(sqrt(sum_squares.direction[i].green- 1234cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy (mean.direction[i].green*mean.direction[i].green))*sqrt( 1235cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy sum_squares.direction[i].green-(mean.direction[i].green* 1236cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy mean.direction[i].green))); 1237d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].correlation[i]= 1238cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy (correlation.direction[i].blue-mean.direction[i].blue* 1239cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy mean.direction[i].blue)/(sqrt(sum_squares.direction[i].blue- 1240cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy (mean.direction[i].blue*mean.direction[i].blue))*sqrt( 1241cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy sum_squares.direction[i].blue-(mean.direction[i].blue* 1242cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy mean.direction[i].blue))); 1243cdf8e1b14a1280a464eeaa3c8b37b8ece8b9cdb2cristy if (image->colorspace == CMYKColorspace) 1244d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].correlation[i]= 12454c08aed51c5899665ade97263692328eea4af106cristy (correlation.direction[i].black-mean.direction[i].black* 12464c08aed51c5899665ade97263692328eea4af106cristy mean.direction[i].black)/(sqrt(sum_squares.direction[i].black- 12474c08aed51c5899665ade97263692328eea4af106cristy (mean.direction[i].black*mean.direction[i].black))*sqrt( 12484c08aed51c5899665ade97263692328eea4af106cristy sum_squares.direction[i].black-(mean.direction[i].black* 12494c08aed51c5899665ade97263692328eea4af106cristy mean.direction[i].black))); 125017f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1251d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].correlation[i]= 12524c08aed51c5899665ade97263692328eea4af106cristy (correlation.direction[i].alpha-mean.direction[i].alpha* 12534c08aed51c5899665ade97263692328eea4af106cristy mean.direction[i].alpha)/(sqrt(sum_squares.direction[i].alpha- 12544c08aed51c5899665ade97263692328eea4af106cristy (mean.direction[i].alpha*mean.direction[i].alpha))*sqrt( 12554c08aed51c5899665ade97263692328eea4af106cristy sum_squares.direction[i].alpha-(mean.direction[i].alpha* 12564c08aed51c5899665ade97263692328eea4af106cristy mean.direction[i].alpha))); 12577e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy } 1258cf5e649a2c6de215ffc88ee00987090773ba0722cristy /* 1259cf5e649a2c6de215ffc88ee00987090773ba0722cristy Compute more texture features. 1260cf5e649a2c6de215ffc88ee00987090773ba0722cristy */ 1261e18977973bff5866de9aa6ed097aea40e27570d6cristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 1262ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp parallel for schedule(static,4) shared(status) \ 12635e6b259130f9dbe0da4666f734937017babe573acristy magick_threads(image,image,number_grays,1) 1264e18977973bff5866de9aa6ed097aea40e27570d6cristy#endif 1265e18977973bff5866de9aa6ed097aea40e27570d6cristy for (i=0; i < 4; i++) 1266e18977973bff5866de9aa6ed097aea40e27570d6cristy { 1267bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 1268e18977973bff5866de9aa6ed097aea40e27570d6cristy x; 1269e18977973bff5866de9aa6ed097aea40e27570d6cristy 1270bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (x=2; x < (ssize_t) (2*number_grays); x++) 1271e18977973bff5866de9aa6ed097aea40e27570d6cristy { 1272e18977973bff5866de9aa6ed097aea40e27570d6cristy /* 1273e18977973bff5866de9aa6ed097aea40e27570d6cristy Sum average. 1274e18977973bff5866de9aa6ed097aea40e27570d6cristy */ 1275d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].sum_average[i]+= 1276ffa10d0fe53ef0f0db63ee506c52695595976b99cristy x*density_xy[x].direction[i].red; 1277d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].sum_average[i]+= 1278ffa10d0fe53ef0f0db63ee506c52695595976b99cristy x*density_xy[x].direction[i].green; 1279d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].sum_average[i]+= 1280ffa10d0fe53ef0f0db63ee506c52695595976b99cristy x*density_xy[x].direction[i].blue; 1281e18977973bff5866de9aa6ed097aea40e27570d6cristy if (image->colorspace == CMYKColorspace) 1282d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].sum_average[i]+= 12834c08aed51c5899665ade97263692328eea4af106cristy x*density_xy[x].direction[i].black; 128417f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1285d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].sum_average[i]+= 12864c08aed51c5899665ade97263692328eea4af106cristy x*density_xy[x].direction[i].alpha; 1287e18977973bff5866de9aa6ed097aea40e27570d6cristy /* 1288e18977973bff5866de9aa6ed097aea40e27570d6cristy Sum entropy. 1289e18977973bff5866de9aa6ed097aea40e27570d6cristy */ 1290d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].sum_entropy[i]-= 1291ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].red* 12920633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_xy[x].direction[i].red); 1293d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].sum_entropy[i]-= 1294ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].green* 12950633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_xy[x].direction[i].green); 1296d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].sum_entropy[i]-= 1297ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].blue* 12980633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_xy[x].direction[i].blue); 1299e18977973bff5866de9aa6ed097aea40e27570d6cristy if (image->colorspace == CMYKColorspace) 1300d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].sum_entropy[i]-= 13014c08aed51c5899665ade97263692328eea4af106cristy density_xy[x].direction[i].black* 13020633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_xy[x].direction[i].black); 130317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1304d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].sum_entropy[i]-= 13054c08aed51c5899665ade97263692328eea4af106cristy density_xy[x].direction[i].alpha* 13060633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_xy[x].direction[i].alpha); 1307e18977973bff5866de9aa6ed097aea40e27570d6cristy /* 1308e18977973bff5866de9aa6ed097aea40e27570d6cristy Sum variance. 1309e18977973bff5866de9aa6ed097aea40e27570d6cristy */ 1310d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].sum_variance[i]+= 1311d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy (x-channel_features[RedPixelChannel].sum_entropy[i])* 1312d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy (x-channel_features[RedPixelChannel].sum_entropy[i])* 1313ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].red; 1314d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].sum_variance[i]+= 1315d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy (x-channel_features[GreenPixelChannel].sum_entropy[i])* 1316d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy (x-channel_features[GreenPixelChannel].sum_entropy[i])* 1317ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].green; 1318d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].sum_variance[i]+= 1319d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy (x-channel_features[BluePixelChannel].sum_entropy[i])* 1320d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy (x-channel_features[BluePixelChannel].sum_entropy[i])* 1321ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].blue; 1322e18977973bff5866de9aa6ed097aea40e27570d6cristy if (image->colorspace == CMYKColorspace) 1323d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].sum_variance[i]+= 1324d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy (x-channel_features[BlackPixelChannel].sum_entropy[i])* 1325d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy (x-channel_features[BlackPixelChannel].sum_entropy[i])* 13264c08aed51c5899665ade97263692328eea4af106cristy density_xy[x].direction[i].black; 132717f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1328d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].sum_variance[i]+= 1329d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy (x-channel_features[AlphaPixelChannel].sum_entropy[i])* 1330d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy (x-channel_features[AlphaPixelChannel].sum_entropy[i])* 13314c08aed51c5899665ade97263692328eea4af106cristy density_xy[x].direction[i].alpha; 1332e18977973bff5866de9aa6ed097aea40e27570d6cristy } 1333e18977973bff5866de9aa6ed097aea40e27570d6cristy } 1334e18977973bff5866de9aa6ed097aea40e27570d6cristy /* 1335e18977973bff5866de9aa6ed097aea40e27570d6cristy Compute more texture features. 1336e18977973bff5866de9aa6ed097aea40e27570d6cristy */ 1337cf5e649a2c6de215ffc88ee00987090773ba0722cristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 1338ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp parallel for schedule(static,4) shared(status) \ 13395e6b259130f9dbe0da4666f734937017babe573acristy magick_threads(image,image,number_grays,1) 1340cf5e649a2c6de215ffc88ee00987090773ba0722cristy#endif 1341cf5e649a2c6de215ffc88ee00987090773ba0722cristy for (i=0; i < 4; i++) 1342cf5e649a2c6de215ffc88ee00987090773ba0722cristy { 1343bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 1344cf5e649a2c6de215ffc88ee00987090773ba0722cristy y; 1345cf5e649a2c6de215ffc88ee00987090773ba0722cristy 1346bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (y=0; y < (ssize_t) number_grays; y++) 1347cf5e649a2c6de215ffc88ee00987090773ba0722cristy { 1348bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 1349cf5e649a2c6de215ffc88ee00987090773ba0722cristy x; 1350cf5e649a2c6de215ffc88ee00987090773ba0722cristy 1351bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (x=0; x < (ssize_t) number_grays; x++) 1352cf5e649a2c6de215ffc88ee00987090773ba0722cristy { 1353cf5e649a2c6de215ffc88ee00987090773ba0722cristy /* 1354cf5e649a2c6de215ffc88ee00987090773ba0722cristy Sum of Squares: Variance 1355cf5e649a2c6de215ffc88ee00987090773ba0722cristy */ 1356cf5e649a2c6de215ffc88ee00987090773ba0722cristy variance.direction[i].red+=(y-mean.direction[i].red+1)* 1357cf5e649a2c6de215ffc88ee00987090773ba0722cristy (y-mean.direction[i].red+1)*cooccurrence[x][y].direction[i].red; 1358cf5e649a2c6de215ffc88ee00987090773ba0722cristy variance.direction[i].green+=(y-mean.direction[i].green+1)* 1359cf5e649a2c6de215ffc88ee00987090773ba0722cristy (y-mean.direction[i].green+1)*cooccurrence[x][y].direction[i].green; 1360cf5e649a2c6de215ffc88ee00987090773ba0722cristy variance.direction[i].blue+=(y-mean.direction[i].blue+1)* 1361cf5e649a2c6de215ffc88ee00987090773ba0722cristy (y-mean.direction[i].blue+1)*cooccurrence[x][y].direction[i].blue; 136253a727d91e1edeb3a67fa7d923db42974bba3b64cristy if (image->colorspace == CMYKColorspace) 13634c08aed51c5899665ade97263692328eea4af106cristy variance.direction[i].black+=(y-mean.direction[i].black+1)* 13644c08aed51c5899665ade97263692328eea4af106cristy (y-mean.direction[i].black+1)*cooccurrence[x][y].direction[i].black; 136517f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 13664c08aed51c5899665ade97263692328eea4af106cristy variance.direction[i].alpha+=(y-mean.direction[i].alpha+1)* 13674c08aed51c5899665ade97263692328eea4af106cristy (y-mean.direction[i].alpha+1)* 13684c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha; 1369e18977973bff5866de9aa6ed097aea40e27570d6cristy /* 1370e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy Sum average / Difference Variance. 1371e18977973bff5866de9aa6ed097aea40e27570d6cristy */ 1372ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[MagickAbsoluteValue(y-x)].direction[i].red+= 1373e18977973bff5866de9aa6ed097aea40e27570d6cristy cooccurrence[x][y].direction[i].red; 1374ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[MagickAbsoluteValue(y-x)].direction[i].green+= 1375e18977973bff5866de9aa6ed097aea40e27570d6cristy cooccurrence[x][y].direction[i].green; 1376ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[MagickAbsoluteValue(y-x)].direction[i].blue+= 1377e18977973bff5866de9aa6ed097aea40e27570d6cristy cooccurrence[x][y].direction[i].blue; 1378e18977973bff5866de9aa6ed097aea40e27570d6cristy if (image->colorspace == CMYKColorspace) 13794c08aed51c5899665ade97263692328eea4af106cristy density_xy[MagickAbsoluteValue(y-x)].direction[i].black+= 13804c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].black; 138117f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 13824c08aed51c5899665ade97263692328eea4af106cristy density_xy[MagickAbsoluteValue(y-x)].direction[i].alpha+= 13834c08aed51c5899665ade97263692328eea4af106cristy cooccurrence[x][y].direction[i].alpha; 1384e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy /* 1385e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy Information Measures of Correlation. 1386e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy */ 1387ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy.direction[i].red-=cooccurrence[x][y].direction[i].red* 13880633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(cooccurrence[x][y].direction[i].red); 1389ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy.direction[i].green-=cooccurrence[x][y].direction[i].green* 13900633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(cooccurrence[x][y].direction[i].green); 1391ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy.direction[i].blue-=cooccurrence[x][y].direction[i].blue* 13920633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(cooccurrence[x][y].direction[i].blue); 139353a727d91e1edeb3a67fa7d923db42974bba3b64cristy if (image->colorspace == CMYKColorspace) 13944c08aed51c5899665ade97263692328eea4af106cristy entropy_xy.direction[i].black-=cooccurrence[x][y].direction[i].black* 13950633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(cooccurrence[x][y].direction[i].black); 139617f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 13974c08aed51c5899665ade97263692328eea4af106cristy entropy_xy.direction[i].alpha-= 13980633a1f35940363594ecb272bb113e045fd65f93cristy cooccurrence[x][y].direction[i].alpha*MagickLog10( 13990633a1f35940363594ecb272bb113e045fd65f93cristy cooccurrence[x][y].direction[i].alpha); 1400ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy1.direction[i].red-=(cooccurrence[x][y].direction[i].red* 14010633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_x[x].direction[i].red*density_y[y].direction[i].red)); 1402ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy1.direction[i].green-=(cooccurrence[x][y].direction[i].green* 14030633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_x[x].direction[i].green* 14040633a1f35940363594ecb272bb113e045fd65f93cristy density_y[y].direction[i].green)); 1405ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy1.direction[i].blue-=(cooccurrence[x][y].direction[i].blue* 14060633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_x[x].direction[i].blue*density_y[y].direction[i].blue)); 1407e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy if (image->colorspace == CMYKColorspace) 14084c08aed51c5899665ade97263692328eea4af106cristy entropy_xy1.direction[i].black-=( 14090633a1f35940363594ecb272bb113e045fd65f93cristy cooccurrence[x][y].direction[i].black*MagickLog10( 14100633a1f35940363594ecb272bb113e045fd65f93cristy density_x[x].direction[i].black*density_y[y].direction[i].black)); 141117f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 14124c08aed51c5899665ade97263692328eea4af106cristy entropy_xy1.direction[i].alpha-=( 14130633a1f35940363594ecb272bb113e045fd65f93cristy cooccurrence[x][y].direction[i].alpha*MagickLog10( 14140633a1f35940363594ecb272bb113e045fd65f93cristy density_x[x].direction[i].alpha*density_y[y].direction[i].alpha)); 1415ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy2.direction[i].red-=(density_x[x].direction[i].red* 14160633a1f35940363594ecb272bb113e045fd65f93cristy density_y[y].direction[i].red*MagickLog10(density_x[x].direction[i].red* 14170633a1f35940363594ecb272bb113e045fd65f93cristy density_y[y].direction[i].red)); 1418ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy2.direction[i].green-=(density_x[x].direction[i].green* 14190633a1f35940363594ecb272bb113e045fd65f93cristy density_y[y].direction[i].green*MagickLog10(density_x[x].direction[i].green* 14200633a1f35940363594ecb272bb113e045fd65f93cristy density_y[y].direction[i].green)); 1421ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy2.direction[i].blue-=(density_x[x].direction[i].blue* 14220633a1f35940363594ecb272bb113e045fd65f93cristy density_y[y].direction[i].blue*MagickLog10(density_x[x].direction[i].blue* 14230633a1f35940363594ecb272bb113e045fd65f93cristy density_y[y].direction[i].blue)); 1424e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy if (image->colorspace == CMYKColorspace) 14254c08aed51c5899665ade97263692328eea4af106cristy entropy_xy2.direction[i].black-=(density_x[x].direction[i].black* 14260633a1f35940363594ecb272bb113e045fd65f93cristy density_y[y].direction[i].black*MagickLog10( 14270633a1f35940363594ecb272bb113e045fd65f93cristy density_x[x].direction[i].black*density_y[y].direction[i].black)); 142817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 14294c08aed51c5899665ade97263692328eea4af106cristy entropy_xy2.direction[i].alpha-=(density_x[x].direction[i].alpha* 14300633a1f35940363594ecb272bb113e045fd65f93cristy density_y[y].direction[i].alpha*MagickLog10( 14310633a1f35940363594ecb272bb113e045fd65f93cristy density_x[x].direction[i].alpha*density_y[y].direction[i].alpha)); 1432cf5e649a2c6de215ffc88ee00987090773ba0722cristy } 1433cf5e649a2c6de215ffc88ee00987090773ba0722cristy } 1434d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].variance_sum_of_squares[i]= 1435cf5e649a2c6de215ffc88ee00987090773ba0722cristy variance.direction[i].red; 1436d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].variance_sum_of_squares[i]= 1437cf5e649a2c6de215ffc88ee00987090773ba0722cristy variance.direction[i].green; 1438d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].variance_sum_of_squares[i]= 1439cf5e649a2c6de215ffc88ee00987090773ba0722cristy variance.direction[i].blue; 1440cf5e649a2c6de215ffc88ee00987090773ba0722cristy if (image->colorspace == CMYKColorspace) 1441d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].variance_sum_of_squares[i]= 14424c08aed51c5899665ade97263692328eea4af106cristy variance.direction[i].black; 144317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1444d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].variance_sum_of_squares[i]= 14454c08aed51c5899665ade97263692328eea4af106cristy variance.direction[i].alpha; 1446cf5e649a2c6de215ffc88ee00987090773ba0722cristy } 1447cf5e649a2c6de215ffc88ee00987090773ba0722cristy /* 1448cf5e649a2c6de215ffc88ee00987090773ba0722cristy Compute more texture features. 1449cf5e649a2c6de215ffc88ee00987090773ba0722cristy */ 1450e18977973bff5866de9aa6ed097aea40e27570d6cristy (void) ResetMagickMemory(&variance,0,sizeof(variance)); 1451e18977973bff5866de9aa6ed097aea40e27570d6cristy (void) ResetMagickMemory(&sum_squares,0,sizeof(sum_squares)); 1452e18977973bff5866de9aa6ed097aea40e27570d6cristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 1453ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp parallel for schedule(static,4) shared(status) \ 14545e6b259130f9dbe0da4666f734937017babe573acristy magick_threads(image,image,number_grays,1) 1455e18977973bff5866de9aa6ed097aea40e27570d6cristy#endif 1456e18977973bff5866de9aa6ed097aea40e27570d6cristy for (i=0; i < 4; i++) 1457e18977973bff5866de9aa6ed097aea40e27570d6cristy { 1458bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 1459e18977973bff5866de9aa6ed097aea40e27570d6cristy x; 1460e18977973bff5866de9aa6ed097aea40e27570d6cristy 1461bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (x=0; x < (ssize_t) number_grays; x++) 1462e18977973bff5866de9aa6ed097aea40e27570d6cristy { 1463e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy /* 1464e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy Difference variance. 1465e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy */ 1466ffa10d0fe53ef0f0db63ee506c52695595976b99cristy variance.direction[i].red+=density_xy[x].direction[i].red; 1467ffa10d0fe53ef0f0db63ee506c52695595976b99cristy variance.direction[i].green+=density_xy[x].direction[i].green; 1468ffa10d0fe53ef0f0db63ee506c52695595976b99cristy variance.direction[i].blue+=density_xy[x].direction[i].blue; 1469e18977973bff5866de9aa6ed097aea40e27570d6cristy if (image->colorspace == CMYKColorspace) 14704c08aed51c5899665ade97263692328eea4af106cristy variance.direction[i].black+=density_xy[x].direction[i].black; 147117f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 14724c08aed51c5899665ade97263692328eea4af106cristy variance.direction[i].alpha+=density_xy[x].direction[i].alpha; 1473ffa10d0fe53ef0f0db63ee506c52695595976b99cristy sum_squares.direction[i].red+=density_xy[x].direction[i].red* 1474ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].red; 1475ffa10d0fe53ef0f0db63ee506c52695595976b99cristy sum_squares.direction[i].green+=density_xy[x].direction[i].green* 1476ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].green; 1477ffa10d0fe53ef0f0db63ee506c52695595976b99cristy sum_squares.direction[i].blue+=density_xy[x].direction[i].blue* 1478ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].blue; 1479e18977973bff5866de9aa6ed097aea40e27570d6cristy if (image->colorspace == CMYKColorspace) 14804c08aed51c5899665ade97263692328eea4af106cristy sum_squares.direction[i].black+=density_xy[x].direction[i].black* 14814c08aed51c5899665ade97263692328eea4af106cristy density_xy[x].direction[i].black; 148217f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 14834c08aed51c5899665ade97263692328eea4af106cristy sum_squares.direction[i].alpha+=density_xy[x].direction[i].alpha* 14844c08aed51c5899665ade97263692328eea4af106cristy density_xy[x].direction[i].alpha; 1485f6214de6bb7f45514a52bf72c3977591aeeddc94cristy /* 1486f6214de6bb7f45514a52bf72c3977591aeeddc94cristy Difference entropy. 1487f6214de6bb7f45514a52bf72c3977591aeeddc94cristy */ 1488d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].difference_entropy[i]-= 1489ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].red* 14900633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_xy[x].direction[i].red); 1491d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].difference_entropy[i]-= 1492ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].green* 14930633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_xy[x].direction[i].green); 1494d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].difference_entropy[i]-= 1495ffa10d0fe53ef0f0db63ee506c52695595976b99cristy density_xy[x].direction[i].blue* 14960633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_xy[x].direction[i].blue); 1497f6214de6bb7f45514a52bf72c3977591aeeddc94cristy if (image->colorspace == CMYKColorspace) 1498d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].difference_entropy[i]-= 14994c08aed51c5899665ade97263692328eea4af106cristy density_xy[x].direction[i].black* 15000633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_xy[x].direction[i].black); 150117f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1502d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].difference_entropy[i]-= 15034c08aed51c5899665ade97263692328eea4af106cristy density_xy[x].direction[i].alpha* 15040633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_xy[x].direction[i].alpha); 1505e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy /* 1506e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy Information Measures of Correlation. 1507e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy */ 1508ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_x.direction[i].red-=(density_x[x].direction[i].red* 15090633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_x[x].direction[i].red)); 1510ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_x.direction[i].green-=(density_x[x].direction[i].green* 15110633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_x[x].direction[i].green)); 1512ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_x.direction[i].blue-=(density_x[x].direction[i].blue* 15130633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_x[x].direction[i].blue)); 1514e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy if (image->colorspace == CMYKColorspace) 15154c08aed51c5899665ade97263692328eea4af106cristy entropy_x.direction[i].black-=(density_x[x].direction[i].black* 15160633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_x[x].direction[i].black)); 151717f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 15184c08aed51c5899665ade97263692328eea4af106cristy entropy_x.direction[i].alpha-=(density_x[x].direction[i].alpha* 15190633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_x[x].direction[i].alpha)); 152053a727d91e1edeb3a67fa7d923db42974bba3b64cristy entropy_y.direction[i].red-=(density_y[x].direction[i].red* 15210633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_y[x].direction[i].red)); 152253a727d91e1edeb3a67fa7d923db42974bba3b64cristy entropy_y.direction[i].green-=(density_y[x].direction[i].green* 15230633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_y[x].direction[i].green)); 152453a727d91e1edeb3a67fa7d923db42974bba3b64cristy entropy_y.direction[i].blue-=(density_y[x].direction[i].blue* 15250633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_y[x].direction[i].blue)); 1526e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy if (image->colorspace == CMYKColorspace) 15274c08aed51c5899665ade97263692328eea4af106cristy entropy_y.direction[i].black-=(density_y[x].direction[i].black* 15280633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_y[x].direction[i].black)); 152917f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 15304c08aed51c5899665ade97263692328eea4af106cristy entropy_y.direction[i].alpha-=(density_y[x].direction[i].alpha* 15310633a1f35940363594ecb272bb113e045fd65f93cristy MagickLog10(density_y[x].direction[i].alpha)); 1532e18977973bff5866de9aa6ed097aea40e27570d6cristy } 1533f6214de6bb7f45514a52bf72c3977591aeeddc94cristy /* 1534f6214de6bb7f45514a52bf72c3977591aeeddc94cristy Difference variance. 1535f6214de6bb7f45514a52bf72c3977591aeeddc94cristy */ 1536d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].difference_variance[i]= 1537e0e19dc554957d2413f7fca5063a75fd92b8a12bcristy (((double) number_grays*number_grays*sum_squares.direction[i].red)- 1538e18977973bff5866de9aa6ed097aea40e27570d6cristy (variance.direction[i].red*variance.direction[i].red))/ 1539e18977973bff5866de9aa6ed097aea40e27570d6cristy ((double) number_grays*number_grays*number_grays*number_grays); 1540d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].difference_variance[i]= 1541e0e19dc554957d2413f7fca5063a75fd92b8a12bcristy (((double) number_grays*number_grays*sum_squares.direction[i].green)- 1542e18977973bff5866de9aa6ed097aea40e27570d6cristy (variance.direction[i].green*variance.direction[i].green))/ 1543e18977973bff5866de9aa6ed097aea40e27570d6cristy ((double) number_grays*number_grays*number_grays*number_grays); 1544d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].difference_variance[i]= 1545e0e19dc554957d2413f7fca5063a75fd92b8a12bcristy (((double) number_grays*number_grays*sum_squares.direction[i].blue)- 1546e18977973bff5866de9aa6ed097aea40e27570d6cristy (variance.direction[i].blue*variance.direction[i].blue))/ 1547e18977973bff5866de9aa6ed097aea40e27570d6cristy ((double) number_grays*number_grays*number_grays*number_grays); 15484c08aed51c5899665ade97263692328eea4af106cristy if (image->colorspace == CMYKColorspace) 1549d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].difference_variance[i]= 15504c08aed51c5899665ade97263692328eea4af106cristy (((double) number_grays*number_grays*sum_squares.direction[i].black)- 15514c08aed51c5899665ade97263692328eea4af106cristy (variance.direction[i].black*variance.direction[i].black))/ 15524c08aed51c5899665ade97263692328eea4af106cristy ((double) number_grays*number_grays*number_grays*number_grays); 155317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1554d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].difference_variance[i]= 15554c08aed51c5899665ade97263692328eea4af106cristy (((double) number_grays*number_grays*sum_squares.direction[i].alpha)- 15564c08aed51c5899665ade97263692328eea4af106cristy (variance.direction[i].alpha*variance.direction[i].alpha))/ 1557e18977973bff5866de9aa6ed097aea40e27570d6cristy ((double) number_grays*number_grays*number_grays*number_grays); 1558e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy /* 1559e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy Information Measures of Correlation. 1560e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy */ 1561d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].measure_of_correlation_1[i]= 1562ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (entropy_xy.direction[i].red-entropy_xy1.direction[i].red)/ 1563ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (entropy_x.direction[i].red > entropy_y.direction[i].red ? 1564ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_x.direction[i].red : entropy_y.direction[i].red); 1565d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].measure_of_correlation_1[i]= 1566ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (entropy_xy.direction[i].green-entropy_xy1.direction[i].green)/ 1567ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (entropy_x.direction[i].green > entropy_y.direction[i].green ? 1568ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_x.direction[i].green : entropy_y.direction[i].green); 1569d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].measure_of_correlation_1[i]= 1570ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (entropy_xy.direction[i].blue-entropy_xy1.direction[i].blue)/ 1571ffa10d0fe53ef0f0db63ee506c52695595976b99cristy (entropy_x.direction[i].blue > entropy_y.direction[i].blue ? 1572ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_x.direction[i].blue : entropy_y.direction[i].blue); 1573e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy if (image->colorspace == CMYKColorspace) 1574d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].measure_of_correlation_1[i]= 15754c08aed51c5899665ade97263692328eea4af106cristy (entropy_xy.direction[i].black-entropy_xy1.direction[i].black)/ 15764c08aed51c5899665ade97263692328eea4af106cristy (entropy_x.direction[i].black > entropy_y.direction[i].black ? 15774c08aed51c5899665ade97263692328eea4af106cristy entropy_x.direction[i].black : entropy_y.direction[i].black); 157817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1579d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].measure_of_correlation_1[i]= 15804c08aed51c5899665ade97263692328eea4af106cristy (entropy_xy.direction[i].alpha-entropy_xy1.direction[i].alpha)/ 15814c08aed51c5899665ade97263692328eea4af106cristy (entropy_x.direction[i].alpha > entropy_y.direction[i].alpha ? 15824c08aed51c5899665ade97263692328eea4af106cristy entropy_x.direction[i].alpha : entropy_y.direction[i].alpha); 1583d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[RedPixelChannel].measure_of_correlation_2[i]= 15843bdd925dbb0804df99e548c50667670319655816cristy (sqrt(fabs(1.0-exp(-2.0*(double) (entropy_xy2.direction[i].red- 1585ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy.direction[i].red))))); 1586d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[GreenPixelChannel].measure_of_correlation_2[i]= 15873bdd925dbb0804df99e548c50667670319655816cristy (sqrt(fabs(1.0-exp(-2.0*(double) (entropy_xy2.direction[i].green- 1588ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy.direction[i].green))))); 1589d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BluePixelChannel].measure_of_correlation_2[i]= 15903bdd925dbb0804df99e548c50667670319655816cristy (sqrt(fabs(1.0-exp(-2.0*(double) (entropy_xy2.direction[i].blue- 1591ffa10d0fe53ef0f0db63ee506c52695595976b99cristy entropy_xy.direction[i].blue))))); 1592e0acabf3ebf7da9eb716f98dfbbaa0d2f4d9d7e4cristy if (image->colorspace == CMYKColorspace) 1593d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[BlackPixelChannel].measure_of_correlation_2[i]= 15943bdd925dbb0804df99e548c50667670319655816cristy (sqrt(fabs(1.0-exp(-2.0*(double) (entropy_xy2.direction[i].black- 15954c08aed51c5899665ade97263692328eea4af106cristy entropy_xy.direction[i].black))))); 159617f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 1597d3090f92b8f346df0a8191d5aa3f9d14be5a32d5cristy channel_features[AlphaPixelChannel].measure_of_correlation_2[i]= 15983bdd925dbb0804df99e548c50667670319655816cristy (sqrt(fabs(1.0-exp(-2.0*(double) (entropy_xy2.direction[i].alpha- 15994c08aed51c5899665ade97263692328eea4af106cristy entropy_xy.direction[i].alpha))))); 1600e18977973bff5866de9aa6ed097aea40e27570d6cristy } 1601e18977973bff5866de9aa6ed097aea40e27570d6cristy /* 16022fc10e5aedab9144531a4668dc7526e3caf514e1cristy Compute more texture features. 16032fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 16042fc10e5aedab9144531a4668dc7526e3caf514e1cristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 16052fc10e5aedab9144531a4668dc7526e3caf514e1cristy #pragma omp parallel for schedule(static,4) shared(status) \ 16062fc10e5aedab9144531a4668dc7526e3caf514e1cristy magick_threads(image,image,number_grays,1) 16072fc10e5aedab9144531a4668dc7526e3caf514e1cristy#endif 16082fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (i=0; i < 4; i++) 16092fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 16102fc10e5aedab9144531a4668dc7526e3caf514e1cristy ssize_t 16112fc10e5aedab9144531a4668dc7526e3caf514e1cristy z; 16122fc10e5aedab9144531a4668dc7526e3caf514e1cristy 16132fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (z=0; z < (ssize_t) number_grays; z++) 16142fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 16152fc10e5aedab9144531a4668dc7526e3caf514e1cristy register ssize_t 16162fc10e5aedab9144531a4668dc7526e3caf514e1cristy y; 16172fc10e5aedab9144531a4668dc7526e3caf514e1cristy 16182fc10e5aedab9144531a4668dc7526e3caf514e1cristy ChannelStatistics 16192fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel; 16202fc10e5aedab9144531a4668dc7526e3caf514e1cristy 16212fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) ResetMagickMemory(&pixel,0,sizeof(pixel)); 16222fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (y=0; y < (ssize_t) number_grays; y++) 16232fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 16242fc10e5aedab9144531a4668dc7526e3caf514e1cristy register ssize_t 16252fc10e5aedab9144531a4668dc7526e3caf514e1cristy x; 16262fc10e5aedab9144531a4668dc7526e3caf514e1cristy 16272fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (x=0; x < (ssize_t) number_grays; x++) 16282fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 16292fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 16302fc10e5aedab9144531a4668dc7526e3caf514e1cristy Contrast: amount of local variations present in an image. 16312fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 16322fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (((y-x) == z) || ((x-y) == z)) 16332fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 16342fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel.direction[i].red+=cooccurrence[x][y].direction[i].red; 16352fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel.direction[i].green+=cooccurrence[x][y].direction[i].green; 16362fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel.direction[i].blue+=cooccurrence[x][y].direction[i].blue; 16372fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (image->colorspace == CMYKColorspace) 16382fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel.direction[i].black+=cooccurrence[x][y].direction[i].black; 163917f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 16402fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel.direction[i].alpha+= 16412fc10e5aedab9144531a4668dc7526e3caf514e1cristy cooccurrence[x][y].direction[i].alpha; 16422fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 16432fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 16442fc10e5aedab9144531a4668dc7526e3caf514e1cristy Maximum Correlation Coefficient. 16452fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 16462fc10e5aedab9144531a4668dc7526e3caf514e1cristy Q[z][y].direction[i].red+=cooccurrence[z][x].direction[i].red* 16472fc10e5aedab9144531a4668dc7526e3caf514e1cristy cooccurrence[y][x].direction[i].red/density_x[z].direction[i].red/ 16482fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_y[x].direction[i].red; 16492fc10e5aedab9144531a4668dc7526e3caf514e1cristy Q[z][y].direction[i].green+=cooccurrence[z][x].direction[i].green* 16502fc10e5aedab9144531a4668dc7526e3caf514e1cristy cooccurrence[y][x].direction[i].green/ 16512fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_x[z].direction[i].green/density_y[x].direction[i].red; 16522fc10e5aedab9144531a4668dc7526e3caf514e1cristy Q[z][y].direction[i].blue+=cooccurrence[z][x].direction[i].blue* 16532fc10e5aedab9144531a4668dc7526e3caf514e1cristy cooccurrence[y][x].direction[i].blue/density_x[z].direction[i].blue/ 16542fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_y[x].direction[i].blue; 16552fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (image->colorspace == CMYKColorspace) 16562fc10e5aedab9144531a4668dc7526e3caf514e1cristy Q[z][y].direction[i].black+=cooccurrence[z][x].direction[i].black* 16572fc10e5aedab9144531a4668dc7526e3caf514e1cristy cooccurrence[y][x].direction[i].black/ 16582fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_x[z].direction[i].black/density_y[x].direction[i].black; 165917f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 16602fc10e5aedab9144531a4668dc7526e3caf514e1cristy Q[z][y].direction[i].alpha+= 16612fc10e5aedab9144531a4668dc7526e3caf514e1cristy cooccurrence[z][x].direction[i].alpha* 16622fc10e5aedab9144531a4668dc7526e3caf514e1cristy cooccurrence[y][x].direction[i].alpha/ 16632fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_x[z].direction[i].alpha/ 16642fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_y[x].direction[i].alpha; 16652fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 16662fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 16672fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features[RedPixelChannel].contrast[i]+=z*z* 16682fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel.direction[i].red; 16692fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features[GreenPixelChannel].contrast[i]+=z*z* 16702fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel.direction[i].green; 16712fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features[BluePixelChannel].contrast[i]+=z*z* 16722fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel.direction[i].blue; 16732fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (image->colorspace == CMYKColorspace) 16742fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features[BlackPixelChannel].contrast[i]+=z*z* 16752fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel.direction[i].black; 167617f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 16772fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features[AlphaPixelChannel].contrast[i]+=z*z* 16782fc10e5aedab9144531a4668dc7526e3caf514e1cristy pixel.direction[i].alpha; 16792fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 16802fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 16812fc10e5aedab9144531a4668dc7526e3caf514e1cristy Maximum Correlation Coefficient. 16822fc10e5aedab9144531a4668dc7526e3caf514e1cristy Future: return second largest eigenvalue of Q. 16832fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 16842fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features[RedPixelChannel].maximum_correlation_coefficient[i]= 16852fc10e5aedab9144531a4668dc7526e3caf514e1cristy sqrt((double) -1.0); 16862fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features[GreenPixelChannel].maximum_correlation_coefficient[i]= 16872fc10e5aedab9144531a4668dc7526e3caf514e1cristy sqrt((double) -1.0); 16882fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features[BluePixelChannel].maximum_correlation_coefficient[i]= 16892fc10e5aedab9144531a4668dc7526e3caf514e1cristy sqrt((double) -1.0); 16902fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (image->colorspace == CMYKColorspace) 16912fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features[BlackPixelChannel].maximum_correlation_coefficient[i]= 16922fc10e5aedab9144531a4668dc7526e3caf514e1cristy sqrt((double) -1.0); 169317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait != UndefinedPixelTrait) 16942fc10e5aedab9144531a4668dc7526e3caf514e1cristy channel_features[AlphaPixelChannel].maximum_correlation_coefficient[i]= 16952fc10e5aedab9144531a4668dc7526e3caf514e1cristy sqrt((double) -1.0); 16962fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 16972fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 16982fc10e5aedab9144531a4668dc7526e3caf514e1cristy Relinquish resources. 16992fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 17002fc10e5aedab9144531a4668dc7526e3caf514e1cristy sum=(ChannelStatistics *) RelinquishMagickMemory(sum); 17012fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (i=0; i < (ssize_t) number_grays; i++) 17022fc10e5aedab9144531a4668dc7526e3caf514e1cristy Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]); 17032fc10e5aedab9144531a4668dc7526e3caf514e1cristy Q=(ChannelStatistics **) RelinquishMagickMemory(Q); 17042fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y); 17052fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy); 17062fc10e5aedab9144531a4668dc7526e3caf514e1cristy density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x); 17072fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (i=0; i < (ssize_t) number_grays; i++) 17082fc10e5aedab9144531a4668dc7526e3caf514e1cristy cooccurrence[i]=(ChannelStatistics *) 17092fc10e5aedab9144531a4668dc7526e3caf514e1cristy RelinquishMagickMemory(cooccurrence[i]); 17102fc10e5aedab9144531a4668dc7526e3caf514e1cristy cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence); 17112fc10e5aedab9144531a4668dc7526e3caf514e1cristy return(channel_features); 17122fc10e5aedab9144531a4668dc7526e3caf514e1cristy} 17132fc10e5aedab9144531a4668dc7526e3caf514e1cristy 17142fc10e5aedab9144531a4668dc7526e3caf514e1cristy/* 17152fc10e5aedab9144531a4668dc7526e3caf514e1cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 17162fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 17172fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 17182fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 17192fc10e5aedab9144531a4668dc7526e3caf514e1cristy% H o u g h L i n e I m a g e % 17202fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 17212fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 17222fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 17232fc10e5aedab9144531a4668dc7526e3caf514e1cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 17242fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 1725ec9a82a7d6938f4ff9993500e150cac3628c0e4bcristy% Use HoughLineImage() in conjunction with any binary edge extracted image (we 1726ec9a82a7d6938f4ff9993500e150cac3628c0e4bcristy% recommand Canny) to identify lines in the image. The algorithm accumulates 1727ec9a82a7d6938f4ff9993500e150cac3628c0e4bcristy% counts for every white pixel for every possible orientation (for angles from 1728ec9a82a7d6938f4ff9993500e150cac3628c0e4bcristy% 0 to 179 in 1 degree increments) and distance from the center of the image to 1729ec9a82a7d6938f4ff9993500e150cac3628c0e4bcristy% the corner (in 1 px increments) and stores the counts in an accumulator matrix 1730ec9a82a7d6938f4ff9993500e150cac3628c0e4bcristy% of angle vs distance. The size of the accumulator is 180x(diagonal/2). Next 1731ec9a82a7d6938f4ff9993500e150cac3628c0e4bcristy% it searches this space for peaks in counts and converts the locations of the 1732ec9a82a7d6938f4ff9993500e150cac3628c0e4bcristy% peaks to slope and intercept in the normal x,y input image space. Use the 1733ec9a82a7d6938f4ff9993500e150cac3628c0e4bcristy% slope/intercepts to find the endpoints clipped to the bounds of the image. The 1734ec9a82a7d6938f4ff9993500e150cac3628c0e4bcristy% lines are then drawn. The counts are a measure of the length of the lines 17352fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 17362fc10e5aedab9144531a4668dc7526e3caf514e1cristy% The format of the HoughLineImage method is: 17372fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 17382fc10e5aedab9144531a4668dc7526e3caf514e1cristy% Image *HoughLineImage(const Image *image,const size_t width, 17392fc10e5aedab9144531a4668dc7526e3caf514e1cristy% const size_t height,const size_t threshold,ExceptionInfo *exception) 17402fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 17412fc10e5aedab9144531a4668dc7526e3caf514e1cristy% A description of each parameter follows: 17422fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 17432fc10e5aedab9144531a4668dc7526e3caf514e1cristy% o image: the image. 17442fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 17452fc10e5aedab9144531a4668dc7526e3caf514e1cristy% o width, height: find line pairs as local maxima in this neighborhood. 17462fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 17472fc10e5aedab9144531a4668dc7526e3caf514e1cristy% o threshold: the line count threshold. 17482fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 17492fc10e5aedab9144531a4668dc7526e3caf514e1cristy% o exception: return any errors or warnings in this structure. 17502fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 17512fc10e5aedab9144531a4668dc7526e3caf514e1cristy*/ 17522fc10e5aedab9144531a4668dc7526e3caf514e1cristy 17532fc10e5aedab9144531a4668dc7526e3caf514e1cristystatic inline double MagickRound(double x) 17542fc10e5aedab9144531a4668dc7526e3caf514e1cristy{ 17552fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 17562fc10e5aedab9144531a4668dc7526e3caf514e1cristy Round the fraction to nearest integer. 17572fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 17582fc10e5aedab9144531a4668dc7526e3caf514e1cristy if ((x-floor(x)) < (ceil(x)-x)) 17592fc10e5aedab9144531a4668dc7526e3caf514e1cristy return(floor(x)); 17602fc10e5aedab9144531a4668dc7526e3caf514e1cristy return(ceil(x)); 17612fc10e5aedab9144531a4668dc7526e3caf514e1cristy} 17622fc10e5aedab9144531a4668dc7526e3caf514e1cristy 1763cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristystatic Image *RenderHoughLines(const ImageInfo *image_info,const size_t columns, 1764cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy const size_t rows,ExceptionInfo *exception) 1765cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy{ 1766cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy#define BoundingBox "viewbox" 1767cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy 1768cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy DrawInfo 1769cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy *draw_info; 1770cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy 1771cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy Image 1772cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy *image; 1773cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy 1774cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy MagickBooleanType 1775cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy status; 1776cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy 1777cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy /* 1778cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy Open image. 1779cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy */ 1780cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy image=AcquireImage(image_info,exception); 1781cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 1782cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy if (status == MagickFalse) 1783cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy { 1784cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy image=DestroyImageList(image); 1785cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy return((Image *) NULL); 1786cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy } 1787cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy image->columns=columns; 1788cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy image->rows=rows; 1789cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); 1790cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy draw_info->affine.sx=image->resolution.x == 0.0 ? 1.0 : image->resolution.x/ 1791cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy DefaultResolution; 1792cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy draw_info->affine.sy=image->resolution.y == 0.0 ? 1.0 : image->resolution.y/ 1793cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy DefaultResolution; 1794cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy image->columns=(size_t) (draw_info->affine.sx*image->columns); 1795cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy image->rows=(size_t) (draw_info->affine.sy*image->rows); 1796cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy status=SetImageExtent(image,image->columns,image->rows,exception); 1797cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy if (status == MagickFalse) 1798cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy return(DestroyImageList(image)); 1799cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy if (SetImageBackgroundColor(image,exception) == MagickFalse) 1800cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy { 1801cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy image=DestroyImageList(image); 1802cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy return((Image *) NULL); 1803cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy } 1804cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy /* 1805cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy Render drawing. 1806cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy */ 1807cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy if (GetBlobStreamData(image) == (unsigned char *) NULL) 1808cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy draw_info->primitive=FileToString(image->filename,~0UL,exception); 1809cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy else 1810cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy { 1811cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy draw_info->primitive=(char *) AcquireMagickMemory((size_t) 1812cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy GetBlobSize(image)+1); 1813cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy if (draw_info->primitive != (char *) NULL) 1814cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy { 1815cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy (void) CopyMagickMemory(draw_info->primitive,GetBlobStreamData(image), 1816cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy (size_t) GetBlobSize(image)); 1817cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy draw_info->primitive[GetBlobSize(image)]='\0'; 1818cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy } 1819cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy } 1820cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy (void) DrawImage(image,draw_info,exception); 1821cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy draw_info=DestroyDrawInfo(draw_info); 1822cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy (void) CloseBlob(image); 1823cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy return(GetFirstImageInList(image)); 1824cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy} 1825cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy 18262fc10e5aedab9144531a4668dc7526e3caf514e1cristyMagickExport Image *HoughLineImage(const Image *image,const size_t width, 18272fc10e5aedab9144531a4668dc7526e3caf514e1cristy const size_t height,const size_t threshold,ExceptionInfo *exception) 18282fc10e5aedab9144531a4668dc7526e3caf514e1cristy{ 18298fbcf1ad6a1d07a92ef39435f679143697be4edacristy#define HoughLineImageTag "HoughLine/Image" 18308fbcf1ad6a1d07a92ef39435f679143697be4edacristy 18312fc10e5aedab9144531a4668dc7526e3caf514e1cristy CacheView 18322fc10e5aedab9144531a4668dc7526e3caf514e1cristy *image_view; 18332fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18342fc10e5aedab9144531a4668dc7526e3caf514e1cristy char 1835151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy message[MagickPathExtent], 1836151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy path[MagickPathExtent]; 18372fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18382fc10e5aedab9144531a4668dc7526e3caf514e1cristy const char 18392fc10e5aedab9144531a4668dc7526e3caf514e1cristy *artifact; 18402fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18412fc10e5aedab9144531a4668dc7526e3caf514e1cristy double 18422fc10e5aedab9144531a4668dc7526e3caf514e1cristy hough_height; 18432fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18442fc10e5aedab9144531a4668dc7526e3caf514e1cristy Image 18452fc10e5aedab9144531a4668dc7526e3caf514e1cristy *lines_image = NULL; 18462fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18472fc10e5aedab9144531a4668dc7526e3caf514e1cristy ImageInfo 18482fc10e5aedab9144531a4668dc7526e3caf514e1cristy *image_info; 18492fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18502fc10e5aedab9144531a4668dc7526e3caf514e1cristy int 18512fc10e5aedab9144531a4668dc7526e3caf514e1cristy file; 18522fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18532fc10e5aedab9144531a4668dc7526e3caf514e1cristy MagickBooleanType 18542fc10e5aedab9144531a4668dc7526e3caf514e1cristy status; 18552fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18568fbcf1ad6a1d07a92ef39435f679143697be4edacristy MagickOffsetType 18578fbcf1ad6a1d07a92ef39435f679143697be4edacristy progress; 18588fbcf1ad6a1d07a92ef39435f679143697be4edacristy 18592fc10e5aedab9144531a4668dc7526e3caf514e1cristy MatrixInfo 18602fc10e5aedab9144531a4668dc7526e3caf514e1cristy *accumulator; 18612fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18622fc10e5aedab9144531a4668dc7526e3caf514e1cristy PointInfo 18632fc10e5aedab9144531a4668dc7526e3caf514e1cristy center; 18642fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18652fc10e5aedab9144531a4668dc7526e3caf514e1cristy register ssize_t 18662fc10e5aedab9144531a4668dc7526e3caf514e1cristy y; 18672fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18682fc10e5aedab9144531a4668dc7526e3caf514e1cristy size_t 18692fc10e5aedab9144531a4668dc7526e3caf514e1cristy accumulator_height, 18702fc10e5aedab9144531a4668dc7526e3caf514e1cristy accumulator_width, 18712fc10e5aedab9144531a4668dc7526e3caf514e1cristy line_count; 18722fc10e5aedab9144531a4668dc7526e3caf514e1cristy 18732fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 18742fc10e5aedab9144531a4668dc7526e3caf514e1cristy Create the accumulator. 18752fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 18762fc10e5aedab9144531a4668dc7526e3caf514e1cristy assert(image != (const Image *) NULL); 1877e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(image->signature == MagickCoreSignature); 18782fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (image->debug != MagickFalse) 18792fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 18802fc10e5aedab9144531a4668dc7526e3caf514e1cristy assert(exception != (ExceptionInfo *) NULL); 1881e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(exception->signature == MagickCoreSignature); 18822fc10e5aedab9144531a4668dc7526e3caf514e1cristy accumulator_width=180; 18832fc10e5aedab9144531a4668dc7526e3caf514e1cristy hough_height=((sqrt(2.0)*(double) (image->rows > image->columns ? 18842fc10e5aedab9144531a4668dc7526e3caf514e1cristy image->rows : image->columns))/2.0); 18852fc10e5aedab9144531a4668dc7526e3caf514e1cristy accumulator_height=(size_t) (2.0*hough_height); 18862fc10e5aedab9144531a4668dc7526e3caf514e1cristy accumulator=AcquireMatrixInfo(accumulator_width,accumulator_height, 18872fc10e5aedab9144531a4668dc7526e3caf514e1cristy sizeof(double),exception); 18882fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (accumulator == (MatrixInfo *) NULL) 18892fc10e5aedab9144531a4668dc7526e3caf514e1cristy ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); 18902fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (NullMatrix(accumulator) == MagickFalse) 18912fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 18922fc10e5aedab9144531a4668dc7526e3caf514e1cristy accumulator=DestroyMatrixInfo(accumulator); 18932fc10e5aedab9144531a4668dc7526e3caf514e1cristy ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); 18942fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 18952fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 18962fc10e5aedab9144531a4668dc7526e3caf514e1cristy Populate the accumulator. 18972fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 18982fc10e5aedab9144531a4668dc7526e3caf514e1cristy status=MagickTrue; 18998fbcf1ad6a1d07a92ef39435f679143697be4edacristy progress=0; 19002fc10e5aedab9144531a4668dc7526e3caf514e1cristy center.x=(double) image->columns/2.0; 19012fc10e5aedab9144531a4668dc7526e3caf514e1cristy center.y=(double) image->rows/2.0; 19022fc10e5aedab9144531a4668dc7526e3caf514e1cristy image_view=AcquireVirtualCacheView(image,exception); 19032fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (y=0; y < (ssize_t) image->rows; y++) 19042fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 19052fc10e5aedab9144531a4668dc7526e3caf514e1cristy register const Quantum 190605d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict p; 19072fc10e5aedab9144531a4668dc7526e3caf514e1cristy 19082fc10e5aedab9144531a4668dc7526e3caf514e1cristy register ssize_t 19092fc10e5aedab9144531a4668dc7526e3caf514e1cristy x; 19102fc10e5aedab9144531a4668dc7526e3caf514e1cristy 19112fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (status == MagickFalse) 19122fc10e5aedab9144531a4668dc7526e3caf514e1cristy continue; 19132fc10e5aedab9144531a4668dc7526e3caf514e1cristy p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 19142fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (p == (Quantum *) NULL) 19152fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 19162fc10e5aedab9144531a4668dc7526e3caf514e1cristy status=MagickFalse; 19172fc10e5aedab9144531a4668dc7526e3caf514e1cristy continue; 19182fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 19192fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (x=0; x < (ssize_t) image->columns; x++) 19202fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 19212e03529bdd5a322e00e9b1d4655181c6f09ca768cristy if (GetPixelIntensity(image,p) > (QuantumRange/2.0)) 19222fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 19232fc10e5aedab9144531a4668dc7526e3caf514e1cristy register ssize_t 19242fc10e5aedab9144531a4668dc7526e3caf514e1cristy i; 19252fc10e5aedab9144531a4668dc7526e3caf514e1cristy 19262fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (i=0; i < 180; i++) 19272fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 19282fc10e5aedab9144531a4668dc7526e3caf514e1cristy double 19292fc10e5aedab9144531a4668dc7526e3caf514e1cristy count, 19302fc10e5aedab9144531a4668dc7526e3caf514e1cristy radius; 19312fc10e5aedab9144531a4668dc7526e3caf514e1cristy 19322fc10e5aedab9144531a4668dc7526e3caf514e1cristy radius=(((double) x-center.x)*cos(DegreesToRadians((double) i)))+ 19332fc10e5aedab9144531a4668dc7526e3caf514e1cristy (((double) y-center.y)*sin(DegreesToRadians((double) i))); 19342fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) GetMatrixElement(accumulator,i,(ssize_t) 19352fc10e5aedab9144531a4668dc7526e3caf514e1cristy MagickRound(radius+hough_height),&count); 19362fc10e5aedab9144531a4668dc7526e3caf514e1cristy count++; 19372fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) SetMatrixElement(accumulator,i,(ssize_t) 19382fc10e5aedab9144531a4668dc7526e3caf514e1cristy MagickRound(radius+hough_height),&count); 19392fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 19402fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 19412fc10e5aedab9144531a4668dc7526e3caf514e1cristy p+=GetPixelChannels(image); 19422fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 19438fbcf1ad6a1d07a92ef39435f679143697be4edacristy if (image->progress_monitor != (MagickProgressMonitor) NULL) 19448fbcf1ad6a1d07a92ef39435f679143697be4edacristy { 19458fbcf1ad6a1d07a92ef39435f679143697be4edacristy MagickBooleanType 19468fbcf1ad6a1d07a92ef39435f679143697be4edacristy proceed; 19478fbcf1ad6a1d07a92ef39435f679143697be4edacristy 19488fbcf1ad6a1d07a92ef39435f679143697be4edacristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 19498fbcf1ad6a1d07a92ef39435f679143697be4edacristy #pragma omp critical (MagickCore_CannyEdgeImage) 19508fbcf1ad6a1d07a92ef39435f679143697be4edacristy#endif 19518fbcf1ad6a1d07a92ef39435f679143697be4edacristy proceed=SetImageProgress(image,CannyEdgeImageTag,progress++, 19528fbcf1ad6a1d07a92ef39435f679143697be4edacristy image->rows); 19538fbcf1ad6a1d07a92ef39435f679143697be4edacristy if (proceed == MagickFalse) 19548fbcf1ad6a1d07a92ef39435f679143697be4edacristy status=MagickFalse; 19558fbcf1ad6a1d07a92ef39435f679143697be4edacristy } 19562fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 19572fc10e5aedab9144531a4668dc7526e3caf514e1cristy image_view=DestroyCacheView(image_view); 19582fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (status == MagickFalse) 19592fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 19602fc10e5aedab9144531a4668dc7526e3caf514e1cristy accumulator=DestroyMatrixInfo(accumulator); 19612fc10e5aedab9144531a4668dc7526e3caf514e1cristy return((Image *) NULL); 19622fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 19632fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 19642fc10e5aedab9144531a4668dc7526e3caf514e1cristy Generate line segments from accumulator. 1965e18977973bff5866de9aa6ed097aea40e27570d6cristy */ 19662fc10e5aedab9144531a4668dc7526e3caf514e1cristy file=AcquireUniqueFileResource(path); 19672fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (file == -1) 19682fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 19692fc10e5aedab9144531a4668dc7526e3caf514e1cristy accumulator=DestroyMatrixInfo(accumulator); 19702fc10e5aedab9144531a4668dc7526e3caf514e1cristy return((Image *) NULL); 19712fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 1972151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy (void) FormatLocaleString(message,MagickPathExtent, 19732fc10e5aedab9144531a4668dc7526e3caf514e1cristy "# Hough line transform: %.20gx%.20g%+.20g\n",(double) width, 19742fc10e5aedab9144531a4668dc7526e3caf514e1cristy (double) height,(double) threshold); 197596498423d48af3032b4ad554b12e347e0231eb45cristy if (write(file,message,strlen(message)) != (ssize_t) strlen(message)) 1976233483c36e4f75e4337766b87cae1ab13d8b92a8cristy status=MagickFalse; 1977cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy (void) FormatLocaleString(message,MagickPathExtent, 1978cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy "viewbox 0 0 %.20g %.20g\n",(double) image->columns,(double) image->rows); 197996498423d48af3032b4ad554b12e347e0231eb45cristy if (write(file,message,strlen(message)) != (ssize_t) strlen(message)) 1980233483c36e4f75e4337766b87cae1ab13d8b92a8cristy status=MagickFalse; 19812fc10e5aedab9144531a4668dc7526e3caf514e1cristy line_count=image->columns > image->rows ? image->columns/4 : image->rows/4; 19822fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (threshold != 0) 19832fc10e5aedab9144531a4668dc7526e3caf514e1cristy line_count=threshold; 19842fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (y=0; y < (ssize_t) accumulator_height; y++) 19853a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy { 19862fc10e5aedab9144531a4668dc7526e3caf514e1cristy register ssize_t 19872fc10e5aedab9144531a4668dc7526e3caf514e1cristy x; 1988564a56979706a30a3d0f920fd5f538a408efd4f1cristy 19892fc10e5aedab9144531a4668dc7526e3caf514e1cristy for (x=0; x < (ssize_t) accumulator_width; x++) 19903a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy { 19912fc10e5aedab9144531a4668dc7526e3caf514e1cristy double 19922fc10e5aedab9144531a4668dc7526e3caf514e1cristy count; 19933a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy 19942fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) GetMatrixElement(accumulator,x,y,&count); 19952fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (count >= (double) line_count) 19962fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 19972fc10e5aedab9144531a4668dc7526e3caf514e1cristy double 19982fc10e5aedab9144531a4668dc7526e3caf514e1cristy maxima; 1999bd82207b3816471fba4de916fca7336f38b70493cristy 20002fc10e5aedab9144531a4668dc7526e3caf514e1cristy SegmentInfo 20012fc10e5aedab9144531a4668dc7526e3caf514e1cristy line; 20022fc10e5aedab9144531a4668dc7526e3caf514e1cristy 20032fc10e5aedab9144531a4668dc7526e3caf514e1cristy ssize_t 20042fc10e5aedab9144531a4668dc7526e3caf514e1cristy v; 2005bd82207b3816471fba4de916fca7336f38b70493cristy 20063a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy /* 20072fc10e5aedab9144531a4668dc7526e3caf514e1cristy Is point a local maxima? 20083a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy */ 20092fc10e5aedab9144531a4668dc7526e3caf514e1cristy maxima=count; 20102494e3d5cea70ebef8e12498b10bc2e24da4803fcristy for (v=(-((ssize_t) height/2)); v <= (((ssize_t) height/2)); v++) 20112fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 20122fc10e5aedab9144531a4668dc7526e3caf514e1cristy ssize_t 20132fc10e5aedab9144531a4668dc7526e3caf514e1cristy u; 20142fc10e5aedab9144531a4668dc7526e3caf514e1cristy 20152494e3d5cea70ebef8e12498b10bc2e24da4803fcristy for (u=(-((ssize_t) width/2)); u <= (((ssize_t) width/2)); u++) 20163a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy { 20172fc10e5aedab9144531a4668dc7526e3caf514e1cristy if ((u != 0) || (v !=0)) 20182fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 20192fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) GetMatrixElement(accumulator,x+u,y+v,&count); 20202fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (count > maxima) 20212fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 20222fc10e5aedab9144531a4668dc7526e3caf514e1cristy maxima=count; 20232fc10e5aedab9144531a4668dc7526e3caf514e1cristy break; 20242fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 20252fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 20263a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy } 20272fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (u < (ssize_t) (width/2)) 20282fc10e5aedab9144531a4668dc7526e3caf514e1cristy break; 20292fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 20302fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) GetMatrixElement(accumulator,x,y,&count); 20312fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (maxima > count) 20322fc10e5aedab9144531a4668dc7526e3caf514e1cristy continue; 20332fc10e5aedab9144531a4668dc7526e3caf514e1cristy if ((x >= 45) && (x <= 135)) 20342fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 20352fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 20362fc10e5aedab9144531a4668dc7526e3caf514e1cristy y = (r-x cos(t))/sin(t) 20372fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 20382fc10e5aedab9144531a4668dc7526e3caf514e1cristy line.x1=0.0; 20392fc10e5aedab9144531a4668dc7526e3caf514e1cristy line.y1=((double) (y-(accumulator_height/2.0))-((line.x1- 20402fc10e5aedab9144531a4668dc7526e3caf514e1cristy (image->columns/2.0))*cos(DegreesToRadians((double) x))))/ 20412fc10e5aedab9144531a4668dc7526e3caf514e1cristy sin(DegreesToRadians((double) x))+(image->rows/2.0); 20422fc10e5aedab9144531a4668dc7526e3caf514e1cristy line.x2=(double) image->columns; 20432fc10e5aedab9144531a4668dc7526e3caf514e1cristy line.y2=((double) (y-(accumulator_height/2.0))-((line.x2- 20442fc10e5aedab9144531a4668dc7526e3caf514e1cristy (image->columns/2.0))*cos(DegreesToRadians((double) x))))/ 20452fc10e5aedab9144531a4668dc7526e3caf514e1cristy sin(DegreesToRadians((double) x))+(image->rows/2.0); 20462fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 20472fc10e5aedab9144531a4668dc7526e3caf514e1cristy else 20482fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 20492fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 20502fc10e5aedab9144531a4668dc7526e3caf514e1cristy x = (r-y cos(t))/sin(t) 20512fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 20522fc10e5aedab9144531a4668dc7526e3caf514e1cristy line.y1=0.0; 20532fc10e5aedab9144531a4668dc7526e3caf514e1cristy line.x1=((double) (y-(accumulator_height/2.0))-((line.y1- 20542fc10e5aedab9144531a4668dc7526e3caf514e1cristy (image->rows/2.0))*sin(DegreesToRadians((double) x))))/ 20552fc10e5aedab9144531a4668dc7526e3caf514e1cristy cos(DegreesToRadians((double) x))+(image->columns/2.0); 20562fc10e5aedab9144531a4668dc7526e3caf514e1cristy line.y2=(double) image->rows; 20572fc10e5aedab9144531a4668dc7526e3caf514e1cristy line.x2=((double) (y-(accumulator_height/2.0))-((line.y2- 20582fc10e5aedab9144531a4668dc7526e3caf514e1cristy (image->rows/2.0))*sin(DegreesToRadians((double) x))))/ 20592fc10e5aedab9144531a4668dc7526e3caf514e1cristy cos(DegreesToRadians((double) x))+(image->columns/2.0); 20602fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 2061151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy (void) FormatLocaleString(message,MagickPathExtent, 20622fc10e5aedab9144531a4668dc7526e3caf514e1cristy "line %g,%g %g,%g # %g\n",line.x1,line.y1,line.x2,line.y2,maxima); 206396498423d48af3032b4ad554b12e347e0231eb45cristy if (write(file,message,strlen(message)) != (ssize_t) strlen(message)) 2064233483c36e4f75e4337766b87cae1ab13d8b92a8cristy status=MagickFalse; 20653a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy } 20663a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy } 20673a82f25dfc8e47ea3049f3a474a8c79ebc268926cristy } 20682fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) close(file); 20697e9726d27d1b1e079b9b94b78f5ffd49352fcc91cristy /* 20702fc10e5aedab9144531a4668dc7526e3caf514e1cristy Render lines to image canvas. 2071f2bf2c76eb0f9a013d0a4dd51d4b86d3d714ddf2cristy */ 20722fc10e5aedab9144531a4668dc7526e3caf514e1cristy image_info=AcquireImageInfo(); 20732fc10e5aedab9144531a4668dc7526e3caf514e1cristy image_info->background_color=image->background_color; 2074cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy (void) FormatLocaleString(image_info->filename,MagickPathExtent,"%s",path); 20752fc10e5aedab9144531a4668dc7526e3caf514e1cristy artifact=GetImageArtifact(image,"background"); 20762fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (artifact != (const char *) NULL) 20772fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) SetImageOption(image_info,"background",artifact); 20782fc10e5aedab9144531a4668dc7526e3caf514e1cristy artifact=GetImageArtifact(image,"fill"); 20792fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (artifact != (const char *) NULL) 20802fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) SetImageOption(image_info,"fill",artifact); 20812fc10e5aedab9144531a4668dc7526e3caf514e1cristy artifact=GetImageArtifact(image,"stroke"); 20822fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (artifact != (const char *) NULL) 20832fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) SetImageOption(image_info,"stroke",artifact); 20842fc10e5aedab9144531a4668dc7526e3caf514e1cristy artifact=GetImageArtifact(image,"strokewidth"); 20852fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (artifact != (const char *) NULL) 20862fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) SetImageOption(image_info,"strokewidth",artifact); 2087cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy lines_image=RenderHoughLines(image_info,image->columns,image->rows,exception); 20882fc10e5aedab9144531a4668dc7526e3caf514e1cristy artifact=GetImageArtifact(image,"hough-lines:accumulator"); 20892fc10e5aedab9144531a4668dc7526e3caf514e1cristy if ((lines_image != (Image *) NULL) && 20902fc10e5aedab9144531a4668dc7526e3caf514e1cristy (IsStringTrue(artifact) != MagickFalse)) 20912fc10e5aedab9144531a4668dc7526e3caf514e1cristy { 20922fc10e5aedab9144531a4668dc7526e3caf514e1cristy Image 20932fc10e5aedab9144531a4668dc7526e3caf514e1cristy *accumulator_image; 20942fc10e5aedab9144531a4668dc7526e3caf514e1cristy 20952fc10e5aedab9144531a4668dc7526e3caf514e1cristy accumulator_image=MatrixToImage(accumulator,exception); 20962fc10e5aedab9144531a4668dc7526e3caf514e1cristy if (accumulator_image != (Image *) NULL) 20972fc10e5aedab9144531a4668dc7526e3caf514e1cristy AppendImageToList(&lines_image,accumulator_image); 20982fc10e5aedab9144531a4668dc7526e3caf514e1cristy } 20992fc10e5aedab9144531a4668dc7526e3caf514e1cristy /* 21002fc10e5aedab9144531a4668dc7526e3caf514e1cristy Free resources. 21012fc10e5aedab9144531a4668dc7526e3caf514e1cristy */ 21022fc10e5aedab9144531a4668dc7526e3caf514e1cristy accumulator=DestroyMatrixInfo(accumulator); 21032fc10e5aedab9144531a4668dc7526e3caf514e1cristy image_info=DestroyImageInfo(image_info); 21042fc10e5aedab9144531a4668dc7526e3caf514e1cristy (void) RelinquishUniqueFileResource(path); 21052fc10e5aedab9144531a4668dc7526e3caf514e1cristy return(GetFirstImageInList(lines_image)); 21062fc10e5aedab9144531a4668dc7526e3caf514e1cristy} 21072fc10e5aedab9144531a4668dc7526e3caf514e1cristy 21082fc10e5aedab9144531a4668dc7526e3caf514e1cristy/* 21092fc10e5aedab9144531a4668dc7526e3caf514e1cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21102fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 21112fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 21122fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 21132fc10e5aedab9144531a4668dc7526e3caf514e1cristy% M e a n S h i f t I m a g e % 21142fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 21152fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 21162fc10e5aedab9144531a4668dc7526e3caf514e1cristy% % 21172fc10e5aedab9144531a4668dc7526e3caf514e1cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21182fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 2119c904cab8ecc6ca7aa6a24d3a0f74991d23494829cristy% MeanShiftImage() delineate arbitrarily shaped clusters in the image. For 2120c904cab8ecc6ca7aa6a24d3a0f74991d23494829cristy% each pixel, it visits all the pixels in the neighborhood specified by 2121c904cab8ecc6ca7aa6a24d3a0f74991d23494829cristy% the window centered at the pixel and excludes those that are outside the 2122c904cab8ecc6ca7aa6a24d3a0f74991d23494829cristy% radius=(window-1)/2 surrounding the pixel. From those pixels, it finds those 2123c904cab8ecc6ca7aa6a24d3a0f74991d23494829cristy% that are within the specified color distance from the current mean, and 2124c904cab8ecc6ca7aa6a24d3a0f74991d23494829cristy% computes a new x,y centroid from those coordinates and a new mean. This new 2125c904cab8ecc6ca7aa6a24d3a0f74991d23494829cristy% x,y centroid is used as the center for a new window. This process iterates 2126c904cab8ecc6ca7aa6a24d3a0f74991d23494829cristy% until it converges and the final mean is replaces the (original window 2127cfbe890d0cfcd5d3b0f63744a6901e40e992e07cCristy% center) pixel value. It repeats this process for the next pixel, etc., 2128c904cab8ecc6ca7aa6a24d3a0f74991d23494829cristy% until it processes all pixels in the image. Results are typically better with 2129c904cab8ecc6ca7aa6a24d3a0f74991d23494829cristy% colorspaces other than sRGB. We recommend YIQ, YUV or YCbCr. 21302fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 21312fc10e5aedab9144531a4668dc7526e3caf514e1cristy% The format of the MeanShiftImage method is: 21322fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 21332fc10e5aedab9144531a4668dc7526e3caf514e1cristy% Image *MeanShiftImage(const Image *image,const size_t width, 21346aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy% const size_t height,const double color_distance, 21356aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy% ExceptionInfo *exception) 21362fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 21372fc10e5aedab9144531a4668dc7526e3caf514e1cristy% A description of each parameter follows: 21382fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 21392fc10e5aedab9144531a4668dc7526e3caf514e1cristy% o image: the image. 21402fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 2141d70bd6ca959a16d8a10f4b2bc0988e91cbcad980cristy% o width, height: find pixels in this neighborhood. 21422fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 21436aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy% o color_distance: the color distance. 21442fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 21452fc10e5aedab9144531a4668dc7526e3caf514e1cristy% o exception: return any errors or warnings in this structure. 21462fc10e5aedab9144531a4668dc7526e3caf514e1cristy% 21472fc10e5aedab9144531a4668dc7526e3caf514e1cristy*/ 21482fc10e5aedab9144531a4668dc7526e3caf514e1cristyMagickExport Image *MeanShiftImage(const Image *image,const size_t width, 21496aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy const size_t height,const double color_distance,ExceptionInfo *exception) 21502fc10e5aedab9144531a4668dc7526e3caf514e1cristy{ 21516aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy#define MaxMeanShiftIterations 100 21524c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy#define MeanShiftImageTag "MeanShift/Image" 21536aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 21546aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy CacheView 21556aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy *image_view, 21566aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy *mean_view, 21576aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy *pixel_view; 21586aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 21596aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy Image 21606aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy *mean_image; 21616aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 21626aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy MagickBooleanType 21636aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy status; 21646aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 21654c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy MagickOffsetType 21664c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy progress; 21674c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy 21686aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy ssize_t 21696aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy y; 21706aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 21716aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy assert(image != (const Image *) NULL); 2172e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(image->signature == MagickCoreSignature); 21736aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy if (image->debug != MagickFalse) 21746aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 21756aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy assert(exception != (ExceptionInfo *) NULL); 2176e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(exception->signature == MagickCoreSignature); 21776aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); 21786aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy if (mean_image == (Image *) NULL) 21796aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy return((Image *) NULL); 21806aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy if (SetImageStorageClass(mean_image,DirectClass,exception) == MagickFalse) 21816aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy { 21826aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_image=DestroyImage(mean_image); 21836aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy return((Image *) NULL); 21846aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy } 21856aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy status=MagickTrue; 21864c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy progress=0; 21876aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy image_view=AcquireVirtualCacheView(image,exception); 21886aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy pixel_view=AcquireVirtualCacheView(image,exception); 21896aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_view=AcquireAuthenticCacheView(mean_image,exception); 21906aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 21914c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy #pragma omp parallel for schedule(static,4) shared(status,progress) \ 21926aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy magick_threads(mean_image,mean_image,mean_image->rows,1) 21936aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy#endif 21946aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy for (y=0; y < (ssize_t) mean_image->rows; y++) 21956aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy { 21966aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy register const Quantum 219705d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict p; 21986aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 21996aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy register Quantum 220005d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict q; 22016aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 22026aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy register ssize_t 22036aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy x; 22046aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 22056aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy if (status == MagickFalse) 22066aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy continue; 22076aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 22086aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy q=GetCacheViewAuthenticPixels(mean_view,0,y,mean_image->columns,1, 22096aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy exception); 22106aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 22116aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy { 22126aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy status=MagickFalse; 22136aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy continue; 22146aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy } 22156aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy for (x=0; x < (ssize_t) mean_image->columns; x++) 22166aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy { 22176aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy PixelInfo 22186aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_pixel, 22196aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy previous_pixel; 22206aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 22216aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy PointInfo 22226aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_location, 22236aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy previous_location; 22246aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 22256aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy register ssize_t 22266aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy i; 22276aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 22286aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy GetPixelInfo(image,&mean_pixel); 22296aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy GetPixelInfoPixel(image,p,&mean_pixel); 22306aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_location.x=(double) x; 22316aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_location.y=(double) y; 22326aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy for (i=0; i < MaxMeanShiftIterations; i++) 22336aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy { 22346aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy double 22356aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy distance, 22366aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy gamma; 22376aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 22386aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy PixelInfo 22396aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy sum_pixel; 22406aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 22416aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy PointInfo 22426aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy sum_location; 22436aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 22446aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy ssize_t 22456aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy count, 22466aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy v; 22476aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 22486aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy sum_location.x=0.0; 22496aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy sum_location.y=0.0; 22506aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy GetPixelInfo(image,&sum_pixel); 2251f89d1dd0b5189cf4df3163fc495f0493f8ddcc7ecristy previous_location=mean_location; 22526aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy previous_pixel=mean_pixel; 22536aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy count=0; 22542494e3d5cea70ebef8e12498b10bc2e24da4803fcristy for (v=(-((ssize_t) height/2)); v <= (((ssize_t) height/2)); v++) 22556aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy { 22566aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy ssize_t 22576aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy u; 22586aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy 22592494e3d5cea70ebef8e12498b10bc2e24da4803fcristy for (u=(-((ssize_t) width/2)); u <= (((ssize_t) width/2)); u++) 22606aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy { 2261e5ecaa83494b57d5fd8956f8b4931d58cfd6e8fccristy if ((v*v+u*u) <= (ssize_t) ((width/2)*(height/2))) 22626aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy { 2263983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy PixelInfo 2264983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy pixel; 2265983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy 2266983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy status=GetOneCacheViewVirtualPixelInfo(pixel_view,(ssize_t) 22678c2a8442c506836270be8c418c87f031400edf1bcristy MagickRound(mean_location.x+u),(ssize_t) MagickRound( 22688c2a8442c506836270be8c418c87f031400edf1bcristy mean_location.y+v),&pixel,exception); 2269d70bd6ca959a16d8a10f4b2bc0988e91cbcad980cristy distance=(mean_pixel.red-pixel.red)*(mean_pixel.red-pixel.red)+ 2270d70bd6ca959a16d8a10f4b2bc0988e91cbcad980cristy (mean_pixel.green-pixel.green)*(mean_pixel.green-pixel.green)+ 2271d70bd6ca959a16d8a10f4b2bc0988e91cbcad980cristy (mean_pixel.blue-pixel.blue)*(mean_pixel.blue-pixel.blue); 2272983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy if (distance <= (color_distance*color_distance)) 2273983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy { 2274983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy sum_location.x+=mean_location.x+u; 2275983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy sum_location.y+=mean_location.y+v; 2276983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy sum_pixel.red+=pixel.red; 2277983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy sum_pixel.green+=pixel.green; 2278983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy sum_pixel.blue+=pixel.blue; 2279983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy sum_pixel.alpha+=pixel.alpha; 2280983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy count++; 2281983aa7cfdd9f51bc2309c5b1cbe50c6c3ac23993cristy } 22826aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy } 22836aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy } 22846aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy } 22856aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy gamma=1.0/count; 22868c2a8442c506836270be8c418c87f031400edf1bcristy mean_location.x=gamma*sum_location.x; 22878c2a8442c506836270be8c418c87f031400edf1bcristy mean_location.y=gamma*sum_location.y; 22886aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_pixel.red=gamma*sum_pixel.red; 22896aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_pixel.green=gamma*sum_pixel.green; 22906aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_pixel.blue=gamma*sum_pixel.blue; 22916aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_pixel.alpha=gamma*sum_pixel.alpha; 22926aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy distance=(mean_location.x-previous_location.x)* 22936aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy (mean_location.x-previous_location.x)+ 22946aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy (mean_location.y-previous_location.y)* 22956aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy (mean_location.y-previous_location.y)+ 229621a2b741c3102c64fd63164026da2c5b785ec6f5cristy 255.0*QuantumScale*(mean_pixel.red-previous_pixel.red)* 229721a2b741c3102c64fd63164026da2c5b785ec6f5cristy 255.0*QuantumScale*(mean_pixel.red-previous_pixel.red)+ 229821a2b741c3102c64fd63164026da2c5b785ec6f5cristy 255.0*QuantumScale*(mean_pixel.green-previous_pixel.green)* 229921a2b741c3102c64fd63164026da2c5b785ec6f5cristy 255.0*QuantumScale*(mean_pixel.green-previous_pixel.green)+ 230021a2b741c3102c64fd63164026da2c5b785ec6f5cristy 255.0*QuantumScale*(mean_pixel.blue-previous_pixel.blue)* 230121a2b741c3102c64fd63164026da2c5b785ec6f5cristy 255.0*QuantumScale*(mean_pixel.blue-previous_pixel.blue); 2302d70bd6ca959a16d8a10f4b2bc0988e91cbcad980cristy if (distance <= 3.0) 23036aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy break; 23046aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy } 23056aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy SetPixelRed(mean_image,ClampToQuantum(mean_pixel.red),q); 23066aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy SetPixelGreen(mean_image,ClampToQuantum(mean_pixel.green),q); 23076aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy SetPixelBlue(mean_image,ClampToQuantum(mean_pixel.blue),q); 23086aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy SetPixelAlpha(mean_image,ClampToQuantum(mean_pixel.alpha),q); 23096aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy p+=GetPixelChannels(image); 23106aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy q+=GetPixelChannels(mean_image); 23116aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy } 23126aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy if (SyncCacheViewAuthenticPixels(mean_view,exception) == MagickFalse) 23136aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy status=MagickFalse; 23144c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy if (image->progress_monitor != (MagickProgressMonitor) NULL) 23154c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy { 23164c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy MagickBooleanType 23174c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy proceed; 23184c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy 23194c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 23204c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy #pragma omp critical (MagickCore_MeanShiftImage) 23214c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy#endif 23224c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy proceed=SetImageProgress(image,MeanShiftImageTag,progress++, 23234c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy image->rows); 23244c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy if (proceed == MagickFalse) 23254c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy status=MagickFalse; 23264c8a3ecf917f56f107f2a7477fb60139d2861f3dcristy } 23276aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy } 23286aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy mean_view=DestroyCacheView(mean_view); 23296aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy pixel_view=DestroyCacheView(pixel_view); 23306aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy image_view=DestroyCacheView(image_view); 23316aa40d3dfec558e9b5f4eae34b4cbd7f14944182cristy return(mean_image); 23323e2860cb0796fe77659325ec3d540d8766d54f49cristy} 2333