Best Python code snippet using slash
morphology.py
Source:morphology.py
...43 structure = numpy.array(structure)44 coor = tuple([oo + ss // 2 for ss, oo in zip(structure.shape,45 origin)])46 return bool(structure[coor])47def iterate_structure(structure, iterations, origin=None):48 """49 Iterate a structure by dilating it with itself.50 Parameters51 ----------52 structure : array_like53 Structuring element (an array of bools, for example), to be dilated with54 itself.55 iterations : int56 number of dilations performed on the structure with itself57 origin : optional58 If origin is None, only the iterated structure is returned. If59 not, a tuple of the iterated structure and the modified origin is60 returned.61 Returns62 -------63 iterate_structure : ndarray of bools64 A new structuring element obtained by dilating `structure`65 (`iterations` - 1) times with itself.66 See also67 --------68 generate_binary_structure69 Examples70 --------71 >>> struct = ndimage.generate_binary_structure(2, 1)72 >>> struct.astype(int)73 array([[0, 1, 0],74 [1, 1, 1],75 [0, 1, 0]])76 >>> ndimage.iterate_structure(struct, 2).astype(int)77 array([[0, 0, 1, 0, 0],78 [0, 1, 1, 1, 0],79 [1, 1, 1, 1, 1],80 [0, 1, 1, 1, 0],81 [0, 0, 1, 0, 0]])82 >>> ndimage.iterate_structure(struct, 3).astype(int)83 array([[0, 0, 0, 1, 0, 0, 0],84 [0, 0, 1, 1, 1, 0, 0],85 [0, 1, 1, 1, 1, 1, 0],86 [1, 1, 1, 1, 1, 1, 1],87 [0, 1, 1, 1, 1, 1, 0],88 [0, 0, 1, 1, 1, 0, 0],89 [0, 0, 0, 1, 0, 0, 0]])90 """91 structure = numpy.asarray(structure)92 if iterations < 2:93 return structure.copy()94 ni = iterations - 195 shape = [ii + ni * (ii - 1) for ii in structure.shape]96 pos = [ni * (structure.shape[ii] // 2) for ii in range(len(shape))]97 slc = [slice(pos[ii], pos[ii] + structure.shape[ii], None)98 for ii in range(len(shape))]99 out = numpy.zeros(shape, bool)100 out[slc] = structure != 0101 out = binary_dilation(out, structure, iterations=ni)102 if origin is None:103 return out104 else:105 origin = _ni_support._normalize_sequence(origin, structure.ndim)106 origin = [iterations * o for o in origin]107 return out, origin108def generate_binary_structure(rank, connectivity):109 """110 Generate a binary structure for binary morphological operations.111 Parameters112 ----------113 rank : int114 Number of dimensions of the array to which the structuring element115 will be applied, as returned by `np.ndim`.116 connectivity : int117 `connectivity` determines which elements of the output array belong118 to the structure, i.e. are considered as neighbors of the central119 element. Elements up to a squared distance of `connectivity` from120 the center are considered neighbors. `connectivity` may range from 1121 (no diagonal elements are neighbors) to `rank` (all elements are122 neighbors).123 Returns124 -------125 output : ndarray of bools126 Structuring element which may be used for binary morphological127 operations, with `rank` dimensions and all dimensions equal to 3.128 See also129 --------130 iterate_structure, binary_dilation, binary_erosion131 Notes132 -----133 `generate_binary_structure` can only create structuring elements with134 dimensions equal to 3, i.e. minimal dimensions. For larger structuring135 elements, that are useful e.g. for eroding large objects, one may either136 use `iterate_structure`, or create directly custom arrays with137 numpy functions such as `numpy.ones`.138 Examples139 --------140 >>> struct = ndimage.generate_binary_structure(2, 1)141 >>> struct142 array([[False, True, False],143 [ True, True, True],144 [False, True, False]], dtype=bool)145 >>> a = np.zeros((5,5))146 >>> a[2, 2] = 1147 >>> a148 array([[ 0., 0., 0., 0., 0.],149 [ 0., 0., 0., 0., 0.],150 [ 0., 0., 1., 0., 0.],151 [ 0., 0., 0., 0., 0.],152 [ 0., 0., 0., 0., 0.]])153 >>> b = ndimage.binary_dilation(a, structure=struct).astype(a.dtype)154 >>> b155 array([[ 0., 0., 0., 0., 0.],156 [ 0., 0., 1., 0., 0.],157 [ 0., 1., 1., 1., 0.],158 [ 0., 0., 1., 0., 0.],159 [ 0., 0., 0., 0., 0.]])160 >>> ndimage.binary_dilation(b, structure=struct).astype(a.dtype)161 array([[ 0., 0., 1., 0., 0.],162 [ 0., 1., 1., 1., 0.],163 [ 1., 1., 1., 1., 1.],164 [ 0., 1., 1., 1., 0.],165 [ 0., 0., 1., 0., 0.]])166 >>> struct = ndimage.generate_binary_structure(2, 2)167 >>> struct168 array([[ True, True, True],169 [ True, True, True],170 [ True, True, True]], dtype=bool)171 >>> struct = ndimage.generate_binary_structure(3, 1)172 >>> struct # no diagonal elements173 array([[[False, False, False],174 [False, True, False],175 [False, False, False]],176 [[False, True, False],177 [ True, True, True],178 [False, True, False]],179 [[False, False, False],180 [False, True, False],181 [False, False, False]]], dtype=bool)182 """183 if connectivity < 1:184 connectivity = 1185 if rank < 1:186 if connectivity < 1:187 return numpy.array(0, dtype=bool)188 else:189 return numpy.array(1, dtype=bool)190 output = numpy.fabs(numpy.indices([3] * rank) - 1)191 output = numpy.add.reduce(output, 0)192 return numpy.asarray(output <= connectivity, dtype=bool)193def _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)202 structure = structure.astype(bool)203 if structure.ndim != input.ndim:204 raise RuntimeError('structure and input must have same dimensionality')205 if not structure.flags.contiguous:206 structure = structure.copy()207 if numpy.product(structure.shape,axis=0) < 1:208 raise RuntimeError('structure must not be empty')209 if mask is not None:210 mask = numpy.asarray(mask)211 if mask.shape != input.shape:212 raise RuntimeError('mask and input must have equal sizes')213 origin = _ni_support._normalize_sequence(origin, input.ndim)214 cit = _center_is_true(structure, origin)215 if isinstance(output, numpy.ndarray):216 if numpy.iscomplexobj(output):217 raise TypeError('Complex output type not supported')218 else:219 output = bool220 output, return_value = _ni_support._get_output(output, input)221 if iterations == 1:222 _nd_image.binary_erosion(input, structure, mask, output,223 border_value, origin, invert, cit, 0)224 return return_value225 elif cit and not brute_force:226 changed, coordinate_list = _nd_image.binary_erosion(input,227 structure, mask, output, 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] -= 1234 if mask is not None:235 msk = numpy.asarray(mask)236 msk = mask.astype(numpy.int8)237 if msk is mask:238 msk = mask.copy()239 mask = msk240 if not structure.flags.contiguous:241 structure = structure.copy()242 _nd_image.binary_erosion2(output, structure, mask, iterations - 1,243 origin, invert, coordinate_list)244 return return_value245 else:246 tmp_in = numpy.zeros(input.shape, bool)247 if return_value is None:248 tmp_out = output249 else:250 tmp_out = numpy.zeros(input.shape, bool)251 if not iterations & 1:252 tmp_in, tmp_out = tmp_out, tmp_in253 changed = _nd_image.binary_erosion(input, structure, mask,254 tmp_out, border_value, origin, invert, cit, 0)255 ii = 1256 while (ii < iterations) or (iterations < 1) and changed:257 tmp_in, tmp_out = tmp_out, tmp_in258 changed = _nd_image.binary_erosion(tmp_in, structure, mask,259 tmp_out, border_value, origin, invert, cit, 0)260 ii += 1261 if return_value is not None:262 return tmp_out263def binary_erosion(input, structure=None, iterations=1, mask=None,264 output=None, border_value=0, origin=0, brute_force=False):265 """266 Multi-dimensional binary erosion with a given structuring element.267 Binary erosion is a mathematical morphology operation used for image268 processing.269 Parameters270 ----------271 input : array_like272 Binary image to be eroded. Non-zero (True) elements form273 the subset to be eroded.274 structure : array_like, optional275 Structuring element used for the erosion. Non-zero elements are276 considered True. If no structuring element is provided, an element277 is generated with a square connectivity equal to one.278 iterations : {int, float}, optional279 The erosion is repeated `iterations` times (one, by default).280 If iterations is less than 1, the erosion is repeated until the281 result does not change anymore.282 mask : array_like, optional283 If a mask is given, only those elements with a True value at284 the corresponding mask element are modified at each iteration.285 output : ndarray, optional286 Array of the same shape as input, into which the output is placed.287 By default, a new array is created.288 origin : int or tuple of ints, optional289 Placement of the filter, by default 0.290 border_value : int (cast to 0 or 1)291 Value at the border in the output array.292 Returns293 -------294 binary_erosion : ndarray of bools295 Erosion of the input by the structuring element.296 See also297 --------298 grey_erosion, binary_dilation, binary_closing, binary_opening,299 generate_binary_structure300 Notes301 -----302 Erosion [1]_ is a mathematical morphology operation [2]_ that uses a303 structuring element for shrinking the shapes in an image. The binary304 erosion of an image by a structuring element is the locus of the points305 where a superimposition of the structuring element centered on the point306 is entirely contained in the set of non-zero elements of the image.307 References308 ----------309 .. [1] http://en.wikipedia.org/wiki/Erosion_%28morphology%29310 .. [2] http://en.wikipedia.org/wiki/Mathematical_morphology311 Examples312 --------313 >>> a = np.zeros((7,7), dtype=np.int)314 >>> a[1:6, 2:5] = 1315 >>> a316 array([[0, 0, 0, 0, 0, 0, 0],317 [0, 0, 1, 1, 1, 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, 0, 0, 0, 0, 0]])323 >>> ndimage.binary_erosion(a).astype(a.dtype)324 array([[0, 0, 0, 0, 0, 0, 0],325 [0, 0, 0, 0, 0, 0, 0],326 [0, 0, 0, 1, 0, 0, 0],327 [0, 0, 0, 1, 0, 0, 0],328 [0, 0, 0, 1, 0, 0, 0],329 [0, 0, 0, 0, 0, 0, 0],330 [0, 0, 0, 0, 0, 0, 0]])331 >>> #Erosion removes objects smaller than the structure332 >>> ndimage.binary_erosion(a, structure=np.ones((5,5))).astype(a.dtype)333 array([[0, 0, 0, 0, 0, 0, 0],334 [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 """341 return _binary_erosion(input, structure, iterations, mask,342 output, border_value, origin, 0, brute_force)343def binary_dilation(input, structure=None, iterations=1, mask=None,344 output=None, border_value=0, origin=0, brute_force=False):345 """346 Multi-dimensional binary dilation with the given structuring element.347 Parameters348 ----------349 input : array_like350 Binary array_like to be dilated. Non-zero (True) elements form351 the subset to be dilated.352 structure : array_like, optional353 Structuring element used for the dilation. Non-zero elements are354 considered True. If no structuring element is provided an element355 is generated with a square connectivity equal to one.356 iterations : {int, float}, optional357 The dilation is repeated `iterations` times (one, by default).358 If iterations is less than 1, the dilation is repeated until the359 result does not change anymore.360 mask : array_like, optional361 If a mask is given, only those elements with a True value at362 the corresponding mask element are modified at each iteration.363 output : ndarray, optional364 Array of the same shape as input, into which the output is placed.365 By default, a new array is created.366 origin : int or tuple of ints, optional367 Placement of the filter, by default 0.368 border_value : int (cast to 0 or 1)369 Value at the border in the output array.370 Returns371 -------372 binary_dilation : ndarray of bools373 Dilation of the input by the structuring element.374 See also375 --------376 grey_dilation, binary_erosion, binary_closing, binary_opening,377 generate_binary_structure378 Notes379 -----380 Dilation [1]_ is a mathematical morphology operation [2]_ that uses a381 structuring element for expanding the shapes in an image. The binary382 dilation of an image by a structuring element is the locus of the points383 covered by the structuring element, when its center lies within the384 non-zero points of the image.385 References386 ----------387 .. [1] http://en.wikipedia.org/wiki/Dilation_%28morphology%29388 .. [2] http://en.wikipedia.org/wiki/Mathematical_morphology389 Examples390 --------391 >>> a = np.zeros((5, 5))392 >>> a[2, 2] = 1393 >>> a394 array([[ 0., 0., 0., 0., 0.],395 [ 0., 0., 0., 0., 0.],396 [ 0., 0., 1., 0., 0.],397 [ 0., 0., 0., 0., 0.],398 [ 0., 0., 0., 0., 0.]])399 >>> ndimage.binary_dilation(a)400 array([[False, False, False, False, False],401 [False, False, True, False, False],402 [False, True, True, True, False],403 [False, False, True, False, False],404 [False, False, False, False, False]], dtype=bool)405 >>> ndimage.binary_dilation(a).astype(a.dtype)406 array([[ 0., 0., 0., 0., 0.],407 [ 0., 0., 1., 0., 0.],408 [ 0., 1., 1., 1., 0.],409 [ 0., 0., 1., 0., 0.],410 [ 0., 0., 0., 0., 0.]])411 >>> # 3x3 structuring element with connectivity 1, used by default412 >>> struct1 = ndimage.generate_binary_structure(2, 1)413 >>> struct1414 array([[False, True, False],415 [ True, True, True],416 [False, True, False]], dtype=bool)417 >>> # 3x3 structuring element with connectivity 2418 >>> struct2 = ndimage.generate_binary_structure(2, 2)419 >>> struct2420 array([[ True, True, True],421 [ True, True, True],422 [ True, True, True]], dtype=bool)423 >>> ndimage.binary_dilation(a, structure=struct1).astype(a.dtype)424 array([[ 0., 0., 0., 0., 0.],425 [ 0., 0., 1., 0., 0.],426 [ 0., 1., 1., 1., 0.],427 [ 0., 0., 1., 0., 0.],428 [ 0., 0., 0., 0., 0.]])429 >>> ndimage.binary_dilation(a, structure=struct2).astype(a.dtype)430 array([[ 0., 0., 0., 0., 0.],431 [ 0., 1., 1., 1., 0.],432 [ 0., 1., 1., 1., 0.],433 [ 0., 1., 1., 1., 0.],434 [ 0., 0., 0., 0., 0.]])435 >>> ndimage.binary_dilation(a, structure=struct1,\\436 ... iterations=2).astype(a.dtype)437 array([[ 0., 0., 1., 0., 0.],438 [ 0., 1., 1., 1., 0.],439 [ 1., 1., 1., 1., 1.],440 [ 0., 1., 1., 1., 0.],441 [ 0., 0., 1., 0., 0.]])442 """443 input = numpy.asarray(input)444 if structure is None:445 structure = generate_binary_structure(input.ndim, 1)446 origin = _ni_support._normalize_sequence(origin, input.ndim)447 structure = numpy.asarray(structure)448 structure = structure[tuple([slice(None, None, -1)] *449 structure.ndim)]450 for ii in range(len(origin)):451 origin[ii] = -origin[ii]452 if not structure.shape[ii] & 1:453 origin[ii] -= 1454 return _binary_erosion(input, structure, iterations, mask,455 output, border_value, origin, 1, brute_force)456def binary_opening(input, structure=None, iterations=1, output=None,457 origin=0):458 """459 Multi-dimensional binary opening with the given structuring element.460 The *opening* of an input image by a structuring element is the461 *dilation* of the *erosion* of the image by the structuring element.462 Parameters463 ----------464 input : array_like465 Binary array_like to be opened. Non-zero (True) elements form466 the subset to be opened.467 structure : array_like, optional468 Structuring element used for the opening. Non-zero elements are469 considered True. If no structuring element is provided an element470 is generated with a square connectivity equal to one (i.e., only471 nearest neighbors are connected to the center, diagonally-connected472 elements are not considered neighbors).473 iterations : {int, float}, optional474 The erosion step of the opening, then the dilation step are each475 repeated `iterations` times (one, by default). If `iterations` is476 less than 1, each operation is repeated until the result does477 not change anymore.478 output : ndarray, optional479 Array of the same shape as input, into which the output is placed.480 By default, a new array is created.481 origin : int or tuple of ints, optional482 Placement of the filter, by default 0.483 Returns484 -------485 binary_opening : ndarray of bools486 Opening of the input by the structuring element.487 See also488 --------489 grey_opening, binary_closing, binary_erosion, binary_dilation,490 generate_binary_structure491 Notes492 -----493 *Opening* [1]_ is a mathematical morphology operation [2]_ that494 consists in the succession of an erosion and a dilation of the495 input with the same structuring element. Opening therefore removes496 objects smaller than the structuring element.497 Together with *closing* (`binary_closing`), opening can be used for498 noise removal.499 References500 ----------501 .. [1] http://en.wikipedia.org/wiki/Opening_%28morphology%29502 .. [2] http://en.wikipedia.org/wiki/Mathematical_morphology503 Examples504 --------505 >>> a = np.zeros((5,5), dtype=np.int)506 >>> a[1:4, 1:4] = 1; a[4, 4] = 1507 >>> a508 array([[0, 0, 0, 0, 0],509 [0, 1, 1, 1, 0],510 [0, 1, 1, 1, 0],511 [0, 1, 1, 1, 0],512 [0, 0, 0, 0, 1]])513 >>> # Opening removes small objects514 >>> ndimage.binary_opening(a, structure=np.ones((3,3))).astype(np.int)515 array([[0, 0, 0, 0, 0],516 [0, 1, 1, 1, 0],517 [0, 1, 1, 1, 0],518 [0, 1, 1, 1, 0],519 [0, 0, 0, 0, 0]])520 >>> # Opening can also smooth corners521 >>> ndimage.binary_opening(a).astype(np.int)522 array([[0, 0, 0, 0, 0],523 [0, 0, 1, 0, 0],524 [0, 1, 1, 1, 0],525 [0, 0, 1, 0, 0],526 [0, 0, 0, 0, 0]])527 >>> # Opening is the dilation of the erosion of the input528 >>> ndimage.binary_erosion(a).astype(np.int)529 array([[0, 0, 0, 0, 0],530 [0, 0, 0, 0, 0],531 [0, 0, 1, 0, 0],532 [0, 0, 0, 0, 0],533 [0, 0, 0, 0, 0]])534 >>> ndimage.binary_dilation(ndimage.binary_erosion(a)).astype(np.int)535 array([[0, 0, 0, 0, 0],536 [0, 0, 1, 0, 0],537 [0, 1, 1, 1, 0],538 [0, 0, 1, 0, 0],539 [0, 0, 0, 0, 0]])540 """541 input = numpy.asarray(input)542 if structure is None:543 rank = input.ndim544 structure = generate_binary_structure(rank, 1)545 tmp = binary_erosion(input, structure, iterations, None, None, 0,546 origin)547 return binary_dilation(tmp, structure, iterations, None, output, 0,548 origin)549def binary_closing(input, structure=None, iterations=1, output=None,550 origin=0):551 """552 Multi-dimensional binary closing with the given structuring element.553 The *closing* of an input image by a structuring element is the554 *erosion* of the *dilation* of the image by the structuring element.555 Parameters556 ----------557 input : array_like558 Binary array_like to be closed. Non-zero (True) elements form559 the subset to be closed.560 structure : array_like, optional561 Structuring element used for the closing. Non-zero elements are562 considered True. If no structuring element is provided an element563 is generated with a square connectivity equal to one (i.e., only564 nearest neighbors are connected to the center, diagonally-connected565 elements are not considered neighbors).566 iterations : {int, float}, optional567 The dilation step of the closing, then the erosion step are each568 repeated `iterations` times (one, by default). If iterations is569 less than 1, each operations is repeated until the result does570 not change anymore.571 output : ndarray, optional572 Array of the same shape as input, into which the output is placed.573 By default, a new array is created.574 origin : int or tuple of ints, optional575 Placement of the filter, by default 0.576 Returns577 -------578 binary_closing : ndarray of bools579 Closing of the input by the structuring element.580 See also581 --------582 grey_closing, binary_opening, binary_dilation, binary_erosion,583 generate_binary_structure584 Notes585 -----586 *Closing* [1]_ is a mathematical morphology operation [2]_ that587 consists in the succession of a dilation and an erosion of the588 input with the same structuring element. Closing therefore fills589 holes smaller than the structuring element.590 Together with *opening* (`binary_opening`), closing can be used for591 noise removal.592 References593 ----------594 .. [1] http://en.wikipedia.org/wiki/Closing_%28morphology%29595 .. [2] http://en.wikipedia.org/wiki/Mathematical_morphology596 Examples597 --------598 >>> a = np.zeros((5,5), dtype=np.int)599 >>> a[1:-1, 1:-1] = 1; a[2,2] = 0600 >>> a601 array([[0, 0, 0, 0, 0],602 [0, 1, 1, 1, 0],603 [0, 1, 0, 1, 0],604 [0, 1, 1, 1, 0],605 [0, 0, 0, 0, 0]])606 >>> # Closing removes small holes607 >>> ndimage.binary_closing(a).astype(np.int)608 array([[0, 0, 0, 0, 0],609 [0, 1, 1, 1, 0],610 [0, 1, 1, 1, 0],611 [0, 1, 1, 1, 0],612 [0, 0, 0, 0, 0]])613 >>> # Closing is the erosion of the dilation of the input614 >>> ndimage.binary_dilation(a).astype(np.int)615 array([[0, 1, 1, 1, 0],616 [1, 1, 1, 1, 1],617 [1, 1, 1, 1, 1],618 [1, 1, 1, 1, 1],619 [0, 1, 1, 1, 0]])620 >>> ndimage.binary_erosion(ndimage.binary_dilation(a)).astype(np.int)621 array([[0, 0, 0, 0, 0],622 [0, 1, 1, 1, 0],623 [0, 1, 1, 1, 0],624 [0, 1, 1, 1, 0],625 [0, 0, 0, 0, 0]])626 >>> a = np.zeros((7,7), dtype=np.int)627 >>> a[1:6, 2:5] = 1; a[1:3,3] = 0628 >>> a629 array([[0, 0, 0, 0, 0, 0, 0],630 [0, 0, 1, 0, 1, 0, 0],631 [0, 0, 1, 0, 1, 0, 0],632 [0, 0, 1, 1, 1, 0, 0],633 [0, 0, 1, 1, 1, 0, 0],634 [0, 0, 1, 1, 1, 0, 0],635 [0, 0, 0, 0, 0, 0, 0]])636 >>> # In addition to removing holes, closing can also637 >>> # coarsen boundaries with fine hollows.638 >>> ndimage.binary_closing(a).astype(np.int)639 array([[0, 0, 0, 0, 0, 0, 0],640 [0, 0, 1, 0, 1, 0, 0],641 [0, 0, 1, 1, 1, 0, 0],642 [0, 0, 1, 1, 1, 0, 0],643 [0, 0, 1, 1, 1, 0, 0],644 [0, 0, 1, 1, 1, 0, 0],645 [0, 0, 0, 0, 0, 0, 0]])646 >>> ndimage.binary_closing(a, structure=np.ones((2,2))).astype(np.int)647 array([[0, 0, 0, 0, 0, 0, 0],648 [0, 0, 1, 1, 1, 0, 0],649 [0, 0, 1, 1, 1, 0, 0],650 [0, 0, 1, 1, 1, 0, 0],651 [0, 0, 1, 1, 1, 0, 0],652 [0, 0, 1, 1, 1, 0, 0],653 [0, 0, 0, 0, 0, 0, 0]])654 """655 input = numpy.asarray(input)656 if structure is None:657 rank = input.ndim658 structure = generate_binary_structure(rank, 1)659 tmp = binary_dilation(input, structure, iterations, None, None, 0,660 origin)661 return binary_erosion(tmp, structure, iterations, None, output, 0,662 origin)663def binary_hit_or_miss(input, structure1=None, structure2=None,664 output=None, origin1=0, origin2=None):665 """666 Multi-dimensional binary hit-or-miss transform.667 The hit-or-miss transform finds the locations of a given pattern668 inside the input image.669 Parameters670 ----------671 input : array_like (cast to booleans)672 Binary image where a pattern is to be detected.673 structure1 : array_like (cast to booleans), optional674 Part of the structuring element to be fitted to the foreground675 (non-zero elements) of `input`. If no value is provided, a676 structure of square connectivity 1 is chosen.677 structure2 : array_like (cast to booleans), optional678 Second part of the structuring element that has to miss completely679 the foreground. If no value is provided, the complementary of680 `structure1` is taken.681 output : ndarray, optional682 Array of the same shape as input, into which the output is placed.683 By default, a new array is created.684 origin1 : int or tuple of ints, optional685 Placement of the first part of the structuring element `structure1`,686 by default 0 for a centered structure.687 origin2 : int or tuple of ints, optional688 Placement of the second part of the structuring element `structure2`,689 by default 0 for a centered structure. If a value is provided for690 `origin1` and not for `origin2`, then `origin2` is set to `origin1`.691 Returns692 -------693 binary_hit_or_miss : ndarray694 Hit-or-miss transform of `input` with the given structuring695 element (`structure1`, `structure2`).696 See also697 --------698 ndimage.morphology, binary_erosion699 References700 ----------701 .. [1] http://en.wikipedia.org/wiki/Hit-or-miss_transform702 Examples703 --------704 >>> a = np.zeros((7,7), dtype=np.int)705 >>> a[1, 1] = 1; a[2:4, 2:4] = 1; a[4:6, 4:6] = 1706 >>> a707 array([[0, 0, 0, 0, 0, 0, 0],708 [0, 1, 0, 0, 0, 0, 0],709 [0, 0, 1, 1, 0, 0, 0],710 [0, 0, 1, 1, 0, 0, 0],711 [0, 0, 0, 0, 1, 1, 0],712 [0, 0, 0, 0, 1, 1, 0],713 [0, 0, 0, 0, 0, 0, 0]])714 >>> structure1 = np.array([[1, 0, 0], [0, 1, 1], [0, 1, 1]])715 >>> structure1716 array([[1, 0, 0],717 [0, 1, 1],718 [0, 1, 1]])719 >>> # Find the matches of structure1 in the array a720 >>> ndimage.binary_hit_or_miss(a, structure1=structure1).astype(np.int)721 array([[0, 0, 0, 0, 0, 0, 0],722 [0, 0, 0, 0, 0, 0, 0],723 [0, 0, 1, 0, 0, 0, 0],724 [0, 0, 0, 0, 0, 0, 0],725 [0, 0, 0, 0, 1, 0, 0],726 [0, 0, 0, 0, 0, 0, 0],727 [0, 0, 0, 0, 0, 0, 0]])728 >>> # Change the origin of the filter729 >>> # origin1=1 is equivalent to origin1=(1,1) here730 >>> ndimage.binary_hit_or_miss(a, structure1=structure1,\\731 ... origin1=1).astype(np.int)732 array([[0, 0, 0, 0, 0, 0, 0],733 [0, 0, 0, 0, 0, 0, 0],734 [0, 0, 0, 0, 0, 0, 0],735 [0, 0, 0, 1, 0, 0, 0],736 [0, 0, 0, 0, 0, 0, 0],737 [0, 0, 0, 0, 0, 1, 0],738 [0, 0, 0, 0, 0, 0, 0]])739 """740 input = numpy.asarray(input)741 if structure1 is None:742 structure1 = generate_binary_structure(input.ndim, 1)743 if structure2 is None:744 structure2 = numpy.logical_not(structure1)745 origin1 = _ni_support._normalize_sequence(origin1, input.ndim)746 if origin2 is None:747 origin2 = origin1748 else:749 origin2 = _ni_support._normalize_sequence(origin2, input.ndim)750 tmp1 = _binary_erosion(input, structure1, 1, None, None, 0, origin1,751 0, False)752 inplace = isinstance(output, numpy.ndarray)753 result = _binary_erosion(input, structure2, 1, None, output, 0,754 origin2, 1, False)755 if inplace:756 numpy.logical_not(output, output)757 numpy.logical_and(tmp1, output, output)758 else:759 numpy.logical_not(result, result)760 return numpy.logical_and(tmp1, result)761def binary_propagation(input, structure=None, mask=None,762 output=None, border_value=0, origin=0):763 """764 Multi-dimensional binary propagation with the given structuring element.765 Parameters766 ----------767 input : array_like768 Binary image to be propagated inside `mask`.769 structure : array_like770 Structuring element used in the successive dilations. The output771 may depend on the structuring element, especially if `mask` has772 several connex components. If no structuring element is773 provided, an element is generated with a squared connectivity equal774 to one.775 mask : array_like776 Binary mask defining the region into which `input` is allowed to777 propagate.778 output : ndarray, optional779 Array of the same shape as input, into which the output is placed.780 By default, a new array is created.781 origin : int or tuple of ints, optional782 Placement of the filter, by default 0.783 Returns784 -------785 binary_propagation : ndarray786 Binary propagation of `input` inside `mask`.787 Notes788 -----789 This function is functionally equivalent to calling binary_dilation790 with the number of iterations less then one: iterative dilation until791 the result does not change anymore.792 The succession of an erosion and propagation inside the original image793 can be used instead of an *opening* for deleting small objects while794 keeping the contours of larger objects untouched.795 References796 ----------797 .. [1] http://cmm.ensmp.fr/~serra/cours/pdf/en/ch6en.pdf, slide 15.798 .. [2] http://www.qi.tnw.tudelft.nl/Courses/FIP/noframes/fip-Morpholo.html#Heading102799 Examples800 --------801 >>> input = np.zeros((8, 8), dtype=np.int)802 >>> input[2, 2] = 1803 >>> mask = np.zeros((8, 8), dtype=np.int)804 >>> mask[1:4, 1:4] = mask[4, 4] = mask[6:8, 6:8] = 1805 >>> input806 array([[0, 0, 0, 0, 0, 0, 0, 0],807 [0, 0, 0, 0, 0, 0, 0, 0],808 [0, 0, 1, 0, 0, 0, 0, 0],809 [0, 0, 0, 0, 0, 0, 0, 0],810 [0, 0, 0, 0, 0, 0, 0, 0],811 [0, 0, 0, 0, 0, 0, 0, 0],812 [0, 0, 0, 0, 0, 0, 0, 0],813 [0, 0, 0, 0, 0, 0, 0, 0]])814 >>> mask815 array([[0, 0, 0, 0, 0, 0, 0, 0],816 [0, 1, 1, 1, 0, 0, 0, 0],817 [0, 1, 1, 1, 0, 0, 0, 0],818 [0, 1, 1, 1, 0, 0, 0, 0],819 [0, 0, 0, 0, 1, 0, 0, 0],820 [0, 0, 0, 0, 0, 0, 0, 0],821 [0, 0, 0, 0, 0, 0, 1, 1],822 [0, 0, 0, 0, 0, 0, 1, 1]])823 >>> ndimage.binary_propagation(input, mask=mask).astype(np.int)824 array([[0, 0, 0, 0, 0, 0, 0, 0],825 [0, 1, 1, 1, 0, 0, 0, 0],826 [0, 1, 1, 1, 0, 0, 0, 0],827 [0, 1, 1, 1, 0, 0, 0, 0],828 [0, 0, 0, 0, 0, 0, 0, 0],829 [0, 0, 0, 0, 0, 0, 0, 0],830 [0, 0, 0, 0, 0, 0, 0, 0],831 [0, 0, 0, 0, 0, 0, 0, 0]])832 >>> ndimage.binary_propagation(input, mask=mask,\\833 ... structure=np.ones((3,3))).astype(np.int)834 array([[0, 0, 0, 0, 0, 0, 0, 0],835 [0, 1, 1, 1, 0, 0, 0, 0],836 [0, 1, 1, 1, 0, 0, 0, 0],837 [0, 1, 1, 1, 0, 0, 0, 0],838 [0, 0, 0, 0, 1, 0, 0, 0],839 [0, 0, 0, 0, 0, 0, 0, 0],840 [0, 0, 0, 0, 0, 0, 0, 0],841 [0, 0, 0, 0, 0, 0, 0, 0]])842 >>> # Comparison between opening and erosion+propagation843 >>> a = np.zeros((6,6), dtype=np.int)844 >>> a[2:5, 2:5] = 1; a[0, 0] = 1; a[5, 5] = 1845 >>> a846 array([[1, 0, 0, 0, 0, 0],847 [0, 0, 0, 0, 0, 0],848 [0, 0, 1, 1, 1, 0],849 [0, 0, 1, 1, 1, 0],850 [0, 0, 1, 1, 1, 0],851 [0, 0, 0, 0, 0, 1]])852 >>> ndimage.binary_opening(a).astype(np.int)853 array([[0, 0, 0, 0, 0, 0],854 [0, 0, 0, 0, 0, 0],855 [0, 0, 0, 1, 0, 0],856 [0, 0, 1, 1, 1, 0],857 [0, 0, 0, 1, 0, 0],858 [0, 0, 0, 0, 0, 0]])859 >>> b = ndimage.binary_erosion(a)860 >>> b.astype(int)861 array([[0, 0, 0, 0, 0, 0],862 [0, 0, 0, 0, 0, 0],863 [0, 0, 0, 0, 0, 0],864 [0, 0, 0, 1, 0, 0],865 [0, 0, 0, 0, 0, 0],866 [0, 0, 0, 0, 0, 0]])867 >>> ndimage.binary_propagation(b, mask=a).astype(np.int)868 array([[0, 0, 0, 0, 0, 0],869 [0, 0, 0, 0, 0, 0],870 [0, 0, 1, 1, 1, 0],871 [0, 0, 1, 1, 1, 0],872 [0, 0, 1, 1, 1, 0],873 [0, 0, 0, 0, 0, 0]])874 """875 return binary_dilation(input, structure, -1, mask, output,876 border_value, origin)877def binary_fill_holes(input, structure=None, output=None, origin=0):878 """879 Fill the holes in binary objects.880 Parameters881 ----------882 input : array_like883 n-dimensional binary array with holes to be filled884 structure : array_like, optional885 Structuring element used in the computation; large-size elements886 make computations faster but may miss holes separated from the887 background by thin regions. The default element (with a square888 connectivity equal to one) yields the intuitive result where all889 holes in the input have been filled.890 output : ndarray, optional891 Array of the same shape as input, into which the output is placed.892 By default, a new array is created.893 origin : int, tuple of ints, optional894 Position of the structuring element.895 Returns896 -------897 out : ndarray898 Transformation of the initial image `input` where holes have been899 filled.900 See also901 --------902 binary_dilation, binary_propagation, label903 Notes904 -----905 The algorithm used in this function consists in invading the complementary906 of the shapes in `input` from the outer boundary of the image,907 using binary dilations. Holes are not connected to the boundary and are908 therefore not invaded. The result is the complementary subset of the909 invaded region.910 References911 ----------912 .. [1] http://en.wikipedia.org/wiki/Mathematical_morphology913 Examples914 --------915 >>> a = np.zeros((5, 5), dtype=int)916 >>> a[1:4, 1:4] = 1917 >>> a[2,2] = 0918 >>> a919 array([[0, 0, 0, 0, 0],920 [0, 1, 1, 1, 0],921 [0, 1, 0, 1, 0],922 [0, 1, 1, 1, 0],923 [0, 0, 0, 0, 0]])924 >>> ndimage.binary_fill_holes(a).astype(int)925 array([[0, 0, 0, 0, 0],926 [0, 1, 1, 1, 0],927 [0, 1, 1, 1, 0],928 [0, 1, 1, 1, 0],929 [0, 0, 0, 0, 0]])930 >>> # Too big structuring element931 >>> ndimage.binary_fill_holes(a, structure=np.ones((5,5))).astype(int)932 array([[0, 0, 0, 0, 0],933 [0, 1, 1, 1, 0],934 [0, 1, 0, 1, 0],935 [0, 1, 1, 1, 0],936 [0, 0, 0, 0, 0]])937 """938 mask = numpy.logical_not(input)939 tmp = numpy.zeros(mask.shape, bool)940 inplace = isinstance(output, numpy.ndarray)941 if inplace:942 binary_dilation(tmp, structure, -1, mask, output, 1, origin)943 numpy.logical_not(output, output)944 else:945 output = binary_dilation(tmp, structure, -1, mask, None, 1,946 origin)947 numpy.logical_not(output, output)948 return output949def grey_erosion(input, size=None, footprint=None, structure=None,950 output=None, mode="reflect", cval=0.0, origin=0):951 """952 Calculate a greyscale erosion, using either a structuring element,953 or a footprint corresponding to a flat structuring element.954 Grayscale erosion is a mathematical morphology operation. For the955 simple case of a full and flat structuring element, it can be viewed956 as a minimum filter over a sliding window.957 Parameters958 ----------959 input : array_like960 Array over which the grayscale erosion is to be computed.961 size : tuple of ints962 Shape of a flat and full structuring element used for the grayscale963 erosion. Optional if `footprint` or `structure` is provided.964 footprint : array of ints, optional965 Positions of non-infinite elements of a flat structuring element966 used for the grayscale erosion. Non-zero values give the set of967 neighbors of the center over which the minimum is chosen.968 structure : array of ints, optional969 Structuring element used for the grayscale erosion. `structure`970 may be a non-flat structuring element.971 output : array, optional972 An array used for storing the ouput of the erosion may be provided.973 mode : {'reflect','constant','nearest','mirror', 'wrap'}, optional974 The `mode` parameter determines how the array borders are975 handled, where `cval` is the value when mode is equal to976 'constant'. Default is 'reflect'977 cval : scalar, optional978 Value to fill past edges of input if `mode` is 'constant'. Default979 is 0.0.980 origin : scalar, optional981 The `origin` parameter controls the placement of the filter.982 Default 0983 Returns984 -------985 output : ndarray986 Grayscale erosion of `input`.987 See also988 --------989 binary_erosion, grey_dilation, grey_opening, grey_closing990 generate_binary_structure, ndimage.minimum_filter991 Notes992 -----993 The grayscale erosion of an image input by a structuring element s defined994 over a domain E is given by:995 (input+s)(x) = min {input(y) - s(x-y), for y in E}996 In particular, for structuring elements defined as997 s(y) = 0 for y in E, the grayscale erosion computes the minimum of the998 input image inside a sliding window defined by E.999 Grayscale erosion [1]_ is a *mathematical morphology* operation [2]_.1000 References1001 ----------1002 .. [1] http://en.wikipedia.org/wiki/Erosion_%28morphology%291003 .. [2] http://en.wikipedia.org/wiki/Mathematical_morphology1004 Examples1005 --------1006 >>> a = np.zeros((7,7), dtype=np.int)1007 >>> a[1:6, 1:6] = 31008 >>> a[4,4] = 2; a[2,3] = 11009 >>> a1010 array([[0, 0, 0, 0, 0, 0, 0],1011 [0, 3, 3, 3, 3, 3, 0],1012 [0, 3, 3, 1, 3, 3, 0],1013 [0, 3, 3, 3, 3, 3, 0],1014 [0, 3, 3, 3, 2, 3, 0],1015 [0, 3, 3, 3, 3, 3, 0],1016 [0, 0, 0, 0, 0, 0, 0]])1017 >>> ndimage.grey_erosion(a, size=(3,3))1018 array([[0, 0, 0, 0, 0, 0, 0],1019 [0, 0, 0, 0, 0, 0, 0],1020 [0, 0, 1, 1, 1, 0, 0],1021 [0, 0, 1, 1, 1, 0, 0],1022 [0, 0, 3, 2, 2, 0, 0],1023 [0, 0, 0, 0, 0, 0, 0],1024 [0, 0, 0, 0, 0, 0, 0]])1025 >>> footprint = ndimage.generate_binary_structure(2, 1)1026 >>> footprint1027 array([[False, True, False],1028 [ True, True, True],1029 [False, True, False]], dtype=bool)1030 >>> # Diagonally-connected elements are not considered neighbors1031 >>> ndimage.grey_erosion(a, size=(3,3), footprint=footprint)1032 array([[0, 0, 0, 0, 0, 0, 0],1033 [0, 0, 0, 0, 0, 0, 0],1034 [0, 0, 1, 1, 1, 0, 0],1035 [0, 0, 3, 1, 2, 0, 0],1036 [0, 0, 3, 2, 2, 0, 0],1037 [0, 0, 0, 0, 0, 0, 0],1038 [0, 0, 0, 0, 0, 0, 0]])1039 """1040 if size is None and footprint is None and structure is None:1041 raise ValueError("size, footprint or structure must be specified")1042 return filters._min_or_max_filter(input, size, footprint, structure,1043 output, mode, cval, origin, 1)1044def grey_dilation(input, size=None, footprint=None, structure=None,1045 output=None, mode="reflect", cval=0.0, origin=0):1046 """1047 Calculate a greyscale dilation, using either a structuring element,1048 or a footprint corresponding to a flat structuring element.1049 Grayscale dilation is a mathematical morphology operation. For the1050 simple case of a full and flat structuring element, it can be viewed1051 as a maximum filter over a sliding window.1052 Parameters1053 ----------1054 input : array_like1055 Array over which the grayscale dilation is to be computed.1056 size : tuple of ints1057 Shape of a flat and full structuring element used for the grayscale1058 dilation. Optional if `footprint` or `structure` is provided.1059 footprint : array of ints, optional1060 Positions of non-infinite elements of a flat structuring element1061 used for the grayscale dilation. Non-zero values give the set of1062 neighbors of the center over which the maximum is chosen.1063 structure : array of ints, optional1064 Structuring element used for the grayscale dilation. `structure`1065 may be a non-flat structuring element.1066 output : array, optional1067 An array used for storing the ouput of the dilation may be provided.1068 mode : {'reflect','constant','nearest','mirror', 'wrap'}, optional1069 The `mode` parameter determines how the array borders are1070 handled, where `cval` is the value when mode is equal to1071 'constant'. Default is 'reflect'1072 cval : scalar, optional1073 Value to fill past edges of input if `mode` is 'constant'. Default1074 is 0.0.1075 origin : scalar, optional1076 The `origin` parameter controls the placement of the filter.1077 Default 01078 Returns1079 -------1080 grey_dilation : ndarray1081 Grayscale dilation of `input`.1082 See also1083 --------1084 binary_dilation, grey_erosion, grey_closing, grey_opening1085 generate_binary_structure, ndimage.maximum_filter1086 Notes1087 -----1088 The grayscale dilation of an image input by a structuring element s defined1089 over a domain E is given by:1090 (input+s)(x) = max {input(y) + s(x-y), for y in E}1091 In particular, for structuring elements defined as1092 s(y) = 0 for y in E, the grayscale dilation computes the maximum of the1093 input image inside a sliding window defined by E.1094 Grayscale dilation [1]_ is a *mathematical morphology* operation [2]_.1095 References1096 ----------1097 .. [1] http://en.wikipedia.org/wiki/Dilation_%28morphology%291098 .. [2] http://en.wikipedia.org/wiki/Mathematical_morphology1099 Examples1100 --------1101 >>> a = np.zeros((7,7), dtype=np.int)1102 >>> a[2:5, 2:5] = 11103 >>> a[4,4] = 2; a[2,3] = 31104 >>> a1105 array([[0, 0, 0, 0, 0, 0, 0],1106 [0, 0, 0, 0, 0, 0, 0],1107 [0, 0, 1, 3, 1, 0, 0],1108 [0, 0, 1, 1, 1, 0, 0],1109 [0, 0, 1, 1, 2, 0, 0],1110 [0, 0, 0, 0, 0, 0, 0],1111 [0, 0, 0, 0, 0, 0, 0]])1112 >>> ndimage.grey_dilation(a, size=(3,3))1113 array([[0, 0, 0, 0, 0, 0, 0],1114 [0, 1, 3, 3, 3, 1, 0],1115 [0, 1, 3, 3, 3, 1, 0],1116 [0, 1, 3, 3, 3, 2, 0],1117 [0, 1, 1, 2, 2, 2, 0],1118 [0, 1, 1, 2, 2, 2, 0],1119 [0, 0, 0, 0, 0, 0, 0]])1120 >>> ndimage.grey_dilation(a, footprint=np.ones((3,3)))1121 array([[0, 0, 0, 0, 0, 0, 0],1122 [0, 1, 3, 3, 3, 1, 0],1123 [0, 1, 3, 3, 3, 1, 0],1124 [0, 1, 3, 3, 3, 2, 0],1125 [0, 1, 1, 2, 2, 2, 0],1126 [0, 1, 1, 2, 2, 2, 0],1127 [0, 0, 0, 0, 0, 0, 0]])1128 >>> s = ndimage.generate_binary_structure(2,1)1129 >>> s1130 array([[False, True, False],1131 [ True, True, True],1132 [False, True, False]], dtype=bool)1133 >>> ndimage.grey_dilation(a, footprint=s)1134 array([[0, 0, 0, 0, 0, 0, 0],1135 [0, 0, 1, 3, 1, 0, 0],1136 [0, 1, 3, 3, 3, 1, 0],1137 [0, 1, 1, 3, 2, 1, 0],1138 [0, 1, 1, 2, 2, 2, 0],1139 [0, 0, 1, 1, 2, 0, 0],1140 [0, 0, 0, 0, 0, 0, 0]])1141 >>> ndimage.grey_dilation(a, size=(3,3), structure=np.ones((3,3)))1142 array([[1, 1, 1, 1, 1, 1, 1],1143 [1, 2, 4, 4, 4, 2, 1],1144 [1, 2, 4, 4, 4, 2, 1],1145 [1, 2, 4, 4, 4, 3, 1],1146 [1, 2, 2, 3, 3, 3, 1],1147 [1, 2, 2, 3, 3, 3, 1],1148 [1, 1, 1, 1, 1, 1, 1]])1149 """1150 if size is None and footprint is None and structure is None:1151 raise ValueError("size, footprint or structure must be specified")1152 if structure is not None:1153 structure = numpy.asarray(structure)1154 structure = structure[tuple([slice(None, None, -1)] *1155 structure.ndim)]1156 if footprint is not None:1157 footprint = numpy.asarray(footprint)1158 footprint = footprint[tuple([slice(None, None, -1)] *1159 footprint.ndim)]1160 input = numpy.asarray(input)1161 origin = _ni_support._normalize_sequence(origin, input.ndim)1162 for ii in range(len(origin)):1163 origin[ii] = -origin[ii]1164 if footprint is not None:1165 sz = footprint.shape[ii]1166 elif structure is not None:1167 sz = structure.shape[ii]1168 elif numpy.isscalar(size):1169 sz = size1170 else:1171 sz = size[ii]1172 if not sz & 1:1173 origin[ii] -= 11174 return filters._min_or_max_filter(input, size, footprint, structure,1175 output, mode, cval, origin, 0)1176def grey_opening(input, size=None, footprint=None, structure=None,1177 output=None, mode="reflect", cval=0.0, origin=0):1178 """1179 Multi-dimensional greyscale opening.1180 A greyscale opening consists in the succession of a greyscale erosion,1181 and a greyscale dilation.1182 Parameters1183 ----------1184 input : array_like1185 Array over which the grayscale opening is to be computed.1186 size : tuple of ints1187 Shape of a flat and full structuring element used for the grayscale1188 opening. Optional if `footprint` or `structure` is provided.1189 footprint : array of ints, optional1190 Positions of non-infinite elements of a flat structuring element1191 used for the grayscale opening.1192 structure : array of ints, optional1193 Structuring element used for the grayscale opening. `structure`1194 may be a non-flat structuring element.1195 output : array, optional1196 An array used for storing the ouput of the opening may be provided.1197 mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional1198 The `mode` parameter determines how the array borders are1199 handled, where `cval` is the value when mode is equal to1200 'constant'. Default is 'reflect'1201 cval : scalar, optional1202 Value to fill past edges of input if `mode` is 'constant'. Default1203 is 0.0.1204 origin : scalar, optional1205 The `origin` parameter controls the placement of the filter.1206 Default 01207 Returns1208 -------1209 grey_opening : ndarray1210 Result of the grayscale opening of `input` with `structure`.1211 See also1212 --------1213 binary_opening, grey_dilation, grey_erosion, grey_closing1214 generate_binary_structure1215 Notes1216 -----1217 The action of a grayscale opening with a flat structuring element amounts1218 to smoothen high local maxima, whereas binary opening erases small objects.1219 References1220 ----------1221 .. [1] http://en.wikipedia.org/wiki/Mathematical_morphology1222 Examples1223 --------1224 >>> a = np.arange(36).reshape((6,6))1225 >>> a[3, 3] = 501226 >>> a1227 array([[ 0, 1, 2, 3, 4, 5],1228 [ 6, 7, 8, 9, 10, 11],1229 [12, 13, 14, 15, 16, 17],1230 [18, 19, 20, 50, 22, 23],1231 [24, 25, 26, 27, 28, 29],1232 [30, 31, 32, 33, 34, 35]])1233 >>> ndimage.grey_opening(a, size=(3,3))1234 array([[ 0, 1, 2, 3, 4, 4],1235 [ 6, 7, 8, 9, 10, 10],1236 [12, 13, 14, 15, 16, 16],1237 [18, 19, 20, 22, 22, 22],1238 [24, 25, 26, 27, 28, 28],1239 [24, 25, 26, 27, 28, 28]])1240 >>> # Note that the local maximum a[3,3] has disappeared1241 """1242 tmp = grey_erosion(input, size, footprint, structure, None, mode,1243 cval, origin)1244 return grey_dilation(tmp, size, footprint, structure, output, mode,1245 cval, origin)1246def grey_closing(input, size=None, footprint=None, structure=None,1247 output=None, mode="reflect", cval=0.0, origin=0):1248 """1249 Multi-dimensional greyscale closing.1250 A greyscale closing consists in the succession of a greyscale dilation,1251 and a greyscale erosion.1252 Parameters1253 ----------1254 input : array_like1255 Array over which the grayscale closing is to be computed.1256 size : tuple of ints1257 Shape of a flat and full structuring element used for the grayscale1258 closing. Optional if `footprint` or `structure` is provided.1259 footprint : array of ints, optional1260 Positions of non-infinite elements of a flat structuring element1261 used for the grayscale closing.1262 structure : array of ints, optional1263 Structuring element used for the grayscale closing. `structure`1264 may be a non-flat structuring element.1265 output : array, optional1266 An array used for storing the ouput of the closing may be provided.1267 mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional1268 The `mode` parameter determines how the array borders are1269 handled, where `cval` is the value when mode is equal to1270 'constant'. Default is 'reflect'1271 cval : scalar, optional1272 Value to fill past edges of input if `mode` is 'constant'. Default1273 is 0.0.1274 origin : scalar, optional1275 The `origin` parameter controls the placement of the filter.1276 Default 01277 Returns1278 -------1279 grey_closing : ndarray1280 Result of the grayscale closing of `input` with `structure`.1281 See also1282 --------1283 binary_closing, grey_dilation, grey_erosion, grey_opening,1284 generate_binary_structure1285 Notes1286 -----1287 The action of a grayscale closing with a flat structuring element amounts1288 to smoothen deep local minima, whereas binary closing fills small holes.1289 References1290 ----------1291 .. [1] http://en.wikipedia.org/wiki/Mathematical_morphology1292 Examples1293 --------1294 >>> a = np.arange(36).reshape((6,6))1295 >>> a[3,3] = 01296 >>> a1297 array([[ 0, 1, 2, 3, 4, 5],1298 [ 6, 7, 8, 9, 10, 11],1299 [12, 13, 14, 15, 16, 17],1300 [18, 19, 20, 0, 22, 23],1301 [24, 25, 26, 27, 28, 29],1302 [30, 31, 32, 33, 34, 35]])1303 >>> ndimage.grey_closing(a, size=(3,3))1304 array([[ 7, 7, 8, 9, 10, 11],1305 [ 7, 7, 8, 9, 10, 11],1306 [13, 13, 14, 15, 16, 17],1307 [19, 19, 20, 20, 22, 23],1308 [25, 25, 26, 27, 28, 29],1309 [31, 31, 32, 33, 34, 35]])1310 >>> # Note that the local minimum a[3,3] has disappeared1311 """1312 tmp = grey_dilation(input, size, footprint, structure, None, mode,1313 cval, origin)1314 return grey_erosion(tmp, size, footprint, structure, output, mode,1315 cval, origin)1316def morphological_gradient(input, size=None, footprint=None,1317 structure=None, output=None, mode="reflect",1318 cval=0.0, origin=0):1319 """1320 Multi-dimensional morphological gradient.1321 The morphological gradient is calculated as the difference between a1322 dilation and an erosion of the input with a given structuring element.1323 Parameters1324 ----------1325 input : array_like1326 Array over which to compute the morphlogical gradient.1327 size : tuple of ints1328 Shape of a flat and full structuring element used for the mathematical1329 morphology operations. Optional if `footprint` or `structure` is1330 provided. A larger `size` yields a more blurred gradient.1331 footprint : array of ints, optional1332 Positions of non-infinite elements of a flat structuring element1333 used for the morphology operations. Larger footprints1334 give a more blurred morphological gradient.1335 structure : array of ints, optional1336 Structuring element used for the morphology operations.1337 `structure` may be a non-flat structuring element.1338 output : array, optional1339 An array used for storing the ouput of the morphological gradient1340 may be provided.1341 mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional1342 The `mode` parameter determines how the array borders are1343 handled, where `cval` is the value when mode is equal to1344 'constant'. Default is 'reflect'1345 cval : scalar, optional1346 Value to fill past edges of input if `mode` is 'constant'. Default1347 is 0.0.1348 origin : scalar, optional1349 The `origin` parameter controls the placement of the filter.1350 Default 01351 Returns1352 -------1353 morphological_gradient : ndarray1354 Morphological gradient of `input`.1355 See also1356 --------1357 grey_dilation, grey_erosion, ndimage.gaussian_gradient_magnitude1358 Notes1359 -----1360 For a flat structuring element, the morphological gradient1361 computed at a given point corresponds to the maximal difference1362 between elements of the input among the elements covered by the1363 structuring element centered on the point.1364 References1365 ----------1366 .. [1] http://en.wikipedia.org/wiki/Mathematical_morphology1367 Examples1368 --------1369 >>> a = np.zeros((7,7), dtype=np.int)1370 >>> a[2:5, 2:5] = 11371 >>> ndimage.morphological_gradient(a, size=(3,3))1372 array([[0, 0, 0, 0, 0, 0, 0],1373 [0, 1, 1, 1, 1, 1, 0],1374 [0, 1, 1, 1, 1, 1, 0],1375 [0, 1, 1, 0, 1, 1, 0],1376 [0, 1, 1, 1, 1, 1, 0],1377 [0, 1, 1, 1, 1, 1, 0],1378 [0, 0, 0, 0, 0, 0, 0]])1379 >>> # The morphological gradient is computed as the difference1380 >>> # between a dilation and an erosion1381 >>> ndimage.grey_dilation(a, size=(3,3)) -\\1382 ... ndimage.grey_erosion(a, size=(3,3))1383 array([[0, 0, 0, 0, 0, 0, 0],1384 [0, 1, 1, 1, 1, 1, 0],1385 [0, 1, 1, 1, 1, 1, 0],1386 [0, 1, 1, 0, 1, 1, 0],1387 [0, 1, 1, 1, 1, 1, 0],1388 [0, 1, 1, 1, 1, 1, 0],1389 [0, 0, 0, 0, 0, 0, 0]])1390 >>> a = np.zeros((7,7), dtype=np.int)1391 >>> a[2:5, 2:5] = 11392 >>> a[4,4] = 2; a[2,3] = 31393 >>> a1394 array([[0, 0, 0, 0, 0, 0, 0],1395 [0, 0, 0, 0, 0, 0, 0],1396 [0, 0, 1, 3, 1, 0, 0],1397 [0, 0, 1, 1, 1, 0, 0],1398 [0, 0, 1, 1, 2, 0, 0],1399 [0, 0, 0, 0, 0, 0, 0],1400 [0, 0, 0, 0, 0, 0, 0]])1401 >>> ndimage.morphological_gradient(a, size=(3,3))1402 array([[0, 0, 0, 0, 0, 0, 0],1403 [0, 1, 3, 3, 3, 1, 0],1404 [0, 1, 3, 3, 3, 1, 0],1405 [0, 1, 3, 2, 3, 2, 0],1406 [0, 1, 1, 2, 2, 2, 0],1407 [0, 1, 1, 2, 2, 2, 0],1408 [0, 0, 0, 0, 0, 0, 0]])1409 """1410 tmp = grey_dilation(input, size, footprint, structure, None, mode,1411 cval, origin)1412 if isinstance(output, numpy.ndarray):1413 grey_erosion(input, size, footprint, structure, output, mode,1414 cval, origin)1415 return numpy.subtract(tmp, output, output)1416 else:1417 return (tmp - grey_erosion(input, size, footprint, structure,1418 None, mode, cval, origin))1419def morphological_laplace(input, size=None, footprint=None,1420 structure=None, output=None,1421 mode="reflect", cval=0.0, origin=0):1422 """1423 Multi-dimensional morphological laplace.1424 Parameters1425 ----------1426 input : array_like1427 Input.1428 size : int or sequence of ints, optional1429 See `structure`.1430 footprint : bool or ndarray, optional1431 See `structure`.1432 structure : structure1433 Either `size`, `footprint`, or the `structure` must be provided.1434 output : ndarray1435 An output array can optionally be provided.1436 mode : {'reflect','constant','nearest','mirror', 'wrap'}, optional1437 The mode parameter determines how the array borders are handled.1438 For 'constant' mode, values beyond borders are set to be `cval`.1439 Default is 'reflect'.1440 cval : scalar, optional1441 Value to fill past edges of input if mode is 'constant'.1442 Default is 0.01443 origin : origin1444 The origin parameter controls the placement of the filter.1445 Returns1446 -------1447 morphological_laplace : ndarray1448 Output1449 """1450 tmp1 = grey_dilation(input, size, footprint, structure, None, mode,1451 cval, origin)1452 if isinstance(output, numpy.ndarray):1453 grey_erosion(input, size, footprint, structure, output, mode,1454 cval, origin)1455 numpy.add(tmp1, output, output)1456 numpy.subtract(output, input, output)1457 return numpy.subtract(output, input, output)1458 else:1459 tmp2 = grey_erosion(input, size, footprint, structure, None, mode,1460 cval, origin)1461 numpy.add(tmp1, tmp2, tmp2)1462 numpy.subtract(tmp2, input, tmp2)1463 numpy.subtract(tmp2, input, tmp2)1464 return tmp21465def white_tophat(input, size=None, footprint=None, structure=None,1466 output=None, mode="reflect", cval=0.0, origin=0):1467 """1468 Multi-dimensional white tophat filter.1469 Parameters1470 ----------1471 input : array_like1472 Input.1473 size : tuple of ints1474 Shape of a flat and full structuring element used for the filter.1475 Optional if `footprint` or `structure` is provided.1476 footprint : array of ints, optional1477 Positions of elements of a flat structuring element1478 used for the white tophat filter.1479 structure : array of ints, optional1480 Structuring element used for the filter. `structure`1481 may be a non-flat structuring element.1482 output : array, optional1483 An array used for storing the output of the filter may be provided.1484 mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional1485 The `mode` parameter determines how the array borders are1486 handled, where `cval` is the value when mode is equal to1487 'constant'. Default is 'reflect'1488 cval : scalar, optional1489 Value to fill past edges of input if `mode` is 'constant'.1490 Default is 0.0.1491 origin : scalar, optional1492 The `origin` parameter controls the placement of the filter.1493 Default is 0.1494 Returns1495 -------1496 output : ndarray1497 Result of the filter of `input` with `structure`.1498 See also1499 --------1500 black_tophat1501 """1502 tmp = grey_erosion(input, size, footprint, structure, None, mode,1503 cval, origin)1504 if isinstance(output, numpy.ndarray):1505 grey_dilation(tmp, size, footprint, structure, output, mode, cval,1506 origin)1507 return numpy.subtract(input, output, output)1508 else:1509 tmp = grey_dilation(tmp, size, footprint, structure, None, mode,1510 cval, origin)1511 return input - tmp1512def black_tophat(input, size=None, footprint=None,1513 structure=None, output=None, mode="reflect",1514 cval=0.0, origin=0):1515 """1516 Multi-dimensional black tophat filter.1517 Parameters1518 ----------1519 input : array_like1520 Input.1521 size : tuple of ints1522 Shape of a flat and full structuring element used for the filter.1523 Optional if `footprint` or `structure` is provided.1524 footprint : array of ints, optional1525 Positions of non-infinite elements of a flat structuring element1526 used for the black tophat filter.1527 structure : array of ints, optional1528 Structuring element used for the filter. `structure`1529 may be a non-flat structuring element.1530 output : array, optional1531 An array used for storing the output of the filter may be provided.1532 mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional1533 The `mode` parameter determines how the array borders are1534 handled, where `cval` is the value when mode is equal to1535 'constant'. Default is 'reflect'1536 cval : scalar, optional1537 Value to fill past edges of input if `mode` is 'constant'. Default1538 is 0.0.1539 origin : scalar, optional1540 The `origin` parameter controls the placement of the filter.1541 Default 01542 Returns1543 -------1544 black_tophat : ndarray1545 Result of the filter of `input` with `structure`.1546 See also1547 --------1548 white_tophat, grey_opening, grey_closing1549 """1550 tmp = grey_dilation(input, size, footprint, structure, None, mode,1551 cval, origin)1552 if isinstance(output, numpy.ndarray):1553 grey_erosion(tmp, size, footprint, structure, output, mode, cval,1554 origin)1555 return numpy.subtract(output, input, output)1556 else:1557 tmp = grey_erosion(tmp, size, footprint, structure, None, mode,1558 cval, origin)1559 return tmp - input1560def distance_transform_bf(input, metric="euclidean", sampling=None,1561 return_distances=True, return_indices=False,1562 distances=None, indices=None):1563 """1564 Distance transform function by a brute force algorithm.1565 This function calculates the distance transform of the `input`, by1566 replacing each background element (zero values), with its1567 shortest distance to the foreground (any element non-zero).1568 In addition to the distance transform, the feature transform can1569 be calculated. In this case the index of the closest background1570 element is returned along the first axis of the result.1571 Parameters1572 ----------1573 input : array_like1574 Input1575 metric : str, optional1576 Three types of distance metric are supported: 'euclidean', 'taxicab'1577 and 'chessboard'.1578 sampling : {int, sequence of ints}, optional1579 This parameter is only used in the case of the euclidean `metric`1580 distance transform.1581 The sampling along each axis can be given by the `sampling` parameter1582 which should be a sequence of length equal to the input rank, or a1583 single number in which the `sampling` is assumed to be equal along all1584 axes.1585 return_distances : bool, optional1586 The `return_distances` flag can be used to indicate if the distance1587 transform is returned.1588 The default is True.1589 return_indices : bool, optional1590 The `return_indices` flags can be used to indicate if the feature1591 transform is returned.1592 The default is False.1593 distances : float64 ndarray, optional1594 Optional output array to hold distances (if `return_distances` is1595 True).1596 indices : int64 ndarray, optional1597 Optional output array to hold indices (if `return_indices` is True).1598 Returns1599 -------1600 distances : ndarray1601 Distance array if `return_distances` is True.1602 indices : ndarray1603 Indices array if `return_indices` is True.1604 Notes1605 -----1606 This function employs a slow brute force algorithm, see also the1607 function distance_transform_cdt for more efficient taxicab and1608 chessboard algorithms.1609 """1610 if (not return_distances) and (not return_indices):1611 msg = 'at least one of distances/indices must be specified'1612 raise RuntimeError(msg)1613 tmp1 = numpy.asarray(input) != 01614 struct = generate_binary_structure(tmp1.ndim, tmp1.ndim)1615 tmp2 = binary_dilation(tmp1, struct)1616 tmp2 = numpy.logical_xor(tmp1, tmp2)1617 tmp1 = tmp1.astype(numpy.int8) - tmp2.astype(numpy.int8)1618 metric = metric.lower()1619 if metric == 'euclidean':1620 metric = 11621 elif metric in ['taxicab', 'cityblock', 'manhattan']:1622 metric = 21623 elif metric == 'chessboard':1624 metric = 31625 else:1626 raise RuntimeError('distance metric not supported')1627 if sampling is not None:1628 sampling = _ni_support._normalize_sequence(sampling, tmp1.ndim)1629 sampling = numpy.asarray(sampling, dtype=numpy.float64)1630 if not sampling.flags.contiguous:1631 sampling = sampling.copy()1632 if return_indices:1633 ft = numpy.zeros(tmp1.shape, dtype=numpy.int32)1634 else:1635 ft = None1636 if return_distances:1637 if distances is None:1638 if metric == 1:1639 dt = numpy.zeros(tmp1.shape, dtype=numpy.float64)1640 else:1641 dt = numpy.zeros(tmp1.shape, dtype=numpy.uint32)1642 else:1643 if distances.shape != tmp1.shape:1644 raise RuntimeError('distances array has wrong shape')1645 if metric == 1:1646 if distances.dtype.type != numpy.float64:1647 raise RuntimeError('distances array must be float64')1648 else:1649 if distances.dtype.type != numpy.uint32:1650 raise RuntimeError('distances array must be uint32')1651 dt = distances1652 else:1653 dt = None1654 _nd_image.distance_transform_bf(tmp1, metric, sampling, dt, ft)1655 if return_indices:1656 if isinstance(indices, numpy.ndarray):1657 if indices.dtype.type != numpy.int32:1658 raise RuntimeError('indices must of int32 type')1659 if indices.shape != (tmp1.ndim,) + tmp1.shape:1660 raise RuntimeError('indices has wrong shape')1661 tmp2 = indices1662 else:1663 tmp2 = numpy.indices(tmp1.shape, dtype=numpy.int32)1664 ft = numpy.ravel(ft)1665 for ii in range(tmp2.shape[0]):1666 rtmp = numpy.ravel(tmp2[ii, ...])[ft]1667 rtmp.shape = tmp1.shape1668 tmp2[ii, ...] = rtmp1669 ft = tmp21670 # construct and return the result1671 result = []1672 if return_distances and not isinstance(distances, numpy.ndarray):1673 result.append(dt)1674 if return_indices and not isinstance(indices, numpy.ndarray):1675 result.append(ft)1676 if len(result) == 2:1677 return tuple(result)1678 elif len(result) == 1:1679 return result[0]1680 else:1681 return None1682def distance_transform_cdt(input, metric='chessboard',1683 return_distances=True, return_indices=False,1684 distances=None, indices=None):1685 """1686 Distance transform for chamfer type of transforms.1687 Parameters1688 ----------1689 input : array_like1690 Input1691 metric : {'chessboard', 'taxicab'}, optional1692 The `metric` determines the type of chamfering that is done. If the1693 `metric` is equal to 'taxicab' a structure is generated using1694 generate_binary_structure with a squared distance equal to 1. If1695 the `metric` is equal to 'chessboard', a `metric` is generated1696 using generate_binary_structure with a squared distance equal to1697 the dimensionality of the array. These choices correspond to the1698 common interpretations of the 'taxicab' and the 'chessboard'1699 distance metrics in two dimensions.1700 The default for `metric` is 'chessboard'.1701 return_distances, return_indices : bool, optional1702 The `return_distances`, and `return_indices` flags can be used to1703 indicate if the distance transform, the feature transform, or both1704 must be returned.1705 If the feature transform is returned (``return_indices=True``),1706 the index of the closest background element is returned along1707 the first axis of the result.1708 The `return_distances` default is True, and the1709 `return_indices` default is False.1710 distances, indices : ndarrays of int32, optional1711 The `distances` and `indices` arguments can be used to give optional1712 output arrays that must be the same shape as `input`.1713 """1714 if (not return_distances) and (not return_indices):1715 msg = 'at least one of distances/indices must be specified'1716 raise RuntimeError(msg)1717 ft_inplace = isinstance(indices, numpy.ndarray)1718 dt_inplace = isinstance(distances, numpy.ndarray)1719 input = numpy.asarray(input)1720 if metric in ['taxicab', 'cityblock', 'manhattan']:1721 rank = input.ndim1722 metric = generate_binary_structure(rank, 1)1723 elif metric == 'chessboard':1724 rank = input.ndim1725 metric = generate_binary_structure(rank, rank)1726 else:1727 try:1728 metric = numpy.asarray(metric)1729 except:1730 raise RuntimeError('invalid metric provided')1731 for s in metric.shape:1732 if s != 3:1733 raise RuntimeError('metric sizes must be equal to 3')1734 if not metric.flags.contiguous:1735 metric = metric.copy()1736 if dt_inplace:1737 if distances.dtype.type != numpy.int32:1738 raise RuntimeError('distances must be of int32 type')1739 if distances.shape != input.shape:...
smb2_structs.py
Source:smb2_structs.py
1import binascii2import logging3import os4import struct5from StringIO import StringIO6from smb2_constants import *7from smb_constants import *8from smb_structs import ProtocolError9from utils import convertFILETIMEtoEpoch10class SMB2Message:11 HEADER_STRUCT_FORMAT = "<4sHHIHHI" # This refers to the common header part that is shared by both sync and async SMB2 header12 HEADER_STRUCT_SIZE = struct.calcsize(HEADER_STRUCT_FORMAT)13 ASYNC_HEADER_STRUCT_FORMAT = "<IQQQ16s"14 ASYNC_HEADER_STRUCT_SIZE = struct.calcsize(ASYNC_HEADER_STRUCT_FORMAT)15 SYNC_HEADER_STRUCT_FORMAT = "<IQIIQ16s"16 SYNC_HEADER_STRUCT_SIZE = struct.calcsize(SYNC_HEADER_STRUCT_FORMAT)17 HEADER_SIZE = 6418 log = logging.getLogger('SMB.SMB2Message')19 protocol = 220 def __init__(self, payload = None):21 self.reset()22 if payload:23 self.payload = payload24 self.payload.initMessage(self)25 def __str__(self):26 b = StringIO()27 b.write('Command: 0x%02X (%s) %s' % ( self.command, SMB2_COMMAND_NAMES.get(self.command, '<unknown>'), os.linesep ))28 b.write('Status: 0x%08X %s' % ( self.status, os.linesep ))29 b.write('Flags: 0x%02X %s' % ( self.flags, os.linesep ))30 b.write('PID: %d %s' % ( self.pid, os.linesep ))31 b.write('MID: %d %s' % ( self.mid, os.linesep ))32 b.write('TID: %d %s' % ( self.tid, os.linesep ))33 b.write('Data: %d bytes %s%s %s' % ( len(self.data), os.linesep, binascii.hexlify(self.data), os.linesep ))34 return b.getvalue()35 def reset(self):36 self.raw_data = ''37 self.command = 038 self.status = 039 self.flags = 040 self.next_command_offset = 041 self.mid = 042 self.session_id = 043 self.signature = '\0'*1644 self.payload = None45 self.data = ''46 # For async SMB2 message47 self.async_id = 048 # For sync SMB2 message49 self.pid = 050 self.tid = 051 # Not used in this class. Maintained for compatibility with SMBMessage class52 self.flags2 = 053 self.uid = 054 self.security = 0L55 self.parameters_data = ''56 def encode(self):57 """58 Encode this SMB2 message into a series of bytes suitable to be embedded with a NetBIOS session message.59 AssertionError will be raised if this SMB message has not been initialized with a Payload instance60 @return: a string containing the encoded SMB2 message61 """62 assert self.payload63 self.pid = os.getpid()64 self.payload.prepare(self)65 headers_data = struct.pack(self.HEADER_STRUCT_FORMAT,66 '\xFESMB', self.HEADER_SIZE, 0, self.status, self.command, 0, self.flags) + \67 struct.pack(self.SYNC_HEADER_STRUCT_FORMAT, self.next_command_offset, self.mid, self.pid, self.tid, self.session_id, self.signature)68 return headers_data + self.data69 def decode(self, buf):70 """71 Decodes the SMB message in buf.72 All fields of the SMB2Message object will be reset to default values before decoding.73 On errors, do not assume that the fields will be reinstated back to what they are before74 this method is invoked.75 References76 ==========77 - [MS-SMB2]: 2.2.178 @param buf: data containing one complete SMB2 message79 @type buf: string80 @return: a positive integer indicating the number of bytes used in buf to decode this SMB message81 @raise ProtocolError: raised when decoding fails82 """83 buf_len = len(buf)84 if buf_len < 64: # All SMB2 headers must be at least 64 bytes. [MS-SMB2]: 2.2.1.1, 2.2.1.285 raise ProtocolError('Not enough data to decode SMB2 header', buf)86 self.reset()87 protocol, struct_size, self.credit_charge, self.status, \88 self.command, self.credit_re, self.flags = struct.unpack(self.HEADER_STRUCT_FORMAT, buf[:self.HEADER_STRUCT_SIZE])89 if protocol != '\xFESMB':90 raise ProtocolError('Invalid 4-byte SMB2 protocol field', buf)91 if struct_size != self.HEADER_SIZE:92 raise ProtocolError('Invalid SMB2 header structure size')93 if self.isAsync:94 if buf_len < self.HEADER_STRUCT_SIZE+self.ASYNC_HEADER_STRUCT_SIZE:95 raise ProtocolError('Not enough data to decode SMB2 header', buf)96 self.next_command_offset, self.mid, self.async_id, self.session_id, \97 self.signature = struct.unpack(self.ASYNC_HEADER_STRUCT_FORMAT,98 buf[self.HEADER_STRUCT_SIZE:self.HEADER_STRUCT_SIZE+self.ASYNC_HEADER_STRUCT_SIZE])99 else:100 if buf_len < self.HEADER_STRUCT_SIZE+self.SYNC_HEADER_STRUCT_SIZE:101 raise ProtocolError('Not enough data to decode SMB2 header', buf)102 self.next_command_offset, self.mid, self.pid, self.tid, self.session_id, \103 self.signature = struct.unpack(self.SYNC_HEADER_STRUCT_FORMAT,104 buf[self.HEADER_STRUCT_SIZE:self.HEADER_STRUCT_SIZE+self.SYNC_HEADER_STRUCT_SIZE])105 if self.next_command_offset > 0:106 self.raw_data = buf[:self.next_command_offset]107 self.data = buf[self.HEADER_SIZE:self.next_command_offset]108 else:109 self.raw_data = buf110 self.data = buf[self.HEADER_SIZE:]111 self._decodeCommand()112 if self.payload:113 self.payload.decode(self)114 return len(self.raw_data)115 def _decodeCommand(self):116 if self.command == SMB2_COM_READ:117 self.payload = SMB2ReadResponse()118 elif self.command == SMB2_COM_WRITE:119 self.payload = SMB2WriteResponse()120 elif self.command == SMB2_COM_QUERY_DIRECTORY:121 self.payload = SMB2QueryDirectoryResponse()122 elif self.command == SMB2_COM_CREATE:123 self.payload = SMB2CreateResponse()124 elif self.command == SMB2_COM_CLOSE:125 self.payload = SMB2CloseResponse()126 elif self.command == SMB2_COM_QUERY_INFO:127 self.payload = SMB2QueryInfoResponse()128 elif self.command == SMB2_COM_SET_INFO:129 self.payload = SMB2SetInfoResponse()130 elif self.command == SMB2_COM_IOCTL:131 self.payload = SMB2IoctlResponse()132 elif self.command == SMB2_COM_TREE_CONNECT:133 self.payload = SMB2TreeConnectResponse()134 elif self.command == SMB2_COM_SESSION_SETUP:135 self.payload = SMB2SessionSetupResponse()136 elif self.command == SMB2_COM_NEGOTIATE:137 self.payload = SMB2NegotiateResponse()138 elif self.command == SMB2_COM_ECHO:139 self.payload = SMB2EchoResponse()140 @property141 def isAsync(self):142 return bool(self.flags & SMB2_FLAGS_ASYNC_COMMAND)143 @property144 def isReply(self):145 return bool(self.flags & SMB2_FLAGS_SERVER_TO_REDIR)146class Structure:147 def initMessage(self, message):148 pass149 def prepare(self, message):150 raise NotImplementedError151 def decode(self, message):152 raise NotImplementedError153class SMB2NegotiateResponse(Structure):154 """155 Contains information on the SMB2_NEGOTIATE response from server156 After calling the decode method, each instance will contain the following attributes,157 - security_mode (integer)158 - dialect_revision (integer)159 - server_guid (string)160 - max_transact_size (integer)161 - max_read_size (integer)162 - max_write_size (integer)163 - system_time (long)164 - server_start_time (long)165 - security_blob (string)166 References:167 ===========168 - [MS-SMB2]: 2.2.4169 """170 STRUCTURE_FORMAT = "<HHHH16sIIIIQQHHI"171 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)172 def decode(self, message):173 assert message.command == SMB2_COM_NEGOTIATE174 if message.status == 0:175 struct_size, self.security_mode, self.dialect_revision, _, self.server_guid, self.capabilities, \176 self.max_transact_size, self.max_read_size, self.max_write_size, self.system_time, self.server_start_time, \177 security_buf_offset, security_buf_len, _ = struct.unpack(self.STRUCTURE_FORMAT, message.raw_data[SMB2Message.HEADER_SIZE:SMB2Message.HEADER_SIZE+self.STRUCTURE_SIZE])178 self.server_start_time = convertFILETIMEtoEpoch(self.server_start_time)179 self.system_time = convertFILETIMEtoEpoch(self.system_time)180 self.security_blob = message.raw_data[security_buf_offset:security_buf_offset+security_buf_len]181class SMB2SessionSetupRequest(Structure):182 """183 References:184 ===========185 - [MS-SMB2]: 2.2.5186 """187 STRUCTURE_FORMAT = "<HBBIIHHQ"188 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)189 def __init__(self, security_blob):190 self.security_blob = security_blob191 def initMessage(self, message):192 Structure.initMessage(self, message)193 message.command = SMB2_COM_SESSION_SETUP194 def prepare(self, message):195 message.data = struct.pack(self.STRUCTURE_FORMAT,196 25, # Structure size. Must be 25 as mandated by [MS-SMB2] 2.2.5197 0, # VcNumber198 0x01, # Security mode199 0x00, # Capabilities200 0, # Channel201 SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE,202 len(self.security_blob),203 0) + self.security_blob204class SMB2SessionSetupResponse(Structure):205 """206 Contains information about the SMB2_COM_SESSION_SETUP response from the server.207 If the message has no errors, each instance contains the following attributes:208 - session_flags (integer)209 - security_blob (string)210 References:211 ===========212 - [MS-SMB2]: 2.2.6213 """214 STRUCTURE_FORMAT = "<HHHH"215 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)216 def decode(self, message):217 assert message.command == SMB2_COM_SESSION_SETUP218 struct_size, self.session_flags, security_blob_offset, security_blob_len \219 = struct.unpack(self.STRUCTURE_FORMAT, message.raw_data[SMB2Message.HEADER_SIZE:SMB2Message.HEADER_SIZE+self.STRUCTURE_SIZE])220 self.security_blob = message.raw_data[security_blob_offset:security_blob_offset+security_blob_len]221class SMB2TreeConnectRequest(Structure):222 """223 References:224 ===========225 - [MS-SMB2]: 2.2.9226 """227 STRUCTURE_FORMAT = "<HHHH"228 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)229 def __init__(self, path):230 self.path = path231 def initMessage(self, message):232 Structure.initMessage(self, message)233 message.command = SMB2_COM_TREE_CONNECT234 def prepare(self, message):235 message.data = struct.pack(self.STRUCTURE_FORMAT,236 9, # Structure size. Must be 9 as mandated by [MS-SMB2] 2.2.9237 0, # Reserved238 SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE,239 len(self.path)*2) + self.path.encode('UTF-16LE')240class SMB2TreeConnectResponse(Structure):241 """242 Contains information about the SMB2_COM_TREE_CONNECT response from the server.243 If the message has no errors, each instance contains the following attributes:244 - share_type (integer): one of the SMB2_SHARE_TYPE_xxx constants245 - share_flags (integer)246 - capabilities (integer): bitmask of SMB2_SHARE_CAP_xxx247 - maximal_access (integer)248 References:249 ===========250 - [MS-SMB2]: 2.2.10251 """252 STRUCTURE_FORMAT = "<HBBIII"253 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)254 def decode(self, message):255 assert message.command == SMB2_COM_TREE_CONNECT256 if message.status == 0:257 struct_size, self.share_type, _, \258 self.share_flags, self.capabilities, self.maximal_access \259 = struct.unpack(self.STRUCTURE_FORMAT, message.raw_data[SMB2Message.HEADER_SIZE:SMB2Message.HEADER_SIZE+self.STRUCTURE_SIZE])260class SMB2CreateRequest(Structure):261 """262 References:263 ===========264 - [MS-SMB2]: 2.2.13265 """266 STRUCTURE_FORMAT = "<HBBIQQIIIIIHHII"267 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)268 def __init__(self, filename, file_attributes = 0,269 access_mask = 0, share_access = 0, create_disp = 0, create_options = 0,270 impersonation = SEC_ANONYMOUS,271 oplock = SMB2_OPLOCK_LEVEL_NONE,272 create_context_data = ''):273 self.filename = filename274 self.file_attributes = file_attributes275 self.access_mask = access_mask276 self.share_access = share_access277 self.create_disp = create_disp278 self.create_options = create_options279 self.oplock = oplock280 self.impersonation = impersonation281 self.create_context_data = create_context_data or ''282 def initMessage(self, message):283 Structure.initMessage(self, message)284 message.command = SMB2_COM_CREATE285 def prepare(self, message):286 buf = self.filename.encode('UTF-16LE')287 if self.create_context_data:288 n = SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE + len(buf)289 if n % 8 != 0:290 buf += '\0'*(8-n%8)291 create_context_offset = SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE + len(buf)292 else:293 create_context_offset = n294 buf += self.create_context_data295 else:296 create_context_offset = 0297 if not buf:298 buf = '\0'299 assert create_context_offset % 8 == 0300 message.data = struct.pack(self.STRUCTURE_FORMAT,301 57, # Structure size. Must be 57 as mandated by [MS-SMB2] 2.2.13302 0, # SecurityFlag. Must be 0303 self.oplock,304 self.impersonation,305 0, # SmbCreateFlags. Must be 0306 0, # Reserved. Must be 0307 self.access_mask, # DesiredAccess. [MS-SMB2] 2.2.13.1308 self.file_attributes,309 self.share_access,310 self.create_disp,311 self.create_options,312 SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE, # NameOffset313 len(self.filename)*2, # NameLength in bytes314 create_context_offset, # CreateContextOffset315 len(self.create_context_data) # CreateContextLength316 ) + buf317class SMB2CreateResponse(Structure):318 """319 Contains information about the SMB2_COM_CREATE response from the server.320 If the message has no errors, each instance contains the following attributes:321 - oplock (integer): one of SMB2_OPLOCK_LEVEL_xxx constants322 - create_action (integer): one of SMB2_FILE_xxx constants323 - allocation_size (long)324 - file_size (long)325 - file_attributes (integer)326 - fid (16-bytes string)327 - create_time, lastaccess_time, lastwrite_time, change_time (float)328 References:329 ===========330 - [MS-SMB2]: 2.2.14331 """332 STRUCTURE_FORMAT = "<HBBIQQQQQQII16sII"333 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)334 def decode(self, message):335 assert message.command == SMB2_COM_CREATE336 if message.status == 0:337 struct_size, self.oplock, _, self.create_action, \338 create_time, lastaccess_time, lastwrite_time, change_time, \339 self.allocation_size, self.file_size, self.file_attributes, \340 _, self.fid, _, _ = struct.unpack(self.STRUCTURE_FORMAT, message.raw_data[SMB2Message.HEADER_SIZE:SMB2Message.HEADER_SIZE+self.STRUCTURE_SIZE])341 self.create_time = convertFILETIMEtoEpoch(create_time)342 self.lastaccess_time = convertFILETIMEtoEpoch(lastaccess_time)343 self.lastwrite_time = convertFILETIMEtoEpoch(lastwrite_time)344 self.change_time = convertFILETIMEtoEpoch(change_time)345class SMB2WriteRequest(Structure):346 """347 References:348 ===========349 - [MS-SMB2]: 2.2.21350 """351 STRUCTURE_FORMAT = "<HHIQ16sIIHHI"352 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)353 def __init__(self, fid, data, offset, remaining_len = 0, flags = 0):354 assert len(fid) == 16355 self.fid = fid356 self.data = data357 self.offset = offset358 self.remaining_len = remaining_len359 self.flags = flags360 def initMessage(self, message):361 Structure.initMessage(self, message)362 message.command = SMB2_COM_WRITE363 def prepare(self, message):364 message.data = struct.pack(self.STRUCTURE_FORMAT,365 49, # Structure size. Must be 49 as mandated by [MS-SMB2] 2.2.21366 SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE, # DataOffset367 len(self.data),368 self.offset,369 self.fid,370 0, # Channel. Must be 0371 self.remaining_len, # RemainingBytes372 0, # WriteChannelInfoOffset,373 0, # WriteChannelInfoLength374 self.flags) + self.data375class SMB2WriteResponse(Structure):376 """377 Contains information about the SMB2_WRITE response from the server.378 If the message has no errors, each instance contains the following attributes:379 - count (integer)380 References:381 ===========382 - [MS-SMB2]: 2.2.22383 """384 STRUCTURE_FORMAT = "<HHIIHH"385 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)386 def decode(self, message):387 assert message.command == SMB2_COM_WRITE388 if message.status == 0:389 struct_size, _, self.count, _, _, _ = struct.unpack(self.STRUCTURE_FORMAT, message.raw_data[SMB2Message.HEADER_SIZE:SMB2Message.HEADER_SIZE+self.STRUCTURE_SIZE])390class SMB2ReadRequest(Structure):391 """392 References:393 ===========394 - [MS-SMB2]: 2.2.19395 """396 STRUCTURE_FORMAT = "<HBBIQ16sIIIHH"397 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)398 def __init__(self, fid, read_offset, read_len, min_read_len = 0):399 self.fid = fid400 self.read_offset = read_offset401 self.read_len = read_len402 self.min_read_len = min_read_len403 def initMessage(self, message):404 Structure.initMessage(self, message)405 message.command = SMB2_COM_READ406 def prepare(self, message):407 message.data = struct.pack(self.STRUCTURE_FORMAT,408 49, # Structure size. Must be 49 as mandated by [MS-SMB2] 2.2.19409 0, # Padding410 0, # Reserved411 self.read_len,412 self.read_offset,413 self.fid,414 self.min_read_len,415 0, # Channel416 0, # RemainingBytes417 0, # ReadChannelInfoOffset418 0 # ReadChannelInfoLength419 ) + '\0'420class SMB2ReadResponse(Structure):421 """422 References:423 ===========424 - [MS-SMB2]: 2.2.20425 """426 STRUCTURE_FORMAT = "<HBBIII"427 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)428 def decode(self, message):429 assert message.command == SMB2_COM_READ430 if message.status == 0:431 struct_size, data_offset, _, self.data_length, _, _ = struct.unpack(self.STRUCTURE_FORMAT, message.raw_data[SMB2Message.HEADER_SIZE:SMB2Message.HEADER_SIZE+self.STRUCTURE_SIZE])432 self.data = message.raw_data[data_offset:data_offset+self.data_length]433class SMB2IoctlRequest(Structure):434 """435 References:436 ===========437 - [MS-SMB2]: 2.2.31438 """439 STRUCTURE_FORMAT = "<HHI16sIIIIIIII"440 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)441 def __init__(self, fid, ctlcode, flags, in_data, max_out_size = 65536):442 self.ctlcode = ctlcode443 self.fid = fid444 self.flags = flags445 self.in_data = in_data446 self.max_out_size = max_out_size447 def initMessage(self, message):448 Structure.initMessage(self, message)449 message.command = SMB2_COM_IOCTL450 def prepare(self, message):451 message.data = struct.pack(self.STRUCTURE_FORMAT,452 57, # Structure size. Must be 57 as mandated by [MS-SMB2] 2.2.31453 0, # Reserved454 self.ctlcode, # CtlCode455 self.fid,456 SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE, # InputOffset457 len(self.in_data), # InputCount458 0, # MaxInputResponse459 0, # OutputOffset460 0, # OutputCount461 self.max_out_size, # MaxOutputResponse462 self.flags, # Flags463 0 # Reserved464 ) + self.in_data465class SMB2IoctlResponse(Structure):466 """467 Contains information about the SMB2_IOCTL response from the server.468 If the message has no errors, each instance contains the following attributes:469 - ctlcode (integer)470 - fid (16-bytes string)471 - flags (integer)472 - in_data (string)473 - out_data (string)474 References:475 ===========476 - [MS-SMB2]: 2.2.32477 """478 STRUCTURE_FORMAT = "<HHI16sIIIIII"479 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)480 def decode(self, message):481 assert message.command == SMB2_COM_IOCTL482 if message.status == 0:483 struct_size, _, self.ctlcode, self.fid, \484 input_offset, input_len, output_offset, output_len, \485 self.flags, _ = struct.unpack(self.STRUCTURE_FORMAT, message.raw_data[SMB2Message.HEADER_SIZE:SMB2Message.HEADER_SIZE+self.STRUCTURE_SIZE])486 if input_len > 0:487 self.in_data = message.raw_data[input_offset:input_offset+input_len]488 else:489 self.in_data = ''490 if output_len > 0:491 self.out_data = message.raw_data[output_offset:output_offset+output_len]492 else:493 self.out_data = ''494class SMB2CloseRequest(Structure):495 """496 References:497 ===========498 - [MS-SMB2]: 2.2.15499 """500 STRUCTURE_FORMAT = "<HHI16s"501 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)502 def __init__(self, fid, flags = 0):503 self.fid = fid504 self.flags = flags505 def initMessage(self, message):506 Structure.initMessage(self, message)507 message.command = SMB2_COM_CLOSE508 def prepare(self, message):509 message.data = struct.pack(self.STRUCTURE_FORMAT,510 24, # Structure size. Must be 24 as mandated by [MS-SMB2]: 2.2.15511 self.flags,512 0, # Reserved. Must be 0513 self.fid)514class SMB2CloseResponse(Structure):515 """516 References:517 ===========518 - [MS-SMB2]: 2.2.16519 """520 def decode(self, message):521 assert message.command == SMB2_COM_CLOSE522class SMB2QueryDirectoryRequest(Structure):523 """524 References:525 ===========526 - [MS-SMB2]: 2.2.33527 """528 STRUCTURE_FORMAT = "<HBBI16sHHI"529 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)530 def __init__(self, fid, filename, info_class, flags, output_buf_len):531 self.fid = fid532 self.filename = filename533 self.info_class = info_class534 self.flags = flags535 self.output_buf_len = output_buf_len536 def initMessage(self, message):537 Structure.initMessage(self, message)538 message.command = SMB2_COM_QUERY_DIRECTORY539 def prepare(self, message):540 message.data = struct.pack(self.STRUCTURE_FORMAT,541 33, # Structure size. Must be 33 as mandated by [MS-SMB2] 2.2.33542 self.info_class, # FileInformationClass543 self.flags, # Flags544 0, # FileIndex545 self.fid, # FileID546 SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE, # FileNameOffset547 len(self.filename)*2,548 self.output_buf_len) + self.filename.encode('UTF-16LE')549class SMB2QueryDirectoryResponse(Structure):550 """551 Contains information about the SMB2_COM_QUERY_DIRECTORY response from the server.552 If the message has no errors, each instance contains the following attributes:553 - data_length (integer)554 - data (string)555 References:556 ===========557 - [MS-SMB2]: 2.2.34558 """559 STRUCTURE_FORMAT = "<HHI"560 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)561 def decode(self, message):562 assert message.command == SMB2_COM_QUERY_DIRECTORY563 if message.status == 0:564 struct_size, offset, self.data_length = struct.unpack(self.STRUCTURE_FORMAT, message.raw_data[SMB2Message.HEADER_SIZE:SMB2Message.HEADER_SIZE+self.STRUCTURE_SIZE])565 self.data = message.raw_data[offset:offset+self.data_length]566class SMB2QueryInfoRequest(Structure):567 """568 References:569 ===========570 - [MS-SMB2]: 2.2.37571 """572 STRUCTURE_FORMAT = "<HBBIHHIII16s"573 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)574 def __init__(self, fid, flags, additional_info, info_type, file_info_class, input_buf, output_buf_len):575 self.fid = fid576 self.flags = flags577 self.additional_info = additional_info578 self.info_type = info_type579 self.file_info_class = file_info_class580 self.output_buf_len = output_buf_len581 self.input_buf = input_buf or ''582 def initMessage(self, message):583 Structure.initMessage(self, message)584 message.command = SMB2_COM_QUERY_INFO585 def prepare(self, message):586 message.data = struct.pack(self.STRUCTURE_FORMAT,587 41, # Structure size. Must be 41 as mandated by [MS-SMB2] 2.2.37588 self.info_type, # InfoType589 self.file_info_class, # FileInfoClass590 self.output_buf_len, # OutputBufferLength591 SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE, # InputBufferOffset592 0, # Reserved593 len(self.input_buf), # InputBufferLength594 self.additional_info, # AdditionalInformation595 self.flags, # Flags596 self.fid # FileId597 ) + self.input_buf598class SMB2QueryInfoResponse(Structure):599 """600 Contains information about the SMB2_COM_QUERY_INFO response from the server.601 If the message has no errors, each instance contains the following attributes:602 - data_length (integer)603 - data (string)604 References:605 ===========606 - [MS-SMB2]: 2.2.38607 """608 STRUCTURE_FORMAT = "<HHI"609 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)610 def decode(self, message):611 assert message.command == SMB2_COM_QUERY_INFO612 if message.status == 0:613 struct_size, buf_offset, self.data_length = struct.unpack(self.STRUCTURE_FORMAT, message.raw_data[SMB2Message.HEADER_SIZE:SMB2Message.HEADER_SIZE+self.STRUCTURE_SIZE])614 self.data = message.raw_data[buf_offset:buf_offset+self.data_length]615class SMB2SetInfoRequest(Structure):616 """617 References:618 ===========619 - [MS-SMB2]: 2.2.39620 """621 STRUCTURE_FORMAT = "<HBBIHHI16s"622 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)623 def __init__(self, fid, additional_info, info_type, file_info_class, data):624 self.fid = fid625 self.additional_info = additional_info626 self.info_type = info_type627 self.file_info_class = file_info_class628 self.data = data or ''629 def initMessage(self, message):630 Structure.initMessage(self, message)631 message.command = SMB2_COM_SET_INFO632 def prepare(self, message):633 message.data = struct.pack(self.STRUCTURE_FORMAT,634 33, # StructureSize. Must be 33 as mandated by [MS-SMB2] 2.2.39635 self.info_type, # InfoType636 self.file_info_class, # FileInfoClass637 len(self.data), # BufferLength638 SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE, # BufferOffset639 0, # Reserved640 self.additional_info, # AdditionalInformation641 self.fid # FileId642 ) + self.data643class SMB2SetInfoResponse(Structure):644 """645 References:646 ===========647 - [MS-SMB2]: 2.2.40648 """649 def decode(self, message):650 pass651class SMB2EchoRequest(Structure):652 """653 References:654 ===========655 - [MS-SMB2]: 2.2.28656 """657 STRUCTURE_FORMAT = '<HH'658 STRUCTURE_SIZE = struct.calcsize(STRUCTURE_FORMAT)659 def initMessage(self, message):660 Structure.initMessage(self, message)661 message.command = SMB2_COM_ECHO662 def prepare(self, message):663 message.data = struct.pack(self.STRUCTURE_FORMAT,664 4, # StructureSize. Must be 4 as mandated by [MS-SMB2] 2.2.29665 0) # Reserved666class SMB2EchoResponse(Structure):667 """668 References:669 ===========670 - [MS-SMB2]: 2.2.29671 """672 def decode(self, message):...
matfuncs.py
Source:matfuncs.py
1"""2Sparse matrix functions3"""4#5# Authors: Travis Oliphant, March 20026# Anthony Scopatz, August 2012 (Sparse Updates)7# Jake Vanderplas, August 2012 (Sparse Updates)8#9from __future__ import division, print_function, absolute_import10__all__ = ['expm', 'inv']11import math12from numpy import asarray, dot, eye, ceil, log213import numpy as np14import scipy.misc15from scipy.linalg.misc import norm16from scipy.linalg.basic import solve, solve_triangular, inv17from scipy.sparse.base import isspmatrix18from scipy.sparse.construct import eye as speye19from scipy.sparse.linalg import spsolve20import scipy.sparse21import scipy.sparse.linalg22from scipy.sparse.linalg.interface import LinearOperator23UPPER_TRIANGULAR = 'upper_triangular'24def inv(A):25 """26 Compute the inverse of a sparse matrix27 .. versionadded:: 0.12.028 Parameters29 ----------30 A : (M,M) ndarray or sparse matrix31 square matrix to be inverted32 Returns33 -------34 Ainv : (M,M) ndarray or sparse matrix35 inverse of `A`36 Notes37 -----38 This computes the sparse inverse of `A`. If the inverse of `A` is expected39 to be non-sparse, it will likely be faster to convert `A` to dense and use40 scipy.linalg.inv.41 """42 I = speye(A.shape[0], A.shape[1], dtype=A.dtype, format=A.format)43 Ainv = spsolve(A, I)44 return Ainv45def _onenorm_matrix_power_nnm(A, p):46 """47 Compute the 1-norm of a non-negative integer power of a non-negative matrix.48 Parameters49 ----------50 A : a square ndarray or matrix or sparse matrix51 Input matrix with non-negative entries.52 p : non-negative integer53 The power to which the matrix is to be raised.54 Returns55 -------56 out : float57 The 1-norm of the matrix power p of A.58 """59 # check input60 if int(p) != p or p < 0:61 raise ValueError('expected non-negative integer p')62 p = int(p)63 if len(A.shape) != 2 or A.shape[0] != A.shape[1]:64 raise ValueError('expected A to be like a square matrix')65 # Explicitly make a column vector so that this works when A is a66 # numpy matrix (in addition to ndarray and sparse matrix).67 v = np.ones((A.shape[0], 1), dtype=float)68 M = A.T69 for i in range(p):70 v = M.dot(v)71 return max(v)72def _onenorm(A):73 # A compatibility function which should eventually disappear.74 # This is copypasted from expm_action.75 if scipy.sparse.isspmatrix(A):76 return max(abs(A).sum(axis=0).flat)77 else:78 return np.linalg.norm(A, 1)79def _ident_like(A):80 # A compatibility function which should eventually disappear.81 # This is copypasted from expm_action.82 if scipy.sparse.isspmatrix(A):83 return scipy.sparse.construct.eye(A.shape[0], A.shape[1],84 dtype=A.dtype, format=A.format)85 else:86 return np.eye(A.shape[0], A.shape[1], dtype=A.dtype)87def _count_nonzero(A):88 # A compatibility function which should eventually disappear.89 #XXX There should be a better way to do this when A is sparse90 # in the traditional sense.91 if isspmatrix(A):92 return np.sum(A.toarray() != 0)93 else:94 return np.sum(A != 0)95def _is_upper_triangular(A):96 # This function could possibly be of wider interest.97 if isspmatrix(A):98 lower_part = scipy.sparse.tril(A, -1)99 if lower_part.nnz == 0:100 # structural upper triangularity101 return True102 else:103 # coincidental upper triangularity104 return _count_nonzero(lower_part) == 0105 else:106 return _count_nonzero(np.tril(A, -1)) == 0107def _smart_matrix_product(A, B, alpha=None, structure=None):108 """109 A matrix product that knows about sparse and structured matrices.110 Parameters111 ----------112 A : 2d ndarray113 First matrix.114 B : 2d ndarray115 Second matrix.116 alpha : float117 The matrix product will be scaled by this constant.118 structure : str, optional119 A string describing the structure of both matrices `A` and `B`.120 Only `upper_triangular` is currently supported.121 Returns122 -------123 M : 2d ndarray124 Matrix product of A and B.125 """126 if len(A.shape) != 2:127 raise ValueError('expected A to be a rectangular matrix')128 if len(B.shape) != 2:129 raise ValueError('expected B to be a rectangular matrix')130 f = None131 if structure == UPPER_TRIANGULAR:132 if not isspmatrix(A) and not isspmatrix(B):133 f, = scipy.linalg.get_blas_funcs(('trmm',), (A, B))134 if f is not None:135 if alpha is None:136 alpha = 1.137 out = f(alpha, A, B)138 else:139 if alpha is None:140 out = A.dot(B)141 else:142 out = alpha * A.dot(B)143 return out144class MatrixPowerOperator(LinearOperator):145 def __init__(self, A, p, structure=None):146 if A.ndim != 2 or A.shape[0] != A.shape[1]:147 raise ValueError('expected A to be like a square matrix')148 if p < 0:149 raise ValueError('expected p to be a non-negative integer')150 self._A = A151 self._p = p152 self._structure = structure153 self.ndim = A.ndim154 self.shape = A.shape155 def matvec(self, x):156 for i in range(self._p):157 x = self._A.dot(x)158 return x159 def rmatvec(self, x):160 for i in range(self._p):161 x = x.dot(self._A)162 return x163 def matmat(self, X):164 for i in range(self._p):165 X = _smart_matrix_product(self._A, X, structure=self._structure)166 return X167 @property168 def T(self):169 return MatrixPowerOperator(self._A.T, self._p)170class ProductOperator(LinearOperator):171 """172 For now, this is limited to products of multiple square matrices.173 """174 def __init__(self, *args, **kwargs):175 self._structure = kwargs.get('structure', None)176 for A in args:177 if len(A.shape) != 2 or A.shape[0] != A.shape[1]:178 raise ValueError(179 'For now, the ProductOperator implementation is '180 'limited to the product of multiple square matrices.')181 if args:182 n = args[0].shape[0]183 for A in args:184 for d in A.shape:185 if d != n:186 raise ValueError(187 'The square matrices of the ProductOperator '188 'must all have the same shape.')189 self.shape = (n, n)190 self.ndim = len(self.shape)191 self._operator_sequence = args192 def matvec(self, x):193 for A in reversed(self._operator_sequence):194 x = A.dot(x)195 return x196 def rmatvec(self, x):197 for A in self._operator_sequence:198 x = x.dot(A)199 return x200 def matmat(self, X):201 for A in reversed(self._operator_sequence):202 X = _smart_matrix_product(A, X, structure=self._structure)203 return X204 @property205 def T(self):206 T_args = [A.T for A in reversed(self._operator_sequence)]207 return ProductOperator(*T_args)208def _onenormest_matrix_power(A, p,209 t=2, itmax=5, compute_v=False, compute_w=False, structure=None):210 """211 Efficiently estimate the 1-norm of A^p.212 Parameters213 ----------214 A : ndarray215 Matrix whose 1-norm of a power is to be computed.216 p : int217 Non-negative integer power.218 t : int, optional219 A positive parameter controlling the tradeoff between220 accuracy versus time and memory usage.221 Larger values take longer and use more memory222 but give more accurate output.223 itmax : int, optional224 Use at most this many iterations.225 compute_v : bool, optional226 Request a norm-maximizing linear operator input vector if True.227 compute_w : bool, optional228 Request a norm-maximizing linear operator output vector if True.229 Returns230 -------231 est : float232 An underestimate of the 1-norm of the sparse matrix.233 v : ndarray, optional234 The vector such that ||Av||_1 == est*||v||_1.235 It can be thought of as an input to the linear operator236 that gives an output with particularly large norm.237 w : ndarray, optional238 The vector Av which has relatively large 1-norm.239 It can be thought of as an output of the linear operator240 that is relatively large in norm compared to the input.241 """242 return scipy.sparse.linalg.onenormest(243 MatrixPowerOperator(A, p, structure=structure))244def _onenormest_product(operator_seq,245 t=2, itmax=5, compute_v=False, compute_w=False, structure=None):246 """247 Efficiently estimate the 1-norm of the matrix product of the args.248 Parameters249 ----------250 operator_seq : linear operator sequence251 Matrices whose 1-norm of product is to be computed.252 t : int, optional253 A positive parameter controlling the tradeoff between254 accuracy versus time and memory usage.255 Larger values take longer and use more memory256 but give more accurate output.257 itmax : int, optional258 Use at most this many iterations.259 compute_v : bool, optional260 Request a norm-maximizing linear operator input vector if True.261 compute_w : bool, optional262 Request a norm-maximizing linear operator output vector if True.263 structure : str, optional264 A string describing the structure of all operators.265 Only `upper_triangular` is currently supported.266 Returns267 -------268 est : float269 An underestimate of the 1-norm of the sparse matrix.270 v : ndarray, optional271 The vector such that ||Av||_1 == est*||v||_1.272 It can be thought of as an input to the linear operator273 that gives an output with particularly large norm.274 w : ndarray, optional275 The vector Av which has relatively large 1-norm.276 It can be thought of as an output of the linear operator277 that is relatively large in norm compared to the input.278 """279 return scipy.sparse.linalg.onenormest(280 ProductOperator(*operator_seq, structure=structure))281class _ExpmPadeHelper(object):282 """283 Help lazily evaluate a matrix exponential.284 The idea is to not do more work than we need for high expm precision,285 so we lazily compute matrix powers and store or precompute286 other properties of the matrix.287 """288 def __init__(self, A, structure=None, use_exact_onenorm=False):289 """290 Initialize the object.291 Parameters292 ----------293 A : a dense or sparse square numpy matrix or ndarray294 The matrix to be exponentiated.295 structure : str, optional296 A string describing the structure of matrix `A`.297 Only `upper_triangular` is currently supported.298 use_exact_onenorm : bool, optional299 If True then only the exact one-norm of matrix powers and products300 will be used. Otherwise, the one-norm of powers and products301 may initially be estimated.302 """303 self.A = A304 self._A2 = None305 self._A4 = None306 self._A6 = None307 self._A8 = None308 self._A10 = None309 self._d4_exact = None310 self._d6_exact = None311 self._d8_exact = None312 self._d10_exact = None313 self._d4_approx = None314 self._d6_approx = None315 self._d8_approx = None316 self._d10_approx = None317 self.ident = _ident_like(A)318 self.structure = structure319 self.use_exact_onenorm = use_exact_onenorm320 @property321 def A2(self):322 if self._A2 is None:323 self._A2 = _smart_matrix_product(324 self.A, self.A, structure=self.structure)325 return self._A2326 @property327 def A4(self):328 if self._A4 is None:329 self._A4 = _smart_matrix_product(330 self.A2, self.A2, structure=self.structure)331 return self._A4332 @property333 def A6(self):334 if self._A6 is None:335 self._A6 = _smart_matrix_product(336 self.A4, self.A2, structure=self.structure)337 return self._A6338 @property339 def A8(self):340 if self._A8 is None:341 self._A8 = _smart_matrix_product(342 self.A6, self.A2, structure=self.structure)343 return self._A8344 @property345 def A10(self):346 if self._A10 is None:347 self._A10 = _smart_matrix_product(348 self.A4, self.A6, structure=self.structure)349 return self._A10350 @property351 def d4_tight(self):352 if self._d4_exact is None:353 self._d4_exact = _onenorm(self.A4)**(1/4.)354 return self._d4_exact355 @property356 def d6_tight(self):357 if self._d6_exact is None:358 self._d6_exact = _onenorm(self.A6)**(1/6.)359 return self._d6_exact360 @property361 def d8_tight(self):362 if self._d8_exact is None:363 self._d8_exact = _onenorm(self.A8)**(1/8.)364 return self._d8_exact365 @property366 def d10_tight(self):367 if self._d10_exact is None:368 self._d10_exact = _onenorm(self.A10)**(1/10.)369 return self._d10_exact370 @property371 def d4_loose(self):372 if self.use_exact_onenorm:373 return self.d4_tight374 if self._d4_exact is not None:375 return self._d4_exact376 else:377 if self._d4_approx is None:378 self._d4_approx = _onenormest_matrix_power(self.A2, 2,379 structure=self.structure)**(1/4.)380 return self._d4_approx381 @property382 def d6_loose(self):383 if self.use_exact_onenorm:384 return self.d6_tight385 if self._d6_exact is not None:386 return self._d6_exact387 else:388 if self._d6_approx is None:389 self._d6_approx = _onenormest_matrix_power(self.A2, 3,390 structure=self.structure)**(1/6.)391 return self._d6_approx392 @property393 def d8_loose(self):394 if self.use_exact_onenorm:395 return self.d8_tight396 if self._d8_exact is not None:397 return self._d8_exact398 else:399 if self._d8_approx is None:400 self._d8_approx = _onenormest_matrix_power(self.A4, 2,401 structure=self.structure)**(1/8.)402 return self._d8_approx403 @property404 def d10_loose(self):405 if self.use_exact_onenorm:406 return self.d10_tight407 if self._d10_exact is not None:408 return self._d10_exact409 else:410 if self._d10_approx is None:411 self._d10_approx = _onenormest_product((self.A4, self.A6),412 structure=self.structure)**(1/10.)413 return self._d10_approx414 def pade3(self):415 b = (120., 60., 12., 1.)416 U = _smart_matrix_product(self.A,417 b[3]*self.A2 + b[1]*self.ident,418 structure=self.structure)419 V = b[2]*self.A2 + b[0]*self.ident420 return U, V421 def pade5(self):422 b = (30240., 15120., 3360., 420., 30., 1.)423 U = _smart_matrix_product(self.A,424 b[5]*self.A4 + b[3]*self.A2 + b[1]*self.ident,425 structure=self.structure)426 V = b[4]*self.A4 + b[2]*self.A2 + b[0]*self.ident427 return U, V428 def pade7(self):429 b = (17297280., 8648640., 1995840., 277200., 25200., 1512., 56., 1.)430 U = _smart_matrix_product(self.A,431 b[7]*self.A6 + b[5]*self.A4 + b[3]*self.A2 + b[1]*self.ident,432 structure=self.structure)433 V = b[6]*self.A6 + b[4]*self.A4 + b[2]*self.A2 + b[0]*self.ident434 return U, V435 def pade9(self):436 b = (17643225600., 8821612800., 2075673600., 302702400., 30270240.,437 2162160., 110880., 3960., 90., 1.)438 U = _smart_matrix_product(self.A,439 (b[9]*self.A8 + b[7]*self.A6 + b[5]*self.A4 +440 b[3]*self.A2 + b[1]*self.ident),441 structure=self.structure)442 V = (b[8]*self.A8 + b[6]*self.A6 + b[4]*self.A4 +443 b[2]*self.A2 + b[0]*self.ident)444 return U, V445 def pade13_scaled(self, s):446 b = (64764752532480000., 32382376266240000., 7771770303897600.,447 1187353796428800., 129060195264000., 10559470521600.,448 670442572800., 33522128640., 1323241920., 40840800., 960960.,449 16380., 182., 1.)450 B = self.A * 2**-s451 B2 = self.A2 * 2**(-2*s)452 B4 = self.A4 * 2**(-4*s)453 B6 = self.A6 * 2**(-6*s)454 U2 = _smart_matrix_product(B6,455 b[13]*B6 + b[11]*B4 + b[9]*B2,456 structure=self.structure)457 U = _smart_matrix_product(B,458 (U2 + b[7]*B6 + b[5]*B4 +459 b[3]*B2 + b[1]*self.ident),460 structure=self.structure)461 V2 = _smart_matrix_product(B6,462 b[12]*B6 + b[10]*B4 + b[8]*B2,463 structure=self.structure)464 V = V2 + b[6]*B6 + b[4]*B4 + b[2]*B2 + b[0]*self.ident465 return U, V466def expm(A):467 """468 Compute the matrix exponential using Pade approximation.469 .. versionadded:: 0.12.0470 Parameters471 ----------472 A : (M,M) array_like or sparse matrix473 2D Array or Matrix (sparse or dense) to be exponentiated474 Returns475 -------476 expA : (M,M) ndarray477 Matrix exponential of `A`478 Notes479 -----480 This is algorithm (6.1) which is a simplification of algorithm (5.1).481 References482 ----------483 .. [1] Awad H. Al-Mohy and Nicholas J. Higham (2009)484 "A New Scaling and Squaring Algorithm for the Matrix Exponential."485 SIAM Journal on Matrix Analysis and Applications.486 31 (3). pp. 970-989. ISSN 1095-7162487 """488 # Avoid indiscriminate asarray() to allow sparse or other strange arrays.489 if isinstance(A, (list, tuple)):490 A = np.asarray(A)491 if len(A.shape) != 2 or A.shape[0] != A.shape[1]:492 raise ValueError('expected a square matrix')493 # Detect upper triangularity.494 structure = UPPER_TRIANGULAR if _is_upper_triangular(A) else None495 # Hardcode a matrix order threshold for exact vs. estimated one-norms.496 use_exact_onenorm = A.shape[0] < 200497 # Track functions of A to help compute the matrix exponential.498 h = _ExpmPadeHelper(499 A, structure=structure, use_exact_onenorm=use_exact_onenorm)500 # Try Pade order 3.501 eta_1 = max(h.d4_loose, h.d6_loose)502 if eta_1 < 1.495585217958292e-002 and _ell(h.A, 3) == 0:503 U, V = h.pade3()504 return _solve_P_Q(U, V, structure=structure)505 # Try Pade order 5.506 eta_2 = max(h.d4_tight, h.d6_loose)507 if eta_2 < 2.539398330063230e-001 and _ell(h.A, 5) == 0:508 U, V = h.pade5()509 return _solve_P_Q(U, V, structure=structure)510 # Try Pade orders 7 and 9.511 eta_3 = max(h.d6_tight, h.d8_loose)512 if eta_3 < 9.504178996162932e-001 and _ell(h.A, 7) == 0:513 U, V = h.pade7()514 return _solve_P_Q(U, V, structure=structure)515 if eta_3 < 2.097847961257068e+000 and _ell(h.A, 9) == 0:516 U, V = h.pade9()517 return _solve_P_Q(U, V, structure=structure)518 # Use Pade order 13.519 eta_4 = max(h.d8_loose, h.d10_loose)520 eta_5 = min(eta_3, eta_4)521 theta_13 = 4.25522 s = max(int(np.ceil(np.log2(eta_5 / theta_13))), 0)523 s = s + _ell(2**-s * h.A, 13)524 U, V = h.pade13_scaled(s)525 X = _solve_P_Q(U, V, structure=structure)526 if structure == UPPER_TRIANGULAR:527 # Invoke Code Fragment 2.1.528 X = _fragment_2_1(X, h.A, s)529 else:530 # X = r_13(A)^(2^s) by repeated squaring.531 for i in range(s):532 X = X.dot(X)533 return X534def _solve_P_Q(U, V, structure=None):535 """536 A helper function for expm_2009.537 Parameters538 ----------539 U : ndarray540 Pade numerator.541 V : ndarray542 Pade denominator.543 structure : str, optional544 A string describing the structure of both matrices `U` and `V`.545 Only `upper_triangular` is currently supported.546 Notes547 -----548 The `structure` argument is inspired by similar args549 for theano and cvxopt functions.550 """551 P = U + V552 Q = -U + V553 if isspmatrix(U):554 return spsolve(Q, P)555 elif structure is None:556 return solve(Q, P)557 elif structure == UPPER_TRIANGULAR:558 return solve_triangular(Q, P)559 else:560 raise ValueError('unsupported matrix structure: ' + str(structure))561def _sinch(x):562 """563 Stably evaluate sinch.564 Notes565 -----566 The strategy of falling back to a sixth order Taylor expansion567 was suggested by the Spallation Neutron Source docs568 which was found on the internet by google search.569 http://www.ornl.gov/~t6p/resources/xal/javadoc/gov/sns/tools/math/ElementaryFunction.html570 The details of the cutoff point and the Horner-like evaluation571 was picked without reference to anything in particular.572 Note that sinch is not currently implemented in scipy.special,573 whereas the "engineer's" definition of sinc is implemented.574 The implementation of sinc involves a scaling factor of pi575 that distinguishes it from the "mathematician's" version of sinc.576 """577 # If x is small then use sixth order Taylor expansion.578 # How small is small? I am using the point where the relative error579 # of the approximation is less than 1e-14.580 # If x is large then directly evaluate sinh(x) / x.581 x2 = x*x582 if abs(x) < 0.0135:583 return 1 + (x2/6.)*(1 + (x2/20.)*(1 + (x2/42.)))584 else:585 return np.sinh(x) / x586def _eq_10_42(lam_1, lam_2, t_12):587 """588 Equation (10.42) of Functions of Matrices: Theory and Computation.589 Notes590 -----591 This is a helper function for _fragment_2_1 of expm_2009.592 Equation (10.42) is on page 251 in the section on Schur algorithms.593 In particular, section 10.4.3 explains the Schur-Parlett algorithm.594 expm([[lam_1, t_12], [0, lam_1])595 =596 [[exp(lam_1), t_12*exp((lam_1 + lam_2)/2)*sinch((lam_1 - lam_2)/2)],597 [0, exp(lam_2)]598 """599 # The plain formula t_12 * (exp(lam_2) - exp(lam_2)) / (lam_2 - lam_1)600 # apparently suffers from cancellation, according to Higham's textbook.601 # A nice implementation of sinch, defined as sinh(x)/x,602 # will apparently work around the cancellation.603 a = 0.5 * (lam_1 + lam_2)604 b = 0.5 * (lam_1 - lam_2)605 return t_12 * np.exp(a) * _sinch(b)606def _fragment_2_1(X, T, s):607 """608 A helper function for expm_2009.609 Notes610 -----611 The argument X is modified in-place, but this modification is not the same612 as the returned value of the function.613 This function also takes pains to do things in ways that are compatible614 with sparse matrices, for example by avoiding fancy indexing615 and by using methods of the matrices whenever possible instead of616 using functions of the numpy or scipy libraries themselves.617 """618 # Form X = r_m(2^-s T)619 # Replace diag(X) by exp(2^-s diag(T)).620 n = X.shape[0]621 diag_T = T.diagonal().copy()622 # Replace diag(X) by exp(2^-s diag(T)).623 scale = 2 ** -s624 exp_diag = np.exp(scale * diag_T)625 for k in range(n):626 X[k, k] = exp_diag[k]627 for i in range(s-1, -1, -1):628 X = X.dot(X)629 # Replace diag(X) by exp(2^-i diag(T)).630 scale = 2 ** -i631 exp_diag = np.exp(scale * diag_T)632 for k in range(n):633 X[k, k] = exp_diag[k]634 # Replace (first) superdiagonal of X by explicit formula635 # for superdiagonal of exp(2^-i T) from Eq (10.42) of636 # the author's 2008 textbook637 # Functions of Matrices: Theory and Computation.638 for k in range(n-1):639 lam_1 = scale * diag_T[k]640 lam_2 = scale * diag_T[k+1]641 t_12 = scale * T[k, k+1]642 value = _eq_10_42(lam_1, lam_2, t_12)643 X[k, k+1] = value644 # Return the updated X matrix.645 return X646def _ell(A, m):647 """648 A helper function for expm_2009.649 Parameters650 ----------651 A : linear operator652 A linear operator whose norm of power we care about.653 m : int654 The power of the linear operator655 Returns656 -------657 value : int658 A value related to a bound.659 """660 if len(A.shape) != 2 or A.shape[0] != A.shape[1]:661 raise ValueError('expected A to be like a square matrix')662 p = 2*m + 1663 # The c_i are explained in (2.2) and (2.6) of the 2005 expm paper.664 # They are coefficients of terms of a generating function series expansion.665 abs_c_recip = scipy.misc.comb(2*p, p, exact=True) * math.factorial(2*p + 1)666 # This is explained after Eq. (1.2) of the 2009 expm paper.667 # It is the "unit roundoff" of IEEE double precision arithmetic.668 u = 2**-53669 # Compute the one-norm of matrix power p of abs(A).670 A_abs_onenorm = _onenorm_matrix_power_nnm(abs(A), p)671 # Treat zero norm as a special case.672 if not A_abs_onenorm:673 return 0674 alpha = A_abs_onenorm / (_onenorm(A) * abs_c_recip)675 log2_alpha_div_u = np.log2(alpha/u)676 value = int(np.ceil(log2_alpha_div_u / (2 * m)))...
test_structures.py
Source:test_structures.py
1import unittest2from ctypes import *3from ctypes.test import need_symbol4from struct import calcsize5import _testcapi6class SubclassesTest(unittest.TestCase):7 def test_subclass(self):8 class X(Structure):9 _fields_ = [("a", c_int)]10 class Y(X):11 _fields_ = [("b", c_int)]12 class Z(X):13 pass14 self.assertEqual(sizeof(X), sizeof(c_int))15 self.assertEqual(sizeof(Y), sizeof(c_int)*2)16 self.assertEqual(sizeof(Z), sizeof(c_int))17 self.assertEqual(X._fields_, [("a", c_int)])18 self.assertEqual(Y._fields_, [("b", c_int)])19 self.assertEqual(Z._fields_, [("a", c_int)])20 def test_subclass_delayed(self):21 class X(Structure):22 pass23 self.assertEqual(sizeof(X), 0)24 X._fields_ = [("a", c_int)]25 class Y(X):26 pass27 self.assertEqual(sizeof(Y), sizeof(X))28 Y._fields_ = [("b", c_int)]29 class Z(X):30 pass31 self.assertEqual(sizeof(X), sizeof(c_int))32 self.assertEqual(sizeof(Y), sizeof(c_int)*2)33 self.assertEqual(sizeof(Z), sizeof(c_int))34 self.assertEqual(X._fields_, [("a", c_int)])35 self.assertEqual(Y._fields_, [("b", c_int)])36 self.assertEqual(Z._fields_, [("a", c_int)])37class StructureTestCase(unittest.TestCase):38 formats = {"c": c_char,39 "b": c_byte,40 "B": c_ubyte,41 "h": c_short,42 "H": c_ushort,43 "i": c_int,44 "I": c_uint,45 "l": c_long,46 "L": c_ulong,47 "q": c_longlong,48 "Q": c_ulonglong,49 "f": c_float,50 "d": c_double,51 }52 def test_simple_structs(self):53 for code, tp in self.formats.items():54 class X(Structure):55 _fields_ = [("x", c_char),56 ("y", tp)]57 self.assertEqual((sizeof(X), code),58 (calcsize("c%c0%c" % (code, code)), code))59 def test_unions(self):60 for code, tp in self.formats.items():61 class X(Union):62 _fields_ = [("x", c_char),63 ("y", tp)]64 self.assertEqual((sizeof(X), code),65 (calcsize("%c" % (code)), code))66 def test_struct_alignment(self):67 class X(Structure):68 _fields_ = [("x", c_char * 3)]69 self.assertEqual(alignment(X), calcsize("s"))70 self.assertEqual(sizeof(X), calcsize("3s"))71 class Y(Structure):72 _fields_ = [("x", c_char * 3),73 ("y", c_int)]74 self.assertEqual(alignment(Y), alignment(c_int))75 self.assertEqual(sizeof(Y), calcsize("3si"))76 class SI(Structure):77 _fields_ = [("a", X),78 ("b", Y)]79 self.assertEqual(alignment(SI), max(alignment(Y), alignment(X)))80 self.assertEqual(sizeof(SI), calcsize("3s0i 3si 0i"))81 class IS(Structure):82 _fields_ = [("b", Y),83 ("a", X)]84 self.assertEqual(alignment(SI), max(alignment(X), alignment(Y)))85 self.assertEqual(sizeof(IS), calcsize("3si 3s 0i"))86 class XX(Structure):87 _fields_ = [("a", X),88 ("b", X)]89 self.assertEqual(alignment(XX), alignment(X))90 self.assertEqual(sizeof(XX), calcsize("3s 3s 0s"))91 def test_empty(self):92 # I had problems with these93 #94 # Although these are pathological cases: Empty Structures!95 class X(Structure):96 _fields_ = []97 class Y(Union):98 _fields_ = []99 # Is this really the correct alignment, or should it be 0?100 self.assertTrue(alignment(X) == alignment(Y) == 1)101 self.assertTrue(sizeof(X) == sizeof(Y) == 0)102 class XX(Structure):103 _fields_ = [("a", X),104 ("b", X)]105 self.assertEqual(alignment(XX), 1)106 self.assertEqual(sizeof(XX), 0)107 def test_fields(self):108 # test the offset and size attributes of Structure/Unoin fields.109 class X(Structure):110 _fields_ = [("x", c_int),111 ("y", c_char)]112 self.assertEqual(X.x.offset, 0)113 self.assertEqual(X.x.size, sizeof(c_int))114 self.assertEqual(X.y.offset, sizeof(c_int))115 self.assertEqual(X.y.size, sizeof(c_char))116 # readonly117 self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92)118 self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92)119 class X(Union):120 _fields_ = [("x", c_int),121 ("y", c_char)]122 self.assertEqual(X.x.offset, 0)123 self.assertEqual(X.x.size, sizeof(c_int))124 self.assertEqual(X.y.offset, 0)125 self.assertEqual(X.y.size, sizeof(c_char))126 # readonly127 self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92)128 self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92)129 # XXX Should we check nested data types also?130 # offset is always relative to the class...131 def test_packed(self):132 class X(Structure):133 _fields_ = [("a", c_byte),134 ("b", c_longlong)]135 _pack_ = 1136 self.assertEqual(sizeof(X), 9)137 self.assertEqual(X.b.offset, 1)138 class X(Structure):139 _fields_ = [("a", c_byte),140 ("b", c_longlong)]141 _pack_ = 2142 self.assertEqual(sizeof(X), 10)143 self.assertEqual(X.b.offset, 2)144 import struct145 longlong_size = struct.calcsize("q")146 longlong_align = struct.calcsize("bq") - longlong_size147 class X(Structure):148 _fields_ = [("a", c_byte),149 ("b", c_longlong)]150 _pack_ = 4151 self.assertEqual(sizeof(X), min(4, longlong_align) + longlong_size)152 self.assertEqual(X.b.offset, min(4, longlong_align))153 class X(Structure):154 _fields_ = [("a", c_byte),155 ("b", c_longlong)]156 _pack_ = 8157 self.assertEqual(sizeof(X), min(8, longlong_align) + longlong_size)158 self.assertEqual(X.b.offset, min(8, longlong_align))159 d = {"_fields_": [("a", "b"),160 ("b", "q")],161 "_pack_": -1}162 self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)163 # Issue 15989164 d = {"_fields_": [("a", c_byte)],165 "_pack_": _testcapi.INT_MAX + 1}166 self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)167 d = {"_fields_": [("a", c_byte)],168 "_pack_": _testcapi.UINT_MAX + 2}169 self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)170 def test_initializers(self):171 class Person(Structure):172 _fields_ = [("name", c_char*6),173 ("age", c_int)]174 self.assertRaises(TypeError, Person, 42)175 self.assertRaises(ValueError, Person, "asldkjaslkdjaslkdj")176 self.assertRaises(TypeError, Person, "Name", "HI")177 # short enough178 self.assertEqual(Person("12345", 5).name, "12345")179 # exact fit180 self.assertEqual(Person("123456", 5).name, "123456")181 # too long182 self.assertRaises(ValueError, Person, "1234567", 5)183 def test_conflicting_initializers(self):184 class POINT(Structure):185 _fields_ = [("x", c_int), ("y", c_int)]186 # conflicting positional and keyword args187 self.assertRaises(TypeError, POINT, 2, 3, x=4)188 self.assertRaises(TypeError, POINT, 2, 3, y=4)189 # too many initializers190 self.assertRaises(TypeError, POINT, 2, 3, 4)191 def test_keyword_initializers(self):192 class POINT(Structure):193 _fields_ = [("x", c_int), ("y", c_int)]194 pt = POINT(1, 2)195 self.assertEqual((pt.x, pt.y), (1, 2))196 pt = POINT(y=2, x=1)197 self.assertEqual((pt.x, pt.y), (1, 2))198 def test_invalid_field_types(self):199 class POINT(Structure):200 pass201 self.assertRaises(TypeError, setattr, POINT, "_fields_", [("x", 1), ("y", 2)])202 def test_invalid_name(self):203 # field name must be string204 def declare_with_name(name):205 class S(Structure):206 _fields_ = [(name, c_int)]207 self.assertRaises(TypeError, declare_with_name, u"x\xe9")208 def test_intarray_fields(self):209 class SomeInts(Structure):210 _fields_ = [("a", c_int * 4)]211 # can use tuple to initialize array (but not list!)212 self.assertEqual(SomeInts((1, 2)).a[:], [1, 2, 0, 0])213 self.assertEqual(SomeInts((1, 2)).a[::], [1, 2, 0, 0])214 self.assertEqual(SomeInts((1, 2)).a[::-1], [0, 0, 2, 1])215 self.assertEqual(SomeInts((1, 2)).a[::2], [1, 0])216 self.assertEqual(SomeInts((1, 2)).a[1:5:6], [2])217 self.assertEqual(SomeInts((1, 2)).a[6:4:-1], [])218 self.assertEqual(SomeInts((1, 2, 3, 4)).a[:], [1, 2, 3, 4])219 self.assertEqual(SomeInts((1, 2, 3, 4)).a[::], [1, 2, 3, 4])220 # too long221 # XXX Should raise ValueError?, not RuntimeError222 self.assertRaises(RuntimeError, SomeInts, (1, 2, 3, 4, 5))223 def test_nested_initializers(self):224 # test initializing nested structures225 class Phone(Structure):226 _fields_ = [("areacode", c_char*6),227 ("number", c_char*12)]228 class Person(Structure):229 _fields_ = [("name", c_char * 12),230 ("phone", Phone),231 ("age", c_int)]232 p = Person("Someone", ("1234", "5678"), 5)233 self.assertEqual(p.name, "Someone")234 self.assertEqual(p.phone.areacode, "1234")235 self.assertEqual(p.phone.number, "5678")236 self.assertEqual(p.age, 5)237 @need_symbol('c_wchar')238 def test_structures_with_wchar(self):239 class PersonW(Structure):240 _fields_ = [("name", c_wchar * 12),241 ("age", c_int)]242 p = PersonW(u"Someone")243 self.assertEqual(p.name, "Someone")244 self.assertEqual(PersonW(u"1234567890").name, u"1234567890")245 self.assertEqual(PersonW(u"12345678901").name, u"12345678901")246 # exact fit247 self.assertEqual(PersonW(u"123456789012").name, u"123456789012")248 #too long249 self.assertRaises(ValueError, PersonW, u"1234567890123")250 def test_init_errors(self):251 class Phone(Structure):252 _fields_ = [("areacode", c_char*6),253 ("number", c_char*12)]254 class Person(Structure):255 _fields_ = [("name", c_char * 12),256 ("phone", Phone),257 ("age", c_int)]258 cls, msg = self.get_except(Person, "Someone", (1, 2))259 self.assertEqual(cls, RuntimeError)260 # In Python 2.5, Exception is a new-style class, and the repr changed261 if issubclass(Exception, object):262 self.assertEqual(msg,263 "(Phone) <type 'exceptions.TypeError'>: "264 "expected string or Unicode object, int found")265 else:266 # Compatibility no longer strictly required267 self.assertEqual(msg,268 "(Phone) exceptions.TypeError: "269 "expected string or Unicode object, int found")270 cls, msg = self.get_except(Person, "Someone", ("a", "b", "c"))271 self.assertEqual(cls, RuntimeError)272 if issubclass(Exception, object):273 self.assertEqual(msg,274 "(Phone) <type 'exceptions.TypeError'>: too many initializers")275 else:276 self.assertEqual(msg, "(Phone) exceptions.TypeError: too many initializers")277 def test_huge_field_name(self):278 # issue12881: segfault with large structure field names279 def create_class(length):280 class S(Structure):281 _fields_ = [('x' * length, c_int)]282 for length in [10 ** i for i in range(0, 8)]:283 try:284 create_class(length)285 except MemoryError:286 # MemoryErrors are OK, we just don't want to segfault287 pass288 def get_except(self, func, *args):289 try:290 func(*args)291 except Exception, detail:292 return detail.__class__, str(detail)293 @unittest.skip('test disabled')294 def test_subclass_creation(self):295 meta = type(Structure)296 # same as 'class X(Structure): pass'297 # fails, since we need either a _fields_ or a _abstract_ attribute298 cls, msg = self.get_except(meta, "X", (Structure,), {})299 self.assertEqual((cls, msg),300 (AttributeError, "class must define a '_fields_' attribute"))301 def test_abstract_class(self):302 class X(Structure):303 _abstract_ = "something"304 # try 'X()'305 cls, msg = self.get_except(eval, "X()", locals())306 self.assertEqual((cls, msg), (TypeError, "abstract class"))307 def test_methods(self):308## class X(Structure):309## _fields_ = []310 self.assertIn("in_dll", dir(type(Structure)))311 self.assertIn("from_address", dir(type(Structure)))312 self.assertIn("in_dll", dir(type(Structure)))313 def test_positional_args(self):314 # see also http://bugs.python.org/issue5042315 class W(Structure):316 _fields_ = [("a", c_int), ("b", c_int)]317 class X(W):318 _fields_ = [("c", c_int)]319 class Y(X):320 pass321 class Z(Y):322 _fields_ = [("d", c_int), ("e", c_int), ("f", c_int)]323 z = Z(1, 2, 3, 4, 5, 6)324 self.assertEqual((z.a, z.b, z.c, z.d, z.e, z.f),325 (1, 2, 3, 4, 5, 6))326 z = Z(1)327 self.assertEqual((z.a, z.b, z.c, z.d, z.e, z.f),328 (1, 0, 0, 0, 0, 0))329 self.assertRaises(TypeError, lambda: Z(1, 2, 3, 4, 5, 6, 7))330class PointerMemberTestCase(unittest.TestCase):331 def test(self):332 # a Structure with a POINTER field333 class S(Structure):334 _fields_ = [("array", POINTER(c_int))]335 s = S()336 # We can assign arrays of the correct type337 s.array = (c_int * 3)(1, 2, 3)338 items = [s.array[i] for i in range(3)]339 self.assertEqual(items, [1, 2, 3])340 # The following are bugs, but are included here because the unittests341 # also describe the current behaviour.342 #343 # This fails with SystemError: bad arg to internal function344 # or with IndexError (with a patch I have)345 s.array[0] = 42346 items = [s.array[i] for i in range(3)]347 self.assertEqual(items, [42, 2, 3])348 s.array[0] = 1349## s.array[1] = 42350 items = [s.array[i] for i in range(3)]351 self.assertEqual(items, [1, 2, 3])352 def test_none_to_pointer_fields(self):353 class S(Structure):354 _fields_ = [("x", c_int),355 ("p", POINTER(c_int))]356 s = S()357 s.x = 12345678358 s.p = None359 self.assertEqual(s.x, 12345678)360class TestRecursiveStructure(unittest.TestCase):361 def test_contains_itself(self):362 class Recursive(Structure):363 pass364 try:365 Recursive._fields_ = [("next", Recursive)]366 except AttributeError, details:367 self.assertIn("Structure or union cannot contain itself",368 str(details))369 else:370 self.fail("Structure or union cannot contain itself")371 def test_vice_versa(self):372 class First(Structure):373 pass374 class Second(Structure):375 pass376 First._fields_ = [("second", Second)]377 try:378 Second._fields_ = [("first", First)]379 except AttributeError, details:380 self.assertIn("_fields_ is final", str(details))381 else:382 self.fail("AttributeError not raised")383if __name__ == '__main__':...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!