morphology.py 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223
  1. # Copyright (C) 2003-2005 Peter J. Verveer
  2. #
  3. # Redistribution and use in source and binary forms, with or without
  4. # modification, are permitted provided that the following conditions
  5. # are met:
  6. #
  7. # 1. Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. #
  10. # 2. Redistributions in binary form must reproduce the above
  11. # copyright notice, this list of conditions and the following
  12. # disclaimer in the documentation and/or other materials provided
  13. # with the distribution.
  14. #
  15. # 3. The name of the author may not be used to endorse or promote
  16. # products derived from this software without specific prior
  17. # written permission.
  18. #
  19. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
  20. # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  23. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  25. # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  27. # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28. # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. from __future__ import division, print_function, absolute_import
  31. import warnings
  32. import numpy
  33. from . import _ni_support
  34. from . import _nd_image
  35. from . import filters
  36. __all__ = ['iterate_structure', 'generate_binary_structure', 'binary_erosion',
  37. 'binary_dilation', 'binary_opening', 'binary_closing',
  38. 'binary_hit_or_miss', 'binary_propagation', 'binary_fill_holes',
  39. 'grey_erosion', 'grey_dilation', 'grey_opening', 'grey_closing',
  40. 'morphological_gradient', 'morphological_laplace', 'white_tophat',
  41. 'black_tophat', 'distance_transform_bf', 'distance_transform_cdt',
  42. 'distance_transform_edt']
  43. def _center_is_true(structure, origin):
  44. structure = numpy.array(structure)
  45. coor = tuple([oo + ss // 2 for ss, oo in zip(structure.shape,
  46. origin)])
  47. return bool(structure[coor])
  48. def iterate_structure(structure, iterations, origin=None):
  49. """
  50. Iterate a structure by dilating it with itself.
  51. Parameters
  52. ----------
  53. structure : array_like
  54. Structuring element (an array of bools, for example), to be dilated with
  55. itself.
  56. iterations : int
  57. number of dilations performed on the structure with itself
  58. origin : optional
  59. If origin is None, only the iterated structure is returned. If
  60. not, a tuple of the iterated structure and the modified origin is
  61. returned.
  62. Returns
  63. -------
  64. iterate_structure : ndarray of bools
  65. A new structuring element obtained by dilating `structure`
  66. (`iterations` - 1) times with itself.
  67. See also
  68. --------
  69. generate_binary_structure
  70. Examples
  71. --------
  72. >>> from scipy import ndimage
  73. >>> struct = ndimage.generate_binary_structure(2, 1)
  74. >>> struct.astype(int)
  75. array([[0, 1, 0],
  76. [1, 1, 1],
  77. [0, 1, 0]])
  78. >>> ndimage.iterate_structure(struct, 2).astype(int)
  79. array([[0, 0, 1, 0, 0],
  80. [0, 1, 1, 1, 0],
  81. [1, 1, 1, 1, 1],
  82. [0, 1, 1, 1, 0],
  83. [0, 0, 1, 0, 0]])
  84. >>> ndimage.iterate_structure(struct, 3).astype(int)
  85. array([[0, 0, 0, 1, 0, 0, 0],
  86. [0, 0, 1, 1, 1, 0, 0],
  87. [0, 1, 1, 1, 1, 1, 0],
  88. [1, 1, 1, 1, 1, 1, 1],
  89. [0, 1, 1, 1, 1, 1, 0],
  90. [0, 0, 1, 1, 1, 0, 0],
  91. [0, 0, 0, 1, 0, 0, 0]])
  92. """
  93. structure = numpy.asarray(structure)
  94. if iterations < 2:
  95. return structure.copy()
  96. ni = iterations - 1
  97. shape = [ii + ni * (ii - 1) for ii in structure.shape]
  98. pos = [ni * (structure.shape[ii] // 2) for ii in range(len(shape))]
  99. slc = tuple(slice(pos[ii], pos[ii] + structure.shape[ii], None)
  100. for ii in range(len(shape)))
  101. out = numpy.zeros(shape, bool)
  102. out[slc] = structure != 0
  103. out = binary_dilation(out, structure, iterations=ni)
  104. if origin is None:
  105. return out
  106. else:
  107. origin = _ni_support._normalize_sequence(origin, structure.ndim)
  108. origin = [iterations * o for o in origin]
  109. return out, origin
  110. def generate_binary_structure(rank, connectivity):
  111. """
  112. Generate a binary structure for binary morphological operations.
  113. Parameters
  114. ----------
  115. rank : int
  116. Number of dimensions of the array to which the structuring element
  117. will be applied, as returned by `np.ndim`.
  118. connectivity : int
  119. `connectivity` determines which elements of the output array belong
  120. to the structure, i.e. are considered as neighbors of the central
  121. element. Elements up to a squared distance of `connectivity` from
  122. the center are considered neighbors. `connectivity` may range from 1
  123. (no diagonal elements are neighbors) to `rank` (all elements are
  124. neighbors).
  125. Returns
  126. -------
  127. output : ndarray of bools
  128. Structuring element which may be used for binary morphological
  129. operations, with `rank` dimensions and all dimensions equal to 3.
  130. See also
  131. --------
  132. iterate_structure, binary_dilation, binary_erosion
  133. Notes
  134. -----
  135. `generate_binary_structure` can only create structuring elements with
  136. dimensions equal to 3, i.e. minimal dimensions. For larger structuring
  137. elements, that are useful e.g. for eroding large objects, one may either
  138. use `iterate_structure`, or create directly custom arrays with
  139. numpy functions such as `numpy.ones`.
  140. Examples
  141. --------
  142. >>> from scipy import ndimage
  143. >>> struct = ndimage.generate_binary_structure(2, 1)
  144. >>> struct
  145. array([[False, True, False],
  146. [ True, True, True],
  147. [False, True, False]], dtype=bool)
  148. >>> a = np.zeros((5,5))
  149. >>> a[2, 2] = 1
  150. >>> a
  151. array([[ 0., 0., 0., 0., 0.],
  152. [ 0., 0., 0., 0., 0.],
  153. [ 0., 0., 1., 0., 0.],
  154. [ 0., 0., 0., 0., 0.],
  155. [ 0., 0., 0., 0., 0.]])
  156. >>> b = ndimage.binary_dilation(a, structure=struct).astype(a.dtype)
  157. >>> b
  158. array([[ 0., 0., 0., 0., 0.],
  159. [ 0., 0., 1., 0., 0.],
  160. [ 0., 1., 1., 1., 0.],
  161. [ 0., 0., 1., 0., 0.],
  162. [ 0., 0., 0., 0., 0.]])
  163. >>> ndimage.binary_dilation(b, structure=struct).astype(a.dtype)
  164. array([[ 0., 0., 1., 0., 0.],
  165. [ 0., 1., 1., 1., 0.],
  166. [ 1., 1., 1., 1., 1.],
  167. [ 0., 1., 1., 1., 0.],
  168. [ 0., 0., 1., 0., 0.]])
  169. >>> struct = ndimage.generate_binary_structure(2, 2)
  170. >>> struct
  171. array([[ True, True, True],
  172. [ True, True, True],
  173. [ True, True, True]], dtype=bool)
  174. >>> struct = ndimage.generate_binary_structure(3, 1)
  175. >>> struct # no diagonal elements
  176. array([[[False, False, False],
  177. [False, True, False],
  178. [False, False, False]],
  179. [[False, True, False],
  180. [ True, True, True],
  181. [False, True, False]],
  182. [[False, False, False],
  183. [False, True, False],
  184. [False, False, False]]], dtype=bool)
  185. """
  186. if connectivity < 1:
  187. connectivity = 1
  188. if rank < 1:
  189. return numpy.array(True, dtype=bool)
  190. output = numpy.fabs(numpy.indices([3] * rank) - 1)
  191. output = numpy.add.reduce(output, 0)
  192. return output <= connectivity
  193. def _binary_erosion(input, structure, iterations, mask, output,
  194. border_value, origin, invert, brute_force):
  195. input = numpy.asarray(input)
  196. if numpy.iscomplexobj(input):
  197. raise TypeError('Complex type not supported')
  198. if structure is None:
  199. structure = generate_binary_structure(input.ndim, 1)
  200. else:
  201. structure = numpy.asarray(structure, dtype=bool)
  202. if structure.ndim != input.ndim:
  203. raise RuntimeError('structure and input must have same dimensionality')
  204. if not structure.flags.contiguous:
  205. structure = structure.copy()
  206. if numpy.product(structure.shape, axis=0) < 1:
  207. raise RuntimeError('structure must not be empty')
  208. if mask is not None:
  209. mask = numpy.asarray(mask)
  210. if mask.shape != input.shape:
  211. raise RuntimeError('mask and input must have equal sizes')
  212. origin = _ni_support._normalize_sequence(origin, input.ndim)
  213. cit = _center_is_true(structure, origin)
  214. if isinstance(output, numpy.ndarray):
  215. if numpy.iscomplexobj(output):
  216. raise TypeError('Complex output type not supported')
  217. else:
  218. output = bool
  219. output = _ni_support._get_output(output, input)
  220. if iterations == 1:
  221. _nd_image.binary_erosion(input, structure, mask, output,
  222. border_value, origin, invert, cit, 0)
  223. return output
  224. elif cit and not brute_force:
  225. changed, coordinate_list = _nd_image.binary_erosion(
  226. input, structure, mask, output,
  227. border_value, origin, invert, cit, 1)
  228. structure = structure[tuple([slice(None, None, -1)] *
  229. structure.ndim)]
  230. for ii in range(len(origin)):
  231. origin[ii] = -origin[ii]
  232. if not structure.shape[ii] & 1:
  233. origin[ii] -= 1
  234. if mask is not None:
  235. mask = numpy.asarray(mask, dtype=numpy.int8)
  236. if not structure.flags.contiguous:
  237. structure = structure.copy()
  238. _nd_image.binary_erosion2(output, structure, mask, iterations - 1,
  239. origin, invert, coordinate_list)
  240. return output
  241. else:
  242. tmp_in = numpy.empty_like(input, dtype=bool)
  243. tmp_out = output
  244. if iterations >= 1 and not iterations & 1:
  245. tmp_in, tmp_out = tmp_out, tmp_in
  246. changed = _nd_image.binary_erosion(
  247. input, structure, mask, tmp_out,
  248. border_value, origin, invert, cit, 0)
  249. ii = 1
  250. while ii < iterations or (iterations < 1 and changed):
  251. tmp_in, tmp_out = tmp_out, tmp_in
  252. changed = _nd_image.binary_erosion(
  253. tmp_in, structure, mask, tmp_out,
  254. border_value, origin, invert, cit, 0)
  255. ii += 1
  256. return output
  257. def binary_erosion(input, structure=None, iterations=1, mask=None, output=None,
  258. border_value=0, origin=0, brute_force=False):
  259. """
  260. Multi-dimensional binary erosion with a given structuring element.
  261. Binary erosion is a mathematical morphology operation used for image
  262. processing.
  263. Parameters
  264. ----------
  265. input : array_like
  266. Binary image to be eroded. Non-zero (True) elements form
  267. the subset to be eroded.
  268. structure : array_like, optional
  269. Structuring element used for the erosion. Non-zero elements are
  270. considered True. If no structuring element is provided, an element
  271. is generated with a square connectivity equal to one.
  272. iterations : {int, float}, optional
  273. The erosion is repeated `iterations` times (one, by default).
  274. If iterations is less than 1, the erosion is repeated until the
  275. result does not change anymore.
  276. mask : array_like, optional
  277. If a mask is given, only those elements with a True value at
  278. the corresponding mask element are modified at each iteration.
  279. output : ndarray, optional
  280. Array of the same shape as input, into which the output is placed.
  281. By default, a new array is created.
  282. border_value : int (cast to 0 or 1), optional
  283. Value at the border in the output array.
  284. origin : int or tuple of ints, optional
  285. Placement of the filter, by default 0.
  286. brute_force : boolean, optional
  287. Memory condition: if False, only the pixels whose value was changed in
  288. the last iteration are tracked as candidates to be updated (eroded) in
  289. the current iteration; if True all pixels are considered as candidates
  290. for erosion, regardless of what happened in the previous iteration.
  291. False by default.
  292. Returns
  293. -------
  294. binary_erosion : ndarray of bools
  295. Erosion of the input by the structuring element.
  296. See also
  297. --------
  298. grey_erosion, binary_dilation, binary_closing, binary_opening,
  299. generate_binary_structure
  300. Notes
  301. -----
  302. Erosion [1]_ is a mathematical morphology operation [2]_ that uses a
  303. structuring element for shrinking the shapes in an image. The binary
  304. erosion of an image by a structuring element is the locus of the points
  305. where a superimposition of the structuring element centered on the point
  306. is entirely contained in the set of non-zero elements of the image.
  307. References
  308. ----------
  309. .. [1] https://en.wikipedia.org/wiki/Erosion_%28morphology%29
  310. .. [2] https://en.wikipedia.org/wiki/Mathematical_morphology
  311. Examples
  312. --------
  313. >>> from scipy import ndimage
  314. >>> a = np.zeros((7,7), dtype=int)
  315. >>> a[1:6, 2:5] = 1
  316. >>> a
  317. array([[0, 0, 0, 0, 0, 0, 0],
  318. [0, 0, 1, 1, 1, 0, 0],
  319. [0, 0, 1, 1, 1, 0, 0],
  320. [0, 0, 1, 1, 1, 0, 0],
  321. [0, 0, 1, 1, 1, 0, 0],
  322. [0, 0, 1, 1, 1, 0, 0],
  323. [0, 0, 0, 0, 0, 0, 0]])
  324. >>> ndimage.binary_erosion(a).astype(a.dtype)
  325. array([[0, 0, 0, 0, 0, 0, 0],
  326. [0, 0, 0, 0, 0, 0, 0],
  327. [0, 0, 0, 1, 0, 0, 0],
  328. [0, 0, 0, 1, 0, 0, 0],
  329. [0, 0, 0, 1, 0, 0, 0],
  330. [0, 0, 0, 0, 0, 0, 0],
  331. [0, 0, 0, 0, 0, 0, 0]])
  332. >>> #Erosion removes objects smaller than the structure
  333. >>> ndimage.binary_erosion(a, structure=np.ones((5,5))).astype(a.dtype)
  334. array([[0, 0, 0, 0, 0, 0, 0],
  335. [0, 0, 0, 0, 0, 0, 0],
  336. [0, 0, 0, 0, 0, 0, 0],
  337. [0, 0, 0, 0, 0, 0, 0],
  338. [0, 0, 0, 0, 0, 0, 0],
  339. [0, 0, 0, 0, 0, 0, 0],
  340. [0, 0, 0, 0, 0, 0, 0]])
  341. """
  342. return _binary_erosion(input, structure, iterations, mask,
  343. output, border_value, origin, 0, brute_force)
  344. def binary_dilation(input, structure=None, iterations=1, mask=None,
  345. output=None, border_value=0, origin=0,
  346. brute_force=False):
  347. """
  348. Multi-dimensional binary dilation with the given structuring element.
  349. Parameters
  350. ----------
  351. input : array_like
  352. Binary array_like to be dilated. Non-zero (True) elements form
  353. the subset to be dilated.
  354. structure : array_like, optional
  355. Structuring element used for the dilation. Non-zero elements are
  356. considered True. If no structuring element is provided an element
  357. is generated with a square connectivity equal to one.
  358. iterations : {int, float}, optional
  359. The dilation is repeated `iterations` times (one, by default).
  360. If iterations is less than 1, the dilation is repeated until the
  361. result does not change anymore.
  362. mask : array_like, optional
  363. If a mask is given, only those elements with a True value at
  364. the corresponding mask element are modified at each iteration.
  365. output : ndarray, optional
  366. Array of the same shape as input, into which the output is placed.
  367. By default, a new array is created.
  368. border_value : int (cast to 0 or 1), optional
  369. Value at the border in the output array.
  370. origin : int or tuple of ints, optional
  371. Placement of the filter, by default 0.
  372. brute_force : boolean, optional
  373. Memory condition: if False, only the pixels whose value was changed in
  374. the last iteration are tracked as candidates to be updated (dilated)
  375. in the current iteration; if True all pixels are considered as
  376. candidates for dilation, regardless of what happened in the previous
  377. iteration. False by default.
  378. Returns
  379. -------
  380. binary_dilation : ndarray of bools
  381. Dilation of the input by the structuring element.
  382. See also
  383. --------
  384. grey_dilation, binary_erosion, binary_closing, binary_opening,
  385. generate_binary_structure
  386. Notes
  387. -----
  388. Dilation [1]_ is a mathematical morphology operation [2]_ that uses a
  389. structuring element for expanding the shapes in an image. The binary
  390. dilation of an image by a structuring element is the locus of the points
  391. covered by the structuring element, when its center lies within the
  392. non-zero points of the image.
  393. References
  394. ----------
  395. .. [1] https://en.wikipedia.org/wiki/Dilation_%28morphology%29
  396. .. [2] https://en.wikipedia.org/wiki/Mathematical_morphology
  397. Examples
  398. --------
  399. >>> from scipy import ndimage
  400. >>> a = np.zeros((5, 5))
  401. >>> a[2, 2] = 1
  402. >>> a
  403. array([[ 0., 0., 0., 0., 0.],
  404. [ 0., 0., 0., 0., 0.],
  405. [ 0., 0., 1., 0., 0.],
  406. [ 0., 0., 0., 0., 0.],
  407. [ 0., 0., 0., 0., 0.]])
  408. >>> ndimage.binary_dilation(a)
  409. array([[False, False, False, False, False],
  410. [False, False, True, False, False],
  411. [False, True, True, True, False],
  412. [False, False, True, False, False],
  413. [False, False, False, False, False]], dtype=bool)
  414. >>> ndimage.binary_dilation(a).astype(a.dtype)
  415. array([[ 0., 0., 0., 0., 0.],
  416. [ 0., 0., 1., 0., 0.],
  417. [ 0., 1., 1., 1., 0.],
  418. [ 0., 0., 1., 0., 0.],
  419. [ 0., 0., 0., 0., 0.]])
  420. >>> # 3x3 structuring element with connectivity 1, used by default
  421. >>> struct1 = ndimage.generate_binary_structure(2, 1)
  422. >>> struct1
  423. array([[False, True, False],
  424. [ True, True, True],
  425. [False, True, False]], dtype=bool)
  426. >>> # 3x3 structuring element with connectivity 2
  427. >>> struct2 = ndimage.generate_binary_structure(2, 2)
  428. >>> struct2
  429. array([[ True, True, True],
  430. [ True, True, True],
  431. [ True, True, True]], dtype=bool)
  432. >>> ndimage.binary_dilation(a, structure=struct1).astype(a.dtype)
  433. array([[ 0., 0., 0., 0., 0.],
  434. [ 0., 0., 1., 0., 0.],
  435. [ 0., 1., 1., 1., 0.],
  436. [ 0., 0., 1., 0., 0.],
  437. [ 0., 0., 0., 0., 0.]])
  438. >>> ndimage.binary_dilation(a, structure=struct2).astype(a.dtype)
  439. array([[ 0., 0., 0., 0., 0.],
  440. [ 0., 1., 1., 1., 0.],
  441. [ 0., 1., 1., 1., 0.],
  442. [ 0., 1., 1., 1., 0.],
  443. [ 0., 0., 0., 0., 0.]])
  444. >>> ndimage.binary_dilation(a, structure=struct1,\\
  445. ... iterations=2).astype(a.dtype)
  446. array([[ 0., 0., 1., 0., 0.],
  447. [ 0., 1., 1., 1., 0.],
  448. [ 1., 1., 1., 1., 1.],
  449. [ 0., 1., 1., 1., 0.],
  450. [ 0., 0., 1., 0., 0.]])
  451. """
  452. input = numpy.asarray(input)
  453. if structure is None:
  454. structure = generate_binary_structure(input.ndim, 1)
  455. origin = _ni_support._normalize_sequence(origin, input.ndim)
  456. structure = numpy.asarray(structure)
  457. structure = structure[tuple([slice(None, None, -1)] *
  458. structure.ndim)]
  459. for ii in range(len(origin)):
  460. origin[ii] = -origin[ii]
  461. if not structure.shape[ii] & 1:
  462. origin[ii] -= 1
  463. return _binary_erosion(input, structure, iterations, mask,
  464. output, border_value, origin, 1, brute_force)
  465. def binary_opening(input, structure=None, iterations=1, output=None,
  466. origin=0, mask=None, border_value=0, brute_force=False):
  467. """
  468. Multi-dimensional binary opening with the given structuring element.
  469. The *opening* of an input image by a structuring element is the
  470. *dilation* of the *erosion* of the image by the structuring element.
  471. Parameters
  472. ----------
  473. input : array_like
  474. Binary array_like to be opened. Non-zero (True) elements form
  475. the subset to be opened.
  476. structure : array_like, optional
  477. Structuring element used for the opening. Non-zero elements are
  478. considered True. If no structuring element is provided an element
  479. is generated with a square connectivity equal to one (i.e., only
  480. nearest neighbors are connected to the center, diagonally-connected
  481. elements are not considered neighbors).
  482. iterations : {int, float}, optional
  483. The erosion step of the opening, then the dilation step are each
  484. repeated `iterations` times (one, by default). If `iterations` is
  485. less than 1, each operation is repeated until the result does
  486. not change anymore.
  487. output : ndarray, optional
  488. Array of the same shape as input, into which the output is placed.
  489. By default, a new array is created.
  490. origin : int or tuple of ints, optional
  491. Placement of the filter, by default 0.
  492. mask : array_like, optional
  493. If a mask is given, only those elements with a True value at
  494. the corresponding mask element are modified at each iteration.
  495. .. versionadded:: 1.1.0
  496. border_value : int (cast to 0 or 1), optional
  497. Value at the border in the output array.
  498. .. versionadded:: 1.1.0
  499. brute_force : boolean, optional
  500. Memory condition: if False, only the pixels whose value was changed in
  501. the last iteration are tracked as candidates to be updated in the
  502. current iteration; if true all pixels are considered as candidates for
  503. update, regardless of what happened in the previous iteration.
  504. False by default.
  505. .. versionadded:: 1.1.0
  506. Returns
  507. -------
  508. binary_opening : ndarray of bools
  509. Opening of the input by the structuring element.
  510. See also
  511. --------
  512. grey_opening, binary_closing, binary_erosion, binary_dilation,
  513. generate_binary_structure
  514. Notes
  515. -----
  516. *Opening* [1]_ is a mathematical morphology operation [2]_ that
  517. consists in the succession of an erosion and a dilation of the
  518. input with the same structuring element. Opening therefore removes
  519. objects smaller than the structuring element.
  520. Together with *closing* (`binary_closing`), opening can be used for
  521. noise removal.
  522. References
  523. ----------
  524. .. [1] https://en.wikipedia.org/wiki/Opening_%28morphology%29
  525. .. [2] https://en.wikipedia.org/wiki/Mathematical_morphology
  526. Examples
  527. --------
  528. >>> from scipy import ndimage
  529. >>> a = np.zeros((5,5), dtype=int)
  530. >>> a[1:4, 1:4] = 1; a[4, 4] = 1
  531. >>> a
  532. array([[0, 0, 0, 0, 0],
  533. [0, 1, 1, 1, 0],
  534. [0, 1, 1, 1, 0],
  535. [0, 1, 1, 1, 0],
  536. [0, 0, 0, 0, 1]])
  537. >>> # Opening removes small objects
  538. >>> ndimage.binary_opening(a, structure=np.ones((3,3))).astype(int)
  539. array([[0, 0, 0, 0, 0],
  540. [0, 1, 1, 1, 0],
  541. [0, 1, 1, 1, 0],
  542. [0, 1, 1, 1, 0],
  543. [0, 0, 0, 0, 0]])
  544. >>> # Opening can also smooth corners
  545. >>> ndimage.binary_opening(a).astype(int)
  546. array([[0, 0, 0, 0, 0],
  547. [0, 0, 1, 0, 0],
  548. [0, 1, 1, 1, 0],
  549. [0, 0, 1, 0, 0],
  550. [0, 0, 0, 0, 0]])
  551. >>> # Opening is the dilation of the erosion of the input
  552. >>> ndimage.binary_erosion(a).astype(int)
  553. array([[0, 0, 0, 0, 0],
  554. [0, 0, 0, 0, 0],
  555. [0, 0, 1, 0, 0],
  556. [0, 0, 0, 0, 0],
  557. [0, 0, 0, 0, 0]])
  558. >>> ndimage.binary_dilation(ndimage.binary_erosion(a)).astype(int)
  559. array([[0, 0, 0, 0, 0],
  560. [0, 0, 1, 0, 0],
  561. [0, 1, 1, 1, 0],
  562. [0, 0, 1, 0, 0],
  563. [0, 0, 0, 0, 0]])
  564. """
  565. input = numpy.asarray(input)
  566. if structure is None:
  567. rank = input.ndim
  568. structure = generate_binary_structure(rank, 1)
  569. tmp = binary_erosion(input, structure, iterations, mask, None,
  570. border_value, origin, brute_force)
  571. return binary_dilation(tmp, structure, iterations, mask, output,
  572. border_value, origin, brute_force)
  573. def binary_closing(input, structure=None, iterations=1, output=None,
  574. origin=0, mask=None, border_value=0, brute_force=False):
  575. """
  576. Multi-dimensional binary closing with the given structuring element.
  577. The *closing* of an input image by a structuring element is the
  578. *erosion* of the *dilation* of the image by the structuring element.
  579. Parameters
  580. ----------
  581. input : array_like
  582. Binary array_like to be closed. Non-zero (True) elements form
  583. the subset to be closed.
  584. structure : array_like, optional
  585. Structuring element used for the closing. Non-zero elements are
  586. considered True. If no structuring element is provided an element
  587. is generated with a square connectivity equal to one (i.e., only
  588. nearest neighbors are connected to the center, diagonally-connected
  589. elements are not considered neighbors).
  590. iterations : {int, float}, optional
  591. The dilation step of the closing, then the erosion step are each
  592. repeated `iterations` times (one, by default). If iterations is
  593. less than 1, each operations is repeated until the result does
  594. not change anymore.
  595. output : ndarray, optional
  596. Array of the same shape as input, into which the output is placed.
  597. By default, a new array is created.
  598. origin : int or tuple of ints, optional
  599. Placement of the filter, by default 0.
  600. mask : array_like, optional
  601. If a mask is given, only those elements with a True value at
  602. the corresponding mask element are modified at each iteration.
  603. .. versionadded:: 1.1.0
  604. border_value : int (cast to 0 or 1), optional
  605. Value at the border in the output array.
  606. .. versionadded:: 1.1.0
  607. brute_force : boolean, optional
  608. Memory condition: if False, only the pixels whose value was changed in
  609. the last iteration are tracked as candidates to be updated in the
  610. current iteration; if true al pixels are considered as candidates for
  611. update, regardless of what happened in the previous iteration.
  612. False by default.
  613. .. versionadded:: 1.1.0
  614. Returns
  615. -------
  616. binary_closing : ndarray of bools
  617. Closing of the input by the structuring element.
  618. See also
  619. --------
  620. grey_closing, binary_opening, binary_dilation, binary_erosion,
  621. generate_binary_structure
  622. Notes
  623. -----
  624. *Closing* [1]_ is a mathematical morphology operation [2]_ that
  625. consists in the succession of a dilation and an erosion of the
  626. input with the same structuring element. Closing therefore fills
  627. holes smaller than the structuring element.
  628. Together with *opening* (`binary_opening`), closing can be used for
  629. noise removal.
  630. References
  631. ----------
  632. .. [1] https://en.wikipedia.org/wiki/Closing_%28morphology%29
  633. .. [2] https://en.wikipedia.org/wiki/Mathematical_morphology
  634. Examples
  635. --------
  636. >>> from scipy import ndimage
  637. >>> a = np.zeros((5,5), dtype=int)
  638. >>> a[1:-1, 1:-1] = 1; a[2,2] = 0
  639. >>> a
  640. array([[0, 0, 0, 0, 0],
  641. [0, 1, 1, 1, 0],
  642. [0, 1, 0, 1, 0],
  643. [0, 1, 1, 1, 0],
  644. [0, 0, 0, 0, 0]])
  645. >>> # Closing removes small holes
  646. >>> ndimage.binary_closing(a).astype(int)
  647. array([[0, 0, 0, 0, 0],
  648. [0, 1, 1, 1, 0],
  649. [0, 1, 1, 1, 0],
  650. [0, 1, 1, 1, 0],
  651. [0, 0, 0, 0, 0]])
  652. >>> # Closing is the erosion of the dilation of the input
  653. >>> ndimage.binary_dilation(a).astype(int)
  654. array([[0, 1, 1, 1, 0],
  655. [1, 1, 1, 1, 1],
  656. [1, 1, 1, 1, 1],
  657. [1, 1, 1, 1, 1],
  658. [0, 1, 1, 1, 0]])
  659. >>> ndimage.binary_erosion(ndimage.binary_dilation(a)).astype(int)
  660. array([[0, 0, 0, 0, 0],
  661. [0, 1, 1, 1, 0],
  662. [0, 1, 1, 1, 0],
  663. [0, 1, 1, 1, 0],
  664. [0, 0, 0, 0, 0]])
  665. >>> a = np.zeros((7,7), dtype=int)
  666. >>> a[1:6, 2:5] = 1; a[1:3,3] = 0
  667. >>> a
  668. array([[0, 0, 0, 0, 0, 0, 0],
  669. [0, 0, 1, 0, 1, 0, 0],
  670. [0, 0, 1, 0, 1, 0, 0],
  671. [0, 0, 1, 1, 1, 0, 0],
  672. [0, 0, 1, 1, 1, 0, 0],
  673. [0, 0, 1, 1, 1, 0, 0],
  674. [0, 0, 0, 0, 0, 0, 0]])
  675. >>> # In addition to removing holes, closing can also
  676. >>> # coarsen boundaries with fine hollows.
  677. >>> ndimage.binary_closing(a).astype(int)
  678. array([[0, 0, 0, 0, 0, 0, 0],
  679. [0, 0, 1, 0, 1, 0, 0],
  680. [0, 0, 1, 1, 1, 0, 0],
  681. [0, 0, 1, 1, 1, 0, 0],
  682. [0, 0, 1, 1, 1, 0, 0],
  683. [0, 0, 1, 1, 1, 0, 0],
  684. [0, 0, 0, 0, 0, 0, 0]])
  685. >>> ndimage.binary_closing(a, structure=np.ones((2,2))).astype(int)
  686. array([[0, 0, 0, 0, 0, 0, 0],
  687. [0, 0, 1, 1, 1, 0, 0],
  688. [0, 0, 1, 1, 1, 0, 0],
  689. [0, 0, 1, 1, 1, 0, 0],
  690. [0, 0, 1, 1, 1, 0, 0],
  691. [0, 0, 1, 1, 1, 0, 0],
  692. [0, 0, 0, 0, 0, 0, 0]])
  693. """
  694. input = numpy.asarray(input)
  695. if structure is None:
  696. rank = input.ndim
  697. structure = generate_binary_structure(rank, 1)
  698. tmp = binary_dilation(input, structure, iterations, mask, None,
  699. border_value, origin, brute_force)
  700. return binary_erosion(tmp, structure, iterations, mask, output,
  701. border_value, origin, brute_force)
  702. def binary_hit_or_miss(input, structure1=None, structure2=None,
  703. output=None, origin1=0, origin2=None):
  704. """
  705. Multi-dimensional binary hit-or-miss transform.
  706. The hit-or-miss transform finds the locations of a given pattern
  707. inside the input image.
  708. Parameters
  709. ----------
  710. input : array_like (cast to booleans)
  711. Binary image where a pattern is to be detected.
  712. structure1 : array_like (cast to booleans), optional
  713. Part of the structuring element to be fitted to the foreground
  714. (non-zero elements) of `input`. If no value is provided, a
  715. structure of square connectivity 1 is chosen.
  716. structure2 : array_like (cast to booleans), optional
  717. Second part of the structuring element that has to miss completely
  718. the foreground. If no value is provided, the complementary of
  719. `structure1` is taken.
  720. output : ndarray, optional
  721. Array of the same shape as input, into which the output is placed.
  722. By default, a new array is created.
  723. origin1 : int or tuple of ints, optional
  724. Placement of the first part of the structuring element `structure1`,
  725. by default 0 for a centered structure.
  726. origin2 : int or tuple of ints, optional
  727. Placement of the second part of the structuring element `structure2`,
  728. by default 0 for a centered structure. If a value is provided for
  729. `origin1` and not for `origin2`, then `origin2` is set to `origin1`.
  730. Returns
  731. -------
  732. binary_hit_or_miss : ndarray
  733. Hit-or-miss transform of `input` with the given structuring
  734. element (`structure1`, `structure2`).
  735. See also
  736. --------
  737. ndimage.morphology, binary_erosion
  738. References
  739. ----------
  740. .. [1] https://en.wikipedia.org/wiki/Hit-or-miss_transform
  741. Examples
  742. --------
  743. >>> from scipy import ndimage
  744. >>> a = np.zeros((7,7), dtype=int)
  745. >>> a[1, 1] = 1; a[2:4, 2:4] = 1; a[4:6, 4:6] = 1
  746. >>> a
  747. array([[0, 0, 0, 0, 0, 0, 0],
  748. [0, 1, 0, 0, 0, 0, 0],
  749. [0, 0, 1, 1, 0, 0, 0],
  750. [0, 0, 1, 1, 0, 0, 0],
  751. [0, 0, 0, 0, 1, 1, 0],
  752. [0, 0, 0, 0, 1, 1, 0],
  753. [0, 0, 0, 0, 0, 0, 0]])
  754. >>> structure1 = np.array([[1, 0, 0], [0, 1, 1], [0, 1, 1]])
  755. >>> structure1
  756. array([[1, 0, 0],
  757. [0, 1, 1],
  758. [0, 1, 1]])
  759. >>> # Find the matches of structure1 in the array a
  760. >>> ndimage.binary_hit_or_miss(a, structure1=structure1).astype(int)
  761. array([[0, 0, 0, 0, 0, 0, 0],
  762. [0, 0, 0, 0, 0, 0, 0],
  763. [0, 0, 1, 0, 0, 0, 0],
  764. [0, 0, 0, 0, 0, 0, 0],
  765. [0, 0, 0, 0, 1, 0, 0],
  766. [0, 0, 0, 0, 0, 0, 0],
  767. [0, 0, 0, 0, 0, 0, 0]])
  768. >>> # Change the origin of the filter
  769. >>> # origin1=1 is equivalent to origin1=(1,1) here
  770. >>> ndimage.binary_hit_or_miss(a, structure1=structure1,\\
  771. ... origin1=1).astype(int)
  772. array([[0, 0, 0, 0, 0, 0, 0],
  773. [0, 0, 0, 0, 0, 0, 0],
  774. [0, 0, 0, 0, 0, 0, 0],
  775. [0, 0, 0, 1, 0, 0, 0],
  776. [0, 0, 0, 0, 0, 0, 0],
  777. [0, 0, 0, 0, 0, 1, 0],
  778. [0, 0, 0, 0, 0, 0, 0]])
  779. """
  780. input = numpy.asarray(input)
  781. if structure1 is None:
  782. structure1 = generate_binary_structure(input.ndim, 1)
  783. if structure2 is None:
  784. structure2 = numpy.logical_not(structure1)
  785. origin1 = _ni_support._normalize_sequence(origin1, input.ndim)
  786. if origin2 is None:
  787. origin2 = origin1
  788. else:
  789. origin2 = _ni_support._normalize_sequence(origin2, input.ndim)
  790. tmp1 = _binary_erosion(input, structure1, 1, None, None, 0, origin1,
  791. 0, False)
  792. inplace = isinstance(output, numpy.ndarray)
  793. result = _binary_erosion(input, structure2, 1, None, output, 0,
  794. origin2, 1, False)
  795. if inplace:
  796. numpy.logical_not(output, output)
  797. numpy.logical_and(tmp1, output, output)
  798. else:
  799. numpy.logical_not(result, result)
  800. return numpy.logical_and(tmp1, result)
  801. def binary_propagation(input, structure=None, mask=None,
  802. output=None, border_value=0, origin=0):
  803. """
  804. Multi-dimensional binary propagation with the given structuring element.
  805. Parameters
  806. ----------
  807. input : array_like
  808. Binary image to be propagated inside `mask`.
  809. structure : array_like, optional
  810. Structuring element used in the successive dilations. The output
  811. may depend on the structuring element, especially if `mask` has
  812. several connex components. If no structuring element is
  813. provided, an element is generated with a squared connectivity equal
  814. to one.
  815. mask : array_like, optional
  816. Binary mask defining the region into which `input` is allowed to
  817. propagate.
  818. output : ndarray, optional
  819. Array of the same shape as input, into which the output is placed.
  820. By default, a new array is created.
  821. border_value : int (cast to 0 or 1), optional
  822. Value at the border in the output array.
  823. origin : int or tuple of ints, optional
  824. Placement of the filter, by default 0.
  825. Returns
  826. -------
  827. binary_propagation : ndarray
  828. Binary propagation of `input` inside `mask`.
  829. Notes
  830. -----
  831. This function is functionally equivalent to calling binary_dilation
  832. with the number of iterations less than one: iterative dilation until
  833. the result does not change anymore.
  834. The succession of an erosion and propagation inside the original image
  835. can be used instead of an *opening* for deleting small objects while
  836. keeping the contours of larger objects untouched.
  837. References
  838. ----------
  839. .. [1] http://cmm.ensmp.fr/~serra/cours/pdf/en/ch6en.pdf, slide 15.
  840. .. [2] I.T. Young, J.J. Gerbrands, and L.J. van Vliet, "Fundamentals of
  841. image processing", 1998
  842. ftp://qiftp.tudelft.nl/DIPimage/docs/FIP2.3.pdf
  843. Examples
  844. --------
  845. >>> from scipy import ndimage
  846. >>> input = np.zeros((8, 8), dtype=int)
  847. >>> input[2, 2] = 1
  848. >>> mask = np.zeros((8, 8), dtype=int)
  849. >>> mask[1:4, 1:4] = mask[4, 4] = mask[6:8, 6:8] = 1
  850. >>> input
  851. array([[0, 0, 0, 0, 0, 0, 0, 0],
  852. [0, 0, 0, 0, 0, 0, 0, 0],
  853. [0, 0, 1, 0, 0, 0, 0, 0],
  854. [0, 0, 0, 0, 0, 0, 0, 0],
  855. [0, 0, 0, 0, 0, 0, 0, 0],
  856. [0, 0, 0, 0, 0, 0, 0, 0],
  857. [0, 0, 0, 0, 0, 0, 0, 0],
  858. [0, 0, 0, 0, 0, 0, 0, 0]])
  859. >>> mask
  860. array([[0, 0, 0, 0, 0, 0, 0, 0],
  861. [0, 1, 1, 1, 0, 0, 0, 0],
  862. [0, 1, 1, 1, 0, 0, 0, 0],
  863. [0, 1, 1, 1, 0, 0, 0, 0],
  864. [0, 0, 0, 0, 1, 0, 0, 0],
  865. [0, 0, 0, 0, 0, 0, 0, 0],
  866. [0, 0, 0, 0, 0, 0, 1, 1],
  867. [0, 0, 0, 0, 0, 0, 1, 1]])
  868. >>> ndimage.binary_propagation(input, mask=mask).astype(int)
  869. array([[0, 0, 0, 0, 0, 0, 0, 0],
  870. [0, 1, 1, 1, 0, 0, 0, 0],
  871. [0, 1, 1, 1, 0, 0, 0, 0],
  872. [0, 1, 1, 1, 0, 0, 0, 0],
  873. [0, 0, 0, 0, 0, 0, 0, 0],
  874. [0, 0, 0, 0, 0, 0, 0, 0],
  875. [0, 0, 0, 0, 0, 0, 0, 0],
  876. [0, 0, 0, 0, 0, 0, 0, 0]])
  877. >>> ndimage.binary_propagation(input, mask=mask,\\
  878. ... structure=np.ones((3,3))).astype(int)
  879. array([[0, 0, 0, 0, 0, 0, 0, 0],
  880. [0, 1, 1, 1, 0, 0, 0, 0],
  881. [0, 1, 1, 1, 0, 0, 0, 0],
  882. [0, 1, 1, 1, 0, 0, 0, 0],
  883. [0, 0, 0, 0, 1, 0, 0, 0],
  884. [0, 0, 0, 0, 0, 0, 0, 0],
  885. [0, 0, 0, 0, 0, 0, 0, 0],
  886. [0, 0, 0, 0, 0, 0, 0, 0]])
  887. >>> # Comparison between opening and erosion+propagation
  888. >>> a = np.zeros((6,6), dtype=int)
  889. >>> a[2:5, 2:5] = 1; a[0, 0] = 1; a[5, 5] = 1
  890. >>> a
  891. array([[1, 0, 0, 0, 0, 0],
  892. [0, 0, 0, 0, 0, 0],
  893. [0, 0, 1, 1, 1, 0],
  894. [0, 0, 1, 1, 1, 0],
  895. [0, 0, 1, 1, 1, 0],
  896. [0, 0, 0, 0, 0, 1]])
  897. >>> ndimage.binary_opening(a).astype(int)
  898. array([[0, 0, 0, 0, 0, 0],
  899. [0, 0, 0, 0, 0, 0],
  900. [0, 0, 0, 1, 0, 0],
  901. [0, 0, 1, 1, 1, 0],
  902. [0, 0, 0, 1, 0, 0],
  903. [0, 0, 0, 0, 0, 0]])
  904. >>> b = ndimage.binary_erosion(a)
  905. >>> b.astype(int)
  906. array([[0, 0, 0, 0, 0, 0],
  907. [0, 0, 0, 0, 0, 0],
  908. [0, 0, 0, 0, 0, 0],
  909. [0, 0, 0, 1, 0, 0],
  910. [0, 0, 0, 0, 0, 0],
  911. [0, 0, 0, 0, 0, 0]])
  912. >>> ndimage.binary_propagation(b, mask=a).astype(int)
  913. array([[0, 0, 0, 0, 0, 0],
  914. [0, 0, 0, 0, 0, 0],
  915. [0, 0, 1, 1, 1, 0],
  916. [0, 0, 1, 1, 1, 0],
  917. [0, 0, 1, 1, 1, 0],
  918. [0, 0, 0, 0, 0, 0]])
  919. """
  920. return binary_dilation(input, structure, -1, mask, output,
  921. border_value, origin)
  922. def binary_fill_holes(input, structure=None, output=None, origin=0):
  923. """
  924. Fill the holes in binary objects.
  925. Parameters
  926. ----------
  927. input : array_like
  928. n-dimensional binary array with holes to be filled
  929. structure : array_like, optional
  930. Structuring element used in the computation; large-size elements
  931. make computations faster but may miss holes separated from the
  932. background by thin regions. The default element (with a square
  933. connectivity equal to one) yields the intuitive result where all
  934. holes in the input have been filled.
  935. output : ndarray, optional
  936. Array of the same shape as input, into which the output is placed.
  937. By default, a new array is created.
  938. origin : int, tuple of ints, optional
  939. Position of the structuring element.
  940. Returns
  941. -------
  942. out : ndarray
  943. Transformation of the initial image `input` where holes have been
  944. filled.
  945. See also
  946. --------
  947. binary_dilation, binary_propagation, label
  948. Notes
  949. -----
  950. The algorithm used in this function consists in invading the complementary
  951. of the shapes in `input` from the outer boundary of the image,
  952. using binary dilations. Holes are not connected to the boundary and are
  953. therefore not invaded. The result is the complementary subset of the
  954. invaded region.
  955. References
  956. ----------
  957. .. [1] https://en.wikipedia.org/wiki/Mathematical_morphology
  958. Examples
  959. --------
  960. >>> from scipy import ndimage
  961. >>> a = np.zeros((5, 5), dtype=int)
  962. >>> a[1:4, 1:4] = 1
  963. >>> a[2,2] = 0
  964. >>> a
  965. array([[0, 0, 0, 0, 0],
  966. [0, 1, 1, 1, 0],
  967. [0, 1, 0, 1, 0],
  968. [0, 1, 1, 1, 0],
  969. [0, 0, 0, 0, 0]])
  970. >>> ndimage.binary_fill_holes(a).astype(int)
  971. array([[0, 0, 0, 0, 0],
  972. [0, 1, 1, 1, 0],
  973. [0, 1, 1, 1, 0],
  974. [0, 1, 1, 1, 0],
  975. [0, 0, 0, 0, 0]])
  976. >>> # Too big structuring element
  977. >>> ndimage.binary_fill_holes(a, structure=np.ones((5,5))).astype(int)
  978. array([[0, 0, 0, 0, 0],
  979. [0, 1, 1, 1, 0],
  980. [0, 1, 0, 1, 0],
  981. [0, 1, 1, 1, 0],
  982. [0, 0, 0, 0, 0]])
  983. """
  984. mask = numpy.logical_not(input)
  985. tmp = numpy.zeros(mask.shape, bool)
  986. inplace = isinstance(output, numpy.ndarray)
  987. if inplace:
  988. binary_dilation(tmp, structure, -1, mask, output, 1, origin)
  989. numpy.logical_not(output, output)
  990. else:
  991. output = binary_dilation(tmp, structure, -1, mask, None, 1,
  992. origin)
  993. numpy.logical_not(output, output)
  994. return output
  995. def grey_erosion(input, size=None, footprint=None, structure=None,
  996. output=None, mode="reflect", cval=0.0, origin=0):
  997. """
  998. Calculate a greyscale erosion, using either a structuring element,
  999. or a footprint corresponding to a flat structuring element.
  1000. Grayscale erosion is a mathematical morphology operation. For the
  1001. simple case of a full and flat structuring element, it can be viewed
  1002. as a minimum filter over a sliding window.
  1003. Parameters
  1004. ----------
  1005. input : array_like
  1006. Array over which the grayscale erosion is to be computed.
  1007. size : tuple of ints
  1008. Shape of a flat and full structuring element used for the grayscale
  1009. erosion. Optional if `footprint` or `structure` is provided.
  1010. footprint : array of ints, optional
  1011. Positions of non-infinite elements of a flat structuring element
  1012. used for the grayscale erosion. Non-zero values give the set of
  1013. neighbors of the center over which the minimum is chosen.
  1014. structure : array of ints, optional
  1015. Structuring element used for the grayscale erosion. `structure`
  1016. may be a non-flat structuring element.
  1017. output : array, optional
  1018. An array used for storing the output of the erosion may be provided.
  1019. mode : {'reflect','constant','nearest','mirror', 'wrap'}, optional
  1020. The `mode` parameter determines how the array borders are
  1021. handled, where `cval` is the value when mode is equal to
  1022. 'constant'. Default is 'reflect'
  1023. cval : scalar, optional
  1024. Value to fill past edges of input if `mode` is 'constant'. Default
  1025. is 0.0.
  1026. origin : scalar, optional
  1027. The `origin` parameter controls the placement of the filter.
  1028. Default 0
  1029. Returns
  1030. -------
  1031. output : ndarray
  1032. Grayscale erosion of `input`.
  1033. See also
  1034. --------
  1035. binary_erosion, grey_dilation, grey_opening, grey_closing
  1036. generate_binary_structure, ndimage.minimum_filter
  1037. Notes
  1038. -----
  1039. The grayscale erosion of an image input by a structuring element s defined
  1040. over a domain E is given by:
  1041. (input+s)(x) = min {input(y) - s(x-y), for y in E}
  1042. In particular, for structuring elements defined as
  1043. s(y) = 0 for y in E, the grayscale erosion computes the minimum of the
  1044. input image inside a sliding window defined by E.
  1045. Grayscale erosion [1]_ is a *mathematical morphology* operation [2]_.
  1046. References
  1047. ----------
  1048. .. [1] https://en.wikipedia.org/wiki/Erosion_%28morphology%29
  1049. .. [2] https://en.wikipedia.org/wiki/Mathematical_morphology
  1050. Examples
  1051. --------
  1052. >>> from scipy import ndimage
  1053. >>> a = np.zeros((7,7), dtype=int)
  1054. >>> a[1:6, 1:6] = 3
  1055. >>> a[4,4] = 2; a[2,3] = 1
  1056. >>> a
  1057. array([[0, 0, 0, 0, 0, 0, 0],
  1058. [0, 3, 3, 3, 3, 3, 0],
  1059. [0, 3, 3, 1, 3, 3, 0],
  1060. [0, 3, 3, 3, 3, 3, 0],
  1061. [0, 3, 3, 3, 2, 3, 0],
  1062. [0, 3, 3, 3, 3, 3, 0],
  1063. [0, 0, 0, 0, 0, 0, 0]])
  1064. >>> ndimage.grey_erosion(a, size=(3,3))
  1065. array([[0, 0, 0, 0, 0, 0, 0],
  1066. [0, 0, 0, 0, 0, 0, 0],
  1067. [0, 0, 1, 1, 1, 0, 0],
  1068. [0, 0, 1, 1, 1, 0, 0],
  1069. [0, 0, 3, 2, 2, 0, 0],
  1070. [0, 0, 0, 0, 0, 0, 0],
  1071. [0, 0, 0, 0, 0, 0, 0]])
  1072. >>> footprint = ndimage.generate_binary_structure(2, 1)
  1073. >>> footprint
  1074. array([[False, True, False],
  1075. [ True, True, True],
  1076. [False, True, False]], dtype=bool)
  1077. >>> # Diagonally-connected elements are not considered neighbors
  1078. >>> ndimage.grey_erosion(a, size=(3,3), footprint=footprint)
  1079. array([[0, 0, 0, 0, 0, 0, 0],
  1080. [0, 0, 0, 0, 0, 0, 0],
  1081. [0, 0, 1, 1, 1, 0, 0],
  1082. [0, 0, 3, 1, 2, 0, 0],
  1083. [0, 0, 3, 2, 2, 0, 0],
  1084. [0, 0, 0, 0, 0, 0, 0],
  1085. [0, 0, 0, 0, 0, 0, 0]])
  1086. """
  1087. if size is None and footprint is None and structure is None:
  1088. raise ValueError("size, footprint or structure must be specified")
  1089. return filters._min_or_max_filter(input, size, footprint, structure,
  1090. output, mode, cval, origin, 1)
  1091. def grey_dilation(input, size=None, footprint=None, structure=None,
  1092. output=None, mode="reflect", cval=0.0, origin=0):
  1093. """
  1094. Calculate a greyscale dilation, using either a structuring element,
  1095. or a footprint corresponding to a flat structuring element.
  1096. Grayscale dilation is a mathematical morphology operation. For the
  1097. simple case of a full and flat structuring element, it can be viewed
  1098. as a maximum filter over a sliding window.
  1099. Parameters
  1100. ----------
  1101. input : array_like
  1102. Array over which the grayscale dilation is to be computed.
  1103. size : tuple of ints
  1104. Shape of a flat and full structuring element used for the grayscale
  1105. dilation. Optional if `footprint` or `structure` is provided.
  1106. footprint : array of ints, optional
  1107. Positions of non-infinite elements of a flat structuring element
  1108. used for the grayscale dilation. Non-zero values give the set of
  1109. neighbors of the center over which the maximum is chosen.
  1110. structure : array of ints, optional
  1111. Structuring element used for the grayscale dilation. `structure`
  1112. may be a non-flat structuring element.
  1113. output : array, optional
  1114. An array used for storing the output of the dilation may be provided.
  1115. mode : {'reflect','constant','nearest','mirror', 'wrap'}, optional
  1116. The `mode` parameter determines how the array borders are
  1117. handled, where `cval` is the value when mode is equal to
  1118. 'constant'. Default is 'reflect'
  1119. cval : scalar, optional
  1120. Value to fill past edges of input if `mode` is 'constant'. Default
  1121. is 0.0.
  1122. origin : scalar, optional
  1123. The `origin` parameter controls the placement of the filter.
  1124. Default 0
  1125. Returns
  1126. -------
  1127. grey_dilation : ndarray
  1128. Grayscale dilation of `input`.
  1129. See also
  1130. --------
  1131. binary_dilation, grey_erosion, grey_closing, grey_opening
  1132. generate_binary_structure, ndimage.maximum_filter
  1133. Notes
  1134. -----
  1135. The grayscale dilation of an image input by a structuring element s defined
  1136. over a domain E is given by:
  1137. (input+s)(x) = max {input(y) + s(x-y), for y in E}
  1138. In particular, for structuring elements defined as
  1139. s(y) = 0 for y in E, the grayscale dilation computes the maximum of the
  1140. input image inside a sliding window defined by E.
  1141. Grayscale dilation [1]_ is a *mathematical morphology* operation [2]_.
  1142. References
  1143. ----------
  1144. .. [1] https://en.wikipedia.org/wiki/Dilation_%28morphology%29
  1145. .. [2] https://en.wikipedia.org/wiki/Mathematical_morphology
  1146. Examples
  1147. --------
  1148. >>> from scipy import ndimage
  1149. >>> a = np.zeros((7,7), dtype=int)
  1150. >>> a[2:5, 2:5] = 1
  1151. >>> a[4,4] = 2; a[2,3] = 3
  1152. >>> a
  1153. array([[0, 0, 0, 0, 0, 0, 0],
  1154. [0, 0, 0, 0, 0, 0, 0],
  1155. [0, 0, 1, 3, 1, 0, 0],
  1156. [0, 0, 1, 1, 1, 0, 0],
  1157. [0, 0, 1, 1, 2, 0, 0],
  1158. [0, 0, 0, 0, 0, 0, 0],
  1159. [0, 0, 0, 0, 0, 0, 0]])
  1160. >>> ndimage.grey_dilation(a, size=(3,3))
  1161. array([[0, 0, 0, 0, 0, 0, 0],
  1162. [0, 1, 3, 3, 3, 1, 0],
  1163. [0, 1, 3, 3, 3, 1, 0],
  1164. [0, 1, 3, 3, 3, 2, 0],
  1165. [0, 1, 1, 2, 2, 2, 0],
  1166. [0, 1, 1, 2, 2, 2, 0],
  1167. [0, 0, 0, 0, 0, 0, 0]])
  1168. >>> ndimage.grey_dilation(a, footprint=np.ones((3,3)))
  1169. array([[0, 0, 0, 0, 0, 0, 0],
  1170. [0, 1, 3, 3, 3, 1, 0],
  1171. [0, 1, 3, 3, 3, 1, 0],
  1172. [0, 1, 3, 3, 3, 2, 0],
  1173. [0, 1, 1, 2, 2, 2, 0],
  1174. [0, 1, 1, 2, 2, 2, 0],
  1175. [0, 0, 0, 0, 0, 0, 0]])
  1176. >>> s = ndimage.generate_binary_structure(2,1)
  1177. >>> s
  1178. array([[False, True, False],
  1179. [ True, True, True],
  1180. [False, True, False]], dtype=bool)
  1181. >>> ndimage.grey_dilation(a, footprint=s)
  1182. array([[0, 0, 0, 0, 0, 0, 0],
  1183. [0, 0, 1, 3, 1, 0, 0],
  1184. [0, 1, 3, 3, 3, 1, 0],
  1185. [0, 1, 1, 3, 2, 1, 0],
  1186. [0, 1, 1, 2, 2, 2, 0],
  1187. [0, 0, 1, 1, 2, 0, 0],
  1188. [0, 0, 0, 0, 0, 0, 0]])
  1189. >>> ndimage.grey_dilation(a, size=(3,3), structure=np.ones((3,3)))
  1190. array([[1, 1, 1, 1, 1, 1, 1],
  1191. [1, 2, 4, 4, 4, 2, 1],
  1192. [1, 2, 4, 4, 4, 2, 1],
  1193. [1, 2, 4, 4, 4, 3, 1],
  1194. [1, 2, 2, 3, 3, 3, 1],
  1195. [1, 2, 2, 3, 3, 3, 1],
  1196. [1, 1, 1, 1, 1, 1, 1]])
  1197. """
  1198. if size is None and footprint is None and structure is None:
  1199. raise ValueError("size, footprint or structure must be specified")
  1200. if structure is not None:
  1201. structure = numpy.asarray(structure)
  1202. structure = structure[tuple([slice(None, None, -1)] *
  1203. structure.ndim)]
  1204. if footprint is not None:
  1205. footprint = numpy.asarray(footprint)
  1206. footprint = footprint[tuple([slice(None, None, -1)] *
  1207. footprint.ndim)]
  1208. input = numpy.asarray(input)
  1209. origin = _ni_support._normalize_sequence(origin, input.ndim)
  1210. for ii in range(len(origin)):
  1211. origin[ii] = -origin[ii]
  1212. if footprint is not None:
  1213. sz = footprint.shape[ii]
  1214. elif structure is not None:
  1215. sz = structure.shape[ii]
  1216. elif numpy.isscalar(size):
  1217. sz = size
  1218. else:
  1219. sz = size[ii]
  1220. if not sz & 1:
  1221. origin[ii] -= 1
  1222. return filters._min_or_max_filter(input, size, footprint, structure,
  1223. output, mode, cval, origin, 0)
  1224. def grey_opening(input, size=None, footprint=None, structure=None,
  1225. output=None, mode="reflect", cval=0.0, origin=0):
  1226. """
  1227. Multi-dimensional greyscale opening.
  1228. A greyscale opening consists in the succession of a greyscale erosion,
  1229. and a greyscale dilation.
  1230. Parameters
  1231. ----------
  1232. input : array_like
  1233. Array over which the grayscale opening is to be computed.
  1234. size : tuple of ints
  1235. Shape of a flat and full structuring element used for the grayscale
  1236. opening. Optional if `footprint` or `structure` is provided.
  1237. footprint : array of ints, optional
  1238. Positions of non-infinite elements of a flat structuring element
  1239. used for the grayscale opening.
  1240. structure : array of ints, optional
  1241. Structuring element used for the grayscale opening. `structure`
  1242. may be a non-flat structuring element.
  1243. output : array, optional
  1244. An array used for storing the output of the opening may be provided.
  1245. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
  1246. The `mode` parameter determines how the array borders are
  1247. handled, where `cval` is the value when mode is equal to
  1248. 'constant'. Default is 'reflect'
  1249. cval : scalar, optional
  1250. Value to fill past edges of input if `mode` is 'constant'. Default
  1251. is 0.0.
  1252. origin : scalar, optional
  1253. The `origin` parameter controls the placement of the filter.
  1254. Default 0
  1255. Returns
  1256. -------
  1257. grey_opening : ndarray
  1258. Result of the grayscale opening of `input` with `structure`.
  1259. See also
  1260. --------
  1261. binary_opening, grey_dilation, grey_erosion, grey_closing
  1262. generate_binary_structure
  1263. Notes
  1264. -----
  1265. The action of a grayscale opening with a flat structuring element amounts
  1266. to smoothen high local maxima, whereas binary opening erases small objects.
  1267. References
  1268. ----------
  1269. .. [1] https://en.wikipedia.org/wiki/Mathematical_morphology
  1270. Examples
  1271. --------
  1272. >>> from scipy import ndimage
  1273. >>> a = np.arange(36).reshape((6,6))
  1274. >>> a[3, 3] = 50
  1275. >>> a
  1276. array([[ 0, 1, 2, 3, 4, 5],
  1277. [ 6, 7, 8, 9, 10, 11],
  1278. [12, 13, 14, 15, 16, 17],
  1279. [18, 19, 20, 50, 22, 23],
  1280. [24, 25, 26, 27, 28, 29],
  1281. [30, 31, 32, 33, 34, 35]])
  1282. >>> ndimage.grey_opening(a, size=(3,3))
  1283. array([[ 0, 1, 2, 3, 4, 4],
  1284. [ 6, 7, 8, 9, 10, 10],
  1285. [12, 13, 14, 15, 16, 16],
  1286. [18, 19, 20, 22, 22, 22],
  1287. [24, 25, 26, 27, 28, 28],
  1288. [24, 25, 26, 27, 28, 28]])
  1289. >>> # Note that the local maximum a[3,3] has disappeared
  1290. """
  1291. if (size is not None) and (footprint is not None):
  1292. warnings.warn("ignoring size because footprint is set", UserWarning, stacklevel=2)
  1293. tmp = grey_erosion(input, size, footprint, structure, None, mode,
  1294. cval, origin)
  1295. return grey_dilation(tmp, size, footprint, structure, output, mode,
  1296. cval, origin)
  1297. def grey_closing(input, size=None, footprint=None, structure=None,
  1298. output=None, mode="reflect", cval=0.0, origin=0):
  1299. """
  1300. Multi-dimensional greyscale closing.
  1301. A greyscale closing consists in the succession of a greyscale dilation,
  1302. and a greyscale erosion.
  1303. Parameters
  1304. ----------
  1305. input : array_like
  1306. Array over which the grayscale closing is to be computed.
  1307. size : tuple of ints
  1308. Shape of a flat and full structuring element used for the grayscale
  1309. closing. Optional if `footprint` or `structure` is provided.
  1310. footprint : array of ints, optional
  1311. Positions of non-infinite elements of a flat structuring element
  1312. used for the grayscale closing.
  1313. structure : array of ints, optional
  1314. Structuring element used for the grayscale closing. `structure`
  1315. may be a non-flat structuring element.
  1316. output : array, optional
  1317. An array used for storing the output of the closing may be provided.
  1318. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
  1319. The `mode` parameter determines how the array borders are
  1320. handled, where `cval` is the value when mode is equal to
  1321. 'constant'. Default is 'reflect'
  1322. cval : scalar, optional
  1323. Value to fill past edges of input if `mode` is 'constant'. Default
  1324. is 0.0.
  1325. origin : scalar, optional
  1326. The `origin` parameter controls the placement of the filter.
  1327. Default 0
  1328. Returns
  1329. -------
  1330. grey_closing : ndarray
  1331. Result of the grayscale closing of `input` with `structure`.
  1332. See also
  1333. --------
  1334. binary_closing, grey_dilation, grey_erosion, grey_opening,
  1335. generate_binary_structure
  1336. Notes
  1337. -----
  1338. The action of a grayscale closing with a flat structuring element amounts
  1339. to smoothen deep local minima, whereas binary closing fills small holes.
  1340. References
  1341. ----------
  1342. .. [1] https://en.wikipedia.org/wiki/Mathematical_morphology
  1343. Examples
  1344. --------
  1345. >>> from scipy import ndimage
  1346. >>> a = np.arange(36).reshape((6,6))
  1347. >>> a[3,3] = 0
  1348. >>> a
  1349. array([[ 0, 1, 2, 3, 4, 5],
  1350. [ 6, 7, 8, 9, 10, 11],
  1351. [12, 13, 14, 15, 16, 17],
  1352. [18, 19, 20, 0, 22, 23],
  1353. [24, 25, 26, 27, 28, 29],
  1354. [30, 31, 32, 33, 34, 35]])
  1355. >>> ndimage.grey_closing(a, size=(3,3))
  1356. array([[ 7, 7, 8, 9, 10, 11],
  1357. [ 7, 7, 8, 9, 10, 11],
  1358. [13, 13, 14, 15, 16, 17],
  1359. [19, 19, 20, 20, 22, 23],
  1360. [25, 25, 26, 27, 28, 29],
  1361. [31, 31, 32, 33, 34, 35]])
  1362. >>> # Note that the local minimum a[3,3] has disappeared
  1363. """
  1364. if (size is not None) and (footprint is not None):
  1365. warnings.warn("ignoring size because footprint is set", UserWarning, stacklevel=2)
  1366. tmp = grey_dilation(input, size, footprint, structure, None, mode,
  1367. cval, origin)
  1368. return grey_erosion(tmp, size, footprint, structure, output, mode,
  1369. cval, origin)
  1370. def morphological_gradient(input, size=None, footprint=None, structure=None,
  1371. output=None, mode="reflect", cval=0.0, origin=0):
  1372. """
  1373. Multi-dimensional morphological gradient.
  1374. The morphological gradient is calculated as the difference between a
  1375. dilation and an erosion of the input with a given structuring element.
  1376. Parameters
  1377. ----------
  1378. input : array_like
  1379. Array over which to compute the morphlogical gradient.
  1380. size : tuple of ints
  1381. Shape of a flat and full structuring element used for the mathematical
  1382. morphology operations. Optional if `footprint` or `structure` is
  1383. provided. A larger `size` yields a more blurred gradient.
  1384. footprint : array of ints, optional
  1385. Positions of non-infinite elements of a flat structuring element
  1386. used for the morphology operations. Larger footprints
  1387. give a more blurred morphological gradient.
  1388. structure : array of ints, optional
  1389. Structuring element used for the morphology operations.
  1390. `structure` may be a non-flat structuring element.
  1391. output : array, optional
  1392. An array used for storing the output of the morphological gradient
  1393. may be provided.
  1394. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
  1395. The `mode` parameter determines how the array borders are
  1396. handled, where `cval` is the value when mode is equal to
  1397. 'constant'. Default is 'reflect'
  1398. cval : scalar, optional
  1399. Value to fill past edges of input if `mode` is 'constant'. Default
  1400. is 0.0.
  1401. origin : scalar, optional
  1402. The `origin` parameter controls the placement of the filter.
  1403. Default 0
  1404. Returns
  1405. -------
  1406. morphological_gradient : ndarray
  1407. Morphological gradient of `input`.
  1408. See also
  1409. --------
  1410. grey_dilation, grey_erosion, ndimage.gaussian_gradient_magnitude
  1411. Notes
  1412. -----
  1413. For a flat structuring element, the morphological gradient
  1414. computed at a given point corresponds to the maximal difference
  1415. between elements of the input among the elements covered by the
  1416. structuring element centered on the point.
  1417. References
  1418. ----------
  1419. .. [1] https://en.wikipedia.org/wiki/Mathematical_morphology
  1420. Examples
  1421. --------
  1422. >>> from scipy import ndimage
  1423. >>> a = np.zeros((7,7), dtype=int)
  1424. >>> a[2:5, 2:5] = 1
  1425. >>> ndimage.morphological_gradient(a, size=(3,3))
  1426. array([[0, 0, 0, 0, 0, 0, 0],
  1427. [0, 1, 1, 1, 1, 1, 0],
  1428. [0, 1, 1, 1, 1, 1, 0],
  1429. [0, 1, 1, 0, 1, 1, 0],
  1430. [0, 1, 1, 1, 1, 1, 0],
  1431. [0, 1, 1, 1, 1, 1, 0],
  1432. [0, 0, 0, 0, 0, 0, 0]])
  1433. >>> # The morphological gradient is computed as the difference
  1434. >>> # between a dilation and an erosion
  1435. >>> ndimage.grey_dilation(a, size=(3,3)) -\\
  1436. ... ndimage.grey_erosion(a, size=(3,3))
  1437. array([[0, 0, 0, 0, 0, 0, 0],
  1438. [0, 1, 1, 1, 1, 1, 0],
  1439. [0, 1, 1, 1, 1, 1, 0],
  1440. [0, 1, 1, 0, 1, 1, 0],
  1441. [0, 1, 1, 1, 1, 1, 0],
  1442. [0, 1, 1, 1, 1, 1, 0],
  1443. [0, 0, 0, 0, 0, 0, 0]])
  1444. >>> a = np.zeros((7,7), dtype=int)
  1445. >>> a[2:5, 2:5] = 1
  1446. >>> a[4,4] = 2; a[2,3] = 3
  1447. >>> a
  1448. array([[0, 0, 0, 0, 0, 0, 0],
  1449. [0, 0, 0, 0, 0, 0, 0],
  1450. [0, 0, 1, 3, 1, 0, 0],
  1451. [0, 0, 1, 1, 1, 0, 0],
  1452. [0, 0, 1, 1, 2, 0, 0],
  1453. [0, 0, 0, 0, 0, 0, 0],
  1454. [0, 0, 0, 0, 0, 0, 0]])
  1455. >>> ndimage.morphological_gradient(a, size=(3,3))
  1456. array([[0, 0, 0, 0, 0, 0, 0],
  1457. [0, 1, 3, 3, 3, 1, 0],
  1458. [0, 1, 3, 3, 3, 1, 0],
  1459. [0, 1, 3, 2, 3, 2, 0],
  1460. [0, 1, 1, 2, 2, 2, 0],
  1461. [0, 1, 1, 2, 2, 2, 0],
  1462. [0, 0, 0, 0, 0, 0, 0]])
  1463. """
  1464. tmp = grey_dilation(input, size, footprint, structure, None, mode,
  1465. cval, origin)
  1466. if isinstance(output, numpy.ndarray):
  1467. grey_erosion(input, size, footprint, structure, output, mode,
  1468. cval, origin)
  1469. return numpy.subtract(tmp, output, output)
  1470. else:
  1471. return (tmp - grey_erosion(input, size, footprint, structure,
  1472. None, mode, cval, origin))
  1473. def morphological_laplace(input, size=None, footprint=None,
  1474. structure=None, output=None,
  1475. mode="reflect", cval=0.0, origin=0):
  1476. """
  1477. Multi-dimensional morphological laplace.
  1478. Parameters
  1479. ----------
  1480. input : array_like
  1481. Input.
  1482. size : int or sequence of ints, optional
  1483. See `structure`.
  1484. footprint : bool or ndarray, optional
  1485. See `structure`.
  1486. structure : structure, optional
  1487. Either `size`, `footprint`, or the `structure` must be provided.
  1488. output : ndarray, optional
  1489. An output array can optionally be provided.
  1490. mode : {'reflect','constant','nearest','mirror', 'wrap'}, optional
  1491. The mode parameter determines how the array borders are handled.
  1492. For 'constant' mode, values beyond borders are set to be `cval`.
  1493. Default is 'reflect'.
  1494. cval : scalar, optional
  1495. Value to fill past edges of input if mode is 'constant'.
  1496. Default is 0.0
  1497. origin : origin, optional
  1498. The origin parameter controls the placement of the filter.
  1499. Returns
  1500. -------
  1501. morphological_laplace : ndarray
  1502. Output
  1503. """
  1504. tmp1 = grey_dilation(input, size, footprint, structure, None, mode,
  1505. cval, origin)
  1506. if isinstance(output, numpy.ndarray):
  1507. grey_erosion(input, size, footprint, structure, output, mode,
  1508. cval, origin)
  1509. numpy.add(tmp1, output, output)
  1510. numpy.subtract(output, input, output)
  1511. return numpy.subtract(output, input, output)
  1512. else:
  1513. tmp2 = grey_erosion(input, size, footprint, structure, None, mode,
  1514. cval, origin)
  1515. numpy.add(tmp1, tmp2, tmp2)
  1516. numpy.subtract(tmp2, input, tmp2)
  1517. numpy.subtract(tmp2, input, tmp2)
  1518. return tmp2
  1519. def white_tophat(input, size=None, footprint=None, structure=None,
  1520. output=None, mode="reflect", cval=0.0, origin=0):
  1521. """
  1522. Multi-dimensional white tophat filter.
  1523. Parameters
  1524. ----------
  1525. input : array_like
  1526. Input.
  1527. size : tuple of ints
  1528. Shape of a flat and full structuring element used for the filter.
  1529. Optional if `footprint` or `structure` is provided.
  1530. footprint : array of ints, optional
  1531. Positions of elements of a flat structuring element
  1532. used for the white tophat filter.
  1533. structure : array of ints, optional
  1534. Structuring element used for the filter. `structure`
  1535. may be a non-flat structuring element.
  1536. output : array, optional
  1537. An array used for storing the output of the filter may be provided.
  1538. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
  1539. The `mode` parameter determines how the array borders are
  1540. handled, where `cval` is the value when mode is equal to
  1541. 'constant'. Default is 'reflect'
  1542. cval : scalar, optional
  1543. Value to fill past edges of input if `mode` is 'constant'.
  1544. Default is 0.0.
  1545. origin : scalar, optional
  1546. The `origin` parameter controls the placement of the filter.
  1547. Default is 0.
  1548. Returns
  1549. -------
  1550. output : ndarray
  1551. Result of the filter of `input` with `structure`.
  1552. See also
  1553. --------
  1554. black_tophat
  1555. """
  1556. if (size is not None) and (footprint is not None):
  1557. warnings.warn("ignoring size because footprint is set", UserWarning, stacklevel=2)
  1558. tmp = grey_erosion(input, size, footprint, structure, None, mode,
  1559. cval, origin)
  1560. tmp = grey_dilation(tmp, size, footprint, structure, output, mode,
  1561. cval, origin)
  1562. if tmp is None:
  1563. tmp = output
  1564. if input.dtype == numpy.bool_ and tmp.dtype == numpy.bool_:
  1565. numpy.bitwise_xor(input, tmp, out=tmp)
  1566. else:
  1567. numpy.subtract(input, tmp, out=tmp)
  1568. return tmp
  1569. def black_tophat(input, size=None, footprint=None,
  1570. structure=None, output=None, mode="reflect",
  1571. cval=0.0, origin=0):
  1572. """
  1573. Multi-dimensional black tophat filter.
  1574. Parameters
  1575. ----------
  1576. input : array_like
  1577. Input.
  1578. size : tuple of ints, optional
  1579. Shape of a flat and full structuring element used for the filter.
  1580. Optional if `footprint` or `structure` is provided.
  1581. footprint : array of ints, optional
  1582. Positions of non-infinite elements of a flat structuring element
  1583. used for the black tophat filter.
  1584. structure : array of ints, optional
  1585. Structuring element used for the filter. `structure`
  1586. may be a non-flat structuring element.
  1587. output : array, optional
  1588. An array used for storing the output of the filter may be provided.
  1589. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
  1590. The `mode` parameter determines how the array borders are
  1591. handled, where `cval` is the value when mode is equal to
  1592. 'constant'. Default is 'reflect'
  1593. cval : scalar, optional
  1594. Value to fill past edges of input if `mode` is 'constant'. Default
  1595. is 0.0.
  1596. origin : scalar, optional
  1597. The `origin` parameter controls the placement of the filter.
  1598. Default 0
  1599. Returns
  1600. -------
  1601. black_tophat : ndarray
  1602. Result of the filter of `input` with `structure`.
  1603. See also
  1604. --------
  1605. white_tophat, grey_opening, grey_closing
  1606. """
  1607. if (size is not None) and (footprint is not None):
  1608. warnings.warn("ignoring size because footprint is set", UserWarning, stacklevel=2)
  1609. tmp = grey_dilation(input, size, footprint, structure, None, mode,
  1610. cval, origin)
  1611. tmp = grey_erosion(tmp, size, footprint, structure, output, mode,
  1612. cval, origin)
  1613. if tmp is None:
  1614. tmp = output
  1615. if input.dtype == numpy.bool_ and tmp.dtype == numpy.bool_:
  1616. numpy.bitwise_xor(tmp, input, out=tmp)
  1617. else:
  1618. numpy.subtract(tmp, input, out=tmp)
  1619. return tmp
  1620. def distance_transform_bf(input, metric="euclidean", sampling=None,
  1621. return_distances=True, return_indices=False,
  1622. distances=None, indices=None):
  1623. """
  1624. Distance transform function by a brute force algorithm.
  1625. This function calculates the distance transform of the `input`, by
  1626. replacing each foreground (non-zero) element, with its
  1627. shortest distance to the background (any zero-valued element).
  1628. In addition to the distance transform, the feature transform can
  1629. be calculated. In this case the index of the closest background
  1630. element is returned along the first axis of the result.
  1631. Parameters
  1632. ----------
  1633. input : array_like
  1634. Input
  1635. metric : str, optional
  1636. Three types of distance metric are supported: 'euclidean', 'taxicab'
  1637. and 'chessboard'.
  1638. sampling : {int, sequence of ints}, optional
  1639. This parameter is only used in the case of the euclidean `metric`
  1640. distance transform.
  1641. The sampling along each axis can be given by the `sampling` parameter
  1642. which should be a sequence of length equal to the input rank, or a
  1643. single number in which the `sampling` is assumed to be equal along all
  1644. axes.
  1645. return_distances : bool, optional
  1646. The `return_distances` flag can be used to indicate if the distance
  1647. transform is returned.
  1648. The default is True.
  1649. return_indices : bool, optional
  1650. The `return_indices` flags can be used to indicate if the feature
  1651. transform is returned.
  1652. The default is False.
  1653. distances : float64 ndarray, optional
  1654. Optional output array to hold distances (if `return_distances` is
  1655. True).
  1656. indices : int64 ndarray, optional
  1657. Optional output array to hold indices (if `return_indices` is True).
  1658. Returns
  1659. -------
  1660. distances : ndarray
  1661. Distance array if `return_distances` is True.
  1662. indices : ndarray
  1663. Indices array if `return_indices` is True.
  1664. Notes
  1665. -----
  1666. This function employs a slow brute force algorithm, see also the
  1667. function distance_transform_cdt for more efficient taxicab and
  1668. chessboard algorithms.
  1669. """
  1670. if (not return_distances) and (not return_indices):
  1671. msg = 'at least one of distances/indices must be specified'
  1672. raise RuntimeError(msg)
  1673. tmp1 = numpy.asarray(input) != 0
  1674. struct = generate_binary_structure(tmp1.ndim, tmp1.ndim)
  1675. tmp2 = binary_dilation(tmp1, struct)
  1676. tmp2 = numpy.logical_xor(tmp1, tmp2)
  1677. tmp1 = tmp1.astype(numpy.int8) - tmp2.astype(numpy.int8)
  1678. metric = metric.lower()
  1679. if metric == 'euclidean':
  1680. metric = 1
  1681. elif metric in ['taxicab', 'cityblock', 'manhattan']:
  1682. metric = 2
  1683. elif metric == 'chessboard':
  1684. metric = 3
  1685. else:
  1686. raise RuntimeError('distance metric not supported')
  1687. if sampling is not None:
  1688. sampling = _ni_support._normalize_sequence(sampling, tmp1.ndim)
  1689. sampling = numpy.asarray(sampling, dtype=numpy.float64)
  1690. if not sampling.flags.contiguous:
  1691. sampling = sampling.copy()
  1692. if return_indices:
  1693. ft = numpy.zeros(tmp1.shape, dtype=numpy.int32)
  1694. else:
  1695. ft = None
  1696. if return_distances:
  1697. if distances is None:
  1698. if metric == 1:
  1699. dt = numpy.zeros(tmp1.shape, dtype=numpy.float64)
  1700. else:
  1701. dt = numpy.zeros(tmp1.shape, dtype=numpy.uint32)
  1702. else:
  1703. if distances.shape != tmp1.shape:
  1704. raise RuntimeError('distances array has wrong shape')
  1705. if metric == 1:
  1706. if distances.dtype.type != numpy.float64:
  1707. raise RuntimeError('distances array must be float64')
  1708. else:
  1709. if distances.dtype.type != numpy.uint32:
  1710. raise RuntimeError('distances array must be uint32')
  1711. dt = distances
  1712. else:
  1713. dt = None
  1714. _nd_image.distance_transform_bf(tmp1, metric, sampling, dt, ft)
  1715. if return_indices:
  1716. if isinstance(indices, numpy.ndarray):
  1717. if indices.dtype.type != numpy.int32:
  1718. raise RuntimeError('indices must of int32 type')
  1719. if indices.shape != (tmp1.ndim,) + tmp1.shape:
  1720. raise RuntimeError('indices has wrong shape')
  1721. tmp2 = indices
  1722. else:
  1723. tmp2 = numpy.indices(tmp1.shape, dtype=numpy.int32)
  1724. ft = numpy.ravel(ft)
  1725. for ii in range(tmp2.shape[0]):
  1726. rtmp = numpy.ravel(tmp2[ii, ...])[ft]
  1727. rtmp.shape = tmp1.shape
  1728. tmp2[ii, ...] = rtmp
  1729. ft = tmp2
  1730. # construct and return the result
  1731. result = []
  1732. if return_distances and not isinstance(distances, numpy.ndarray):
  1733. result.append(dt)
  1734. if return_indices and not isinstance(indices, numpy.ndarray):
  1735. result.append(ft)
  1736. if len(result) == 2:
  1737. return tuple(result)
  1738. elif len(result) == 1:
  1739. return result[0]
  1740. else:
  1741. return None
  1742. def distance_transform_cdt(input, metric='chessboard', return_distances=True,
  1743. return_indices=False, distances=None, indices=None):
  1744. """
  1745. Distance transform for chamfer type of transforms.
  1746. Parameters
  1747. ----------
  1748. input : array_like
  1749. Input
  1750. metric : {'chessboard', 'taxicab'}, optional
  1751. The `metric` determines the type of chamfering that is done. If the
  1752. `metric` is equal to 'taxicab' a structure is generated using
  1753. generate_binary_structure with a squared distance equal to 1. If
  1754. the `metric` is equal to 'chessboard', a `metric` is generated
  1755. using generate_binary_structure with a squared distance equal to
  1756. the dimensionality of the array. These choices correspond to the
  1757. common interpretations of the 'taxicab' and the 'chessboard'
  1758. distance metrics in two dimensions.
  1759. The default for `metric` is 'chessboard'.
  1760. return_distances, return_indices : bool, optional
  1761. The `return_distances`, and `return_indices` flags can be used to
  1762. indicate if the distance transform, the feature transform, or both
  1763. must be returned.
  1764. If the feature transform is returned (``return_indices=True``),
  1765. the index of the closest background element is returned along
  1766. the first axis of the result.
  1767. The `return_distances` default is True, and the
  1768. `return_indices` default is False.
  1769. distances, indices : ndarrays of int32, optional
  1770. The `distances` and `indices` arguments can be used to give optional
  1771. output arrays that must be the same shape as `input`.
  1772. """
  1773. if (not return_distances) and (not return_indices):
  1774. msg = 'at least one of distances/indices must be specified'
  1775. raise RuntimeError(msg)
  1776. ft_inplace = isinstance(indices, numpy.ndarray)
  1777. dt_inplace = isinstance(distances, numpy.ndarray)
  1778. input = numpy.asarray(input)
  1779. if metric in ['taxicab', 'cityblock', 'manhattan']:
  1780. rank = input.ndim
  1781. metric = generate_binary_structure(rank, 1)
  1782. elif metric == 'chessboard':
  1783. rank = input.ndim
  1784. metric = generate_binary_structure(rank, rank)
  1785. else:
  1786. try:
  1787. metric = numpy.asarray(metric)
  1788. except Exception:
  1789. raise RuntimeError('invalid metric provided')
  1790. for s in metric.shape:
  1791. if s != 3:
  1792. raise RuntimeError('metric sizes must be equal to 3')
  1793. if not metric.flags.contiguous:
  1794. metric = metric.copy()
  1795. if dt_inplace:
  1796. if distances.dtype.type != numpy.int32:
  1797. raise RuntimeError('distances must be of int32 type')
  1798. if distances.shape != input.shape:
  1799. raise RuntimeError('distances has wrong shape')
  1800. dt = distances
  1801. dt[...] = numpy.where(input, -1, 0).astype(numpy.int32)
  1802. else:
  1803. dt = numpy.where(input, -1, 0).astype(numpy.int32)
  1804. rank = dt.ndim
  1805. if return_indices:
  1806. sz = numpy.product(dt.shape, axis=0)
  1807. ft = numpy.arange(sz, dtype=numpy.int32)
  1808. ft.shape = dt.shape
  1809. else:
  1810. ft = None
  1811. _nd_image.distance_transform_op(metric, dt, ft)
  1812. dt = dt[tuple([slice(None, None, -1)] * rank)]
  1813. if return_indices:
  1814. ft = ft[tuple([slice(None, None, -1)] * rank)]
  1815. _nd_image.distance_transform_op(metric, dt, ft)
  1816. dt = dt[tuple([slice(None, None, -1)] * rank)]
  1817. if return_indices:
  1818. ft = ft[tuple([slice(None, None, -1)] * rank)]
  1819. ft = numpy.ravel(ft)
  1820. if ft_inplace:
  1821. if indices.dtype.type != numpy.int32:
  1822. raise RuntimeError('indices must of int32 type')
  1823. if indices.shape != (dt.ndim,) + dt.shape:
  1824. raise RuntimeError('indices has wrong shape')
  1825. tmp = indices
  1826. else:
  1827. tmp = numpy.indices(dt.shape, dtype=numpy.int32)
  1828. for ii in range(tmp.shape[0]):
  1829. rtmp = numpy.ravel(tmp[ii, ...])[ft]
  1830. rtmp.shape = dt.shape
  1831. tmp[ii, ...] = rtmp
  1832. ft = tmp
  1833. # construct and return the result
  1834. result = []
  1835. if return_distances and not dt_inplace:
  1836. result.append(dt)
  1837. if return_indices and not ft_inplace:
  1838. result.append(ft)
  1839. if len(result) == 2:
  1840. return tuple(result)
  1841. elif len(result) == 1:
  1842. return result[0]
  1843. else:
  1844. return None
  1845. def distance_transform_edt(input, sampling=None, return_distances=True,
  1846. return_indices=False, distances=None, indices=None):
  1847. """
  1848. Exact euclidean distance transform.
  1849. In addition to the distance transform, the feature transform can
  1850. be calculated. In this case the index of the closest background
  1851. element is returned along the first axis of the result.
  1852. Parameters
  1853. ----------
  1854. input : array_like
  1855. Input data to transform. Can be any type but will be converted
  1856. into binary: 1 wherever input equates to True, 0 elsewhere.
  1857. sampling : float or int, or sequence of same, optional
  1858. Spacing of elements along each dimension. If a sequence, must be of
  1859. length equal to the input rank; if a single number, this is used for
  1860. all axes. If not specified, a grid spacing of unity is implied.
  1861. return_distances : bool, optional
  1862. Whether to return distance matrix. At least one of
  1863. return_distances/return_indices must be True. Default is True.
  1864. return_indices : bool, optional
  1865. Whether to return indices matrix. Default is False.
  1866. distances : ndarray, optional
  1867. Used for output of distance array, must be of type float64.
  1868. indices : ndarray, optional
  1869. Used for output of indices, must be of type int32.
  1870. Returns
  1871. -------
  1872. distance_transform_edt : ndarray or list of ndarrays
  1873. Either distance matrix, index matrix, or a list of the two,
  1874. depending on `return_x` flags and `distance` and `indices`
  1875. input parameters.
  1876. Notes
  1877. -----
  1878. The euclidean distance transform gives values of the euclidean
  1879. distance::
  1880. n
  1881. y_i = sqrt(sum (x[i]-b[i])**2)
  1882. i
  1883. where b[i] is the background point (value 0) with the smallest
  1884. Euclidean distance to input points x[i], and n is the
  1885. number of dimensions.
  1886. Examples
  1887. --------
  1888. >>> from scipy import ndimage
  1889. >>> a = np.array(([0,1,1,1,1],
  1890. ... [0,0,1,1,1],
  1891. ... [0,1,1,1,1],
  1892. ... [0,1,1,1,0],
  1893. ... [0,1,1,0,0]))
  1894. >>> ndimage.distance_transform_edt(a)
  1895. array([[ 0. , 1. , 1.4142, 2.2361, 3. ],
  1896. [ 0. , 0. , 1. , 2. , 2. ],
  1897. [ 0. , 1. , 1.4142, 1.4142, 1. ],
  1898. [ 0. , 1. , 1.4142, 1. , 0. ],
  1899. [ 0. , 1. , 1. , 0. , 0. ]])
  1900. With a sampling of 2 units along x, 1 along y:
  1901. >>> ndimage.distance_transform_edt(a, sampling=[2,1])
  1902. array([[ 0. , 1. , 2. , 2.8284, 3.6056],
  1903. [ 0. , 0. , 1. , 2. , 3. ],
  1904. [ 0. , 1. , 2. , 2.2361, 2. ],
  1905. [ 0. , 1. , 2. , 1. , 0. ],
  1906. [ 0. , 1. , 1. , 0. , 0. ]])
  1907. Asking for indices as well:
  1908. >>> edt, inds = ndimage.distance_transform_edt(a, return_indices=True)
  1909. >>> inds
  1910. array([[[0, 0, 1, 1, 3],
  1911. [1, 1, 1, 1, 3],
  1912. [2, 2, 1, 3, 3],
  1913. [3, 3, 4, 4, 3],
  1914. [4, 4, 4, 4, 4]],
  1915. [[0, 0, 1, 1, 4],
  1916. [0, 1, 1, 1, 4],
  1917. [0, 0, 1, 4, 4],
  1918. [0, 0, 3, 3, 4],
  1919. [0, 0, 3, 3, 4]]])
  1920. With arrays provided for inplace outputs:
  1921. >>> indices = np.zeros(((np.ndim(a),) + a.shape), dtype=np.int32)
  1922. >>> ndimage.distance_transform_edt(a, return_indices=True, indices=indices)
  1923. array([[ 0. , 1. , 1.4142, 2.2361, 3. ],
  1924. [ 0. , 0. , 1. , 2. , 2. ],
  1925. [ 0. , 1. , 1.4142, 1.4142, 1. ],
  1926. [ 0. , 1. , 1.4142, 1. , 0. ],
  1927. [ 0. , 1. , 1. , 0. , 0. ]])
  1928. >>> indices
  1929. array([[[0, 0, 1, 1, 3],
  1930. [1, 1, 1, 1, 3],
  1931. [2, 2, 1, 3, 3],
  1932. [3, 3, 4, 4, 3],
  1933. [4, 4, 4, 4, 4]],
  1934. [[0, 0, 1, 1, 4],
  1935. [0, 1, 1, 1, 4],
  1936. [0, 0, 1, 4, 4],
  1937. [0, 0, 3, 3, 4],
  1938. [0, 0, 3, 3, 4]]])
  1939. """
  1940. if (not return_distances) and (not return_indices):
  1941. msg = 'at least one of distances/indices must be specified'
  1942. raise RuntimeError(msg)
  1943. ft_inplace = isinstance(indices, numpy.ndarray)
  1944. dt_inplace = isinstance(distances, numpy.ndarray)
  1945. # calculate the feature transform
  1946. input = numpy.atleast_1d(numpy.where(input, 1, 0).astype(numpy.int8))
  1947. if sampling is not None:
  1948. sampling = _ni_support._normalize_sequence(sampling, input.ndim)
  1949. sampling = numpy.asarray(sampling, dtype=numpy.float64)
  1950. if not sampling.flags.contiguous:
  1951. sampling = sampling.copy()
  1952. if ft_inplace:
  1953. ft = indices
  1954. if ft.shape != (input.ndim,) + input.shape:
  1955. raise RuntimeError('indices has wrong shape')
  1956. if ft.dtype.type != numpy.int32:
  1957. raise RuntimeError('indices must be of int32 type')
  1958. else:
  1959. ft = numpy.zeros((input.ndim,) + input.shape, dtype=numpy.int32)
  1960. _nd_image.euclidean_feature_transform(input, sampling, ft)
  1961. # if requested, calculate the distance transform
  1962. if return_distances:
  1963. dt = ft - numpy.indices(input.shape, dtype=ft.dtype)
  1964. dt = dt.astype(numpy.float64)
  1965. if sampling is not None:
  1966. for ii in range(len(sampling)):
  1967. dt[ii, ...] *= sampling[ii]
  1968. numpy.multiply(dt, dt, dt)
  1969. if dt_inplace:
  1970. dt = numpy.add.reduce(dt, axis=0)
  1971. if distances.shape != dt.shape:
  1972. raise RuntimeError('indices has wrong shape')
  1973. if distances.dtype.type != numpy.float64:
  1974. raise RuntimeError('indices must be of float64 type')
  1975. numpy.sqrt(dt, distances)
  1976. else:
  1977. dt = numpy.add.reduce(dt, axis=0)
  1978. dt = numpy.sqrt(dt)
  1979. # construct and return the result
  1980. result = []
  1981. if return_distances and not dt_inplace:
  1982. result.append(dt)
  1983. if return_indices and not ft_inplace:
  1984. result.append(ft)
  1985. if len(result) == 2:
  1986. return tuple(result)
  1987. elif len(result) == 1:
  1988. return result[0]
  1989. else:
  1990. return None