machinevision-toolbox-python 1.0.2__tar.gz → 1.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/PKG-INFO +1 -1
  2. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/pyproject.toml +2 -8
  3. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageBlobs.py +110 -150
  4. machinevision_toolbox_python-1.0.2/figs/MVTBDataLogo.png +0 -0
  5. machinevision_toolbox_python-1.0.2/figs/VisionToolboxLogo_CircBlack.png +0 -0
  6. machinevision_toolbox_python-1.0.2/figs/VisionToolboxLogo_NoBackgnd@2x.png +0 -0
  7. machinevision_toolbox_python-1.0.2/figs/blobs_graph.png +0 -0
  8. machinevision_toolbox_python-1.0.2/figs/colorspace.png +0 -0
  9. machinevision_toolbox_python-1.0.2/figs/cube.png +0 -0
  10. machinevision_toolbox_python-1.0.2/figs/cube_fisheye.png +0 -0
  11. machinevision_toolbox_python-1.0.2/figs/gallery1.png +0 -0
  12. machinevision_toolbox_python-1.0.2/figs/hough.png +0 -0
  13. machinevision_toolbox_python-1.0.2/figs/matching.png +0 -0
  14. machinevision_toolbox_python-1.0.2/figs/matching_ransac.png +0 -0
  15. machinevision_toolbox_python-1.0.2/figs/mona+smooth.png +0 -0
  16. machinevision_toolbox_python-1.0.2/figs/mona.png +0 -0
  17. machinevision_toolbox_python-1.0.2/figs/mona_smooth.png +0 -0
  18. machinevision_toolbox_python-1.0.2/figs/multi.png +0 -0
  19. machinevision_toolbox_python-1.0.2/figs/multi_labelled.png +0 -0
  20. machinevision_toolbox_python-1.0.2/figs/shark2+boxes.png +0 -0
  21. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/.gitignore +0 -0
  22. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/CHANGELOG.md +0 -0
  23. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/LICENSE +0 -0
  24. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/Makefile +0 -0
  25. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/NOTES +0 -0
  26. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/README.md +0 -0
  27. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/bun.png +0 -0
  28. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/camtest.py +0 -0
  29. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/dependencies.pdf +0 -0
  30. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/README.md +0 -0
  31. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/blobs1.py +0 -0
  32. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/blobs2.py +0 -0
  33. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/bunny.py +0 -0
  34. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/color.py +0 -0
  35. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/corners.py +0 -0
  36. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/matching.py +0 -0
  37. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/monalisa.py +0 -0
  38. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/morphdemo.py +0 -0
  39. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/mwe.py +0 -0
  40. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/randomdots.py +0 -0
  41. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/ransac_line.py +0 -0
  42. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/readme.py +0 -0
  43. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/examples/showzip.py +0 -0
  44. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/findimages.py +0 -0
  45. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/ilabel.c +0 -0
  46. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/ilabel.py-unopt +0 -0
  47. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/IBVS.ipynb +0 -0
  48. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/ImageMotion.ipynb +0 -0
  49. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/Untitled.ipynb +0 -0
  50. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/Untitled1.ipynb +0 -0
  51. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/blob.ipynb +0 -0
  52. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/calibration-fixture.png +0 -0
  53. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/calibration.ipynb +0 -0
  54. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/camera.ipynb +0 -0
  55. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/chap10.ipynb +0 -0
  56. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/color-images.ipynb +0 -0
  57. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/cones.ipynb +0 -0
  58. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/fiducuals.ipynb +0 -0
  59. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/finding-blobs.ipynb +0 -0
  60. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/gamma.ipynb +0 -0
  61. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/greyscale-images.ipynb +0 -0
  62. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/homogeneous-coords.ipynb +0 -0
  63. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/homography.ipynb +0 -0
  64. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/image-features.ipynb +0 -0
  65. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/image.ipynb +0 -0
  66. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/imageprocessing.ipynb +0 -0
  67. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/images/apriltags.png +0 -0
  68. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/images/aruco.png +0 -0
  69. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/images/butterfly.jpg +0 -0
  70. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/images/calib-image.png +0 -0
  71. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/images/calibration-fixture.png +0 -0
  72. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/images/coordinate-frames.png +0 -0
  73. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/images/output_9.png +0 -0
  74. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/point-features.ipynb +0 -0
  75. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/sift.ipynb +0 -0
  76. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/notebooks/unknown_camera.py +0 -0
  77. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/phone.py +0 -0
  78. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/setup.cfg +0 -0
  79. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/BagOfWords.py +0 -0
  80. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/BundleAdjust.py +0 -0
  81. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/Camera.py +0 -0
  82. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageColor.py +0 -0
  83. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageConstants.py +0 -0
  84. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageCore.py +0 -0
  85. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageFiducials.py +0 -0
  86. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageIO.py +0 -0
  87. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageLineFeatures.py +0 -0
  88. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageMorph.py +0 -0
  89. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageMultiview.py +0 -0
  90. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImagePointFeatures.py +0 -0
  91. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageProcessing.py +0 -0
  92. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageRegionFeatures.py +0 -0
  93. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageReshape.py +0 -0
  94. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageSpatial.py +0 -0
  95. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/ImageWholeFeatures.py +0 -0
  96. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/PointCloud.py +0 -0
  97. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/Sources.py +0 -0
  98. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/VisualServo.py +0 -0
  99. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/__init__.py +0 -0
  100. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/aruco0.pdf +0 -0
  101. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/aruco50.pdf +0 -0
  102. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/__init__.py +0 -0
  103. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/color.py +0 -0
  104. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/data.py +0 -0
  105. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/esttheta.py +0 -0
  106. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/findpeaks.py +0 -0
  107. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/graphics.py +0 -0
  108. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/imageio.py +0 -0
  109. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/meshgrid.py +0 -0
  110. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/shapes.py +0 -0
  111. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/types.py +0 -0
  112. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/base/version.py +0 -0
  113. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/bin/ce.py +0 -0
  114. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/bin/imtool.py +0 -0
  115. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/bin/mvtbtool.py +0 -0
  116. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/bin/tagtool.py +0 -0
  117. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/blocks/Icons/camera.png +0 -0
  118. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/blocks/Icons/estpose_p.png +0 -0
  119. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/blocks/Icons/icons.sh +0 -0
  120. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/blocks/Icons/imageplane.png +0 -0
  121. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/blocks/Icons/visjac_p.png +0 -0
  122. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/blocks/__init__.py +0 -0
  123. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/blocks/camera.py +0 -0
  124. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/blocks/test_blocks.py +0 -0
  125. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/camera_derivatives.py +0 -0
  126. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/decorators.py +0 -0
  127. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/fiducial.py +0 -0
  128. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/machinevision-toolbox-python.code-workspace +0 -0
  129. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/mvtb_types.py +0 -0
  130. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/src/machinevisiontoolbox/newcameras.py +0 -0
  131. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/symbolic/README.md +0 -0
  132. {machinevision_toolbox_python-1.0.2 → machinevision_toolbox_python-1.0.3}/symbolic/bundle-adjust.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machinevision-toolbox-python
3
- Version: 1.0.2
3
+ Version: 1.0.3
4
4
  Summary: Python tools for machine vision - education and research
5
5
  Project-URL: Homepage, https://github.com/petercorke/machinevision-toolbox-python
6
6
  Project-URL: Bug Tracker, https://github.com/pypa/sampleproject/issues
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "machinevision-toolbox-python"
3
- version = "1.0.2"
3
+ version = "1.0.3"
4
4
  authors = [
5
5
  { name = "Peter Corke", email = "rvc@petercorke.com" },
6
6
  { name = "Dorian Tsai" },
@@ -95,13 +95,7 @@ build-backend = "hatchling.build"
95
95
  packages = ["src/machinevisiontoolbox"]
96
96
 
97
97
  [tool.hatch.build.targets.sdist]
98
- exclude = [
99
- "/mvtb-data",
100
- "/docs",
101
- "/tests",
102
- "/.git",
103
- "/.github",
104
- ]
98
+ exclude = ["/mvtb-data", "/docs", "/tests", "/.git", "/.github", "/figs"]
105
99
 
106
100
  [tool.black]
107
101
  line-length = 88
@@ -36,37 +36,6 @@ Defines two key classes:
36
36
  """
37
37
 
38
38
 
39
- _moment_tuple = namedtuple(
40
- "moments",
41
- [
42
- "m00",
43
- "m10",
44
- "m01",
45
- "m20",
46
- "m11",
47
- "m02",
48
- "m30",
49
- "m21",
50
- "m12",
51
- "m03",
52
- "mu20",
53
- "mu11",
54
- "mu02",
55
- "mu30",
56
- "mu21",
57
- "mu12",
58
- "mu03",
59
- "nu20",
60
- "nu11",
61
- "nu02",
62
- "nu30",
63
- "nu21",
64
- "nu12",
65
- "nu03",
66
- ],
67
- )
68
-
69
-
70
39
  class Blob:
71
40
  id = None
72
41
  bbox = None
@@ -81,7 +50,6 @@ class Blob:
81
50
  uc = None
82
51
  vc = None
83
52
  level = None
84
- _moments = None
85
53
 
86
54
  def __init__(self):
87
55
  """Constructor for Blob class
@@ -290,11 +258,6 @@ class Blobs(UserList): # lgtm[py/missing-equals]
290
258
  pp = contour[0, :]
291
259
  blob.color = image.A[pp[1], pp[0]]
292
260
 
293
- ## moments
294
-
295
- # get moments as a dictionary for each contour
296
- blob._moments = cv.moments(contour)
297
-
298
261
  ## perimeter, the contour is not closed
299
262
 
300
263
  blob.perimeter = contour.T
@@ -302,8 +265,13 @@ class Blobs(UserList): # lgtm[py/missing-equals]
302
265
 
303
266
  blob.contourpoint = blob.perimeter[:, 0]
304
267
 
268
+ ## moments
269
+
270
+ # get moments as a dictionary for each contour
271
+ moments = cv.moments(contour)
272
+
305
273
  ## For a single set pixel OpenCV returns all moments as zero, let's fix it
306
- if blob._moments["m00"] == 0:
274
+ if moments["m00"] == 0:
307
275
  runts += 1
308
276
 
309
277
  # Raw moments
@@ -322,94 +290,57 @@ class Blobs(UserList): # lgtm[py/missing-equals]
322
290
  ]:
323
291
  u = uv[0]
324
292
  v = uv[1]
325
- blob._moments[f"m{p}{q}"] += u**p * v**q
293
+ moments[f"m{p}{q}"] += u**p * v**q
326
294
 
327
295
  # Central moments
328
- blob._moments["mu10"] = blob._moments["mu01"] = 0
329
- blob._moments["mu20"] = (
330
- blob._moments["m20"]
331
- - blob._moments["m10"] ** 2 / blob._moments["m00"]
332
- )
333
- blob._moments["mu02"] = (
334
- blob._moments["m02"]
335
- - blob._moments["m01"] ** 2 / blob._moments["m00"]
336
- )
337
- blob._moments["mu11"] = (
338
- blob._moments["m11"]
339
- - blob._moments["m10"] * blob._moments["m01"] / blob._moments["m00"]
296
+ moments["mu10"] = moments["mu01"] = 0
297
+ moments["mu20"] = moments["m20"] - moments["m10"] ** 2 / moments["m00"]
298
+ moments["mu02"] = moments["m02"] - moments["m01"] ** 2 / moments["m00"]
299
+ moments["mu11"] = (
300
+ moments["m11"] - moments["m10"] * moments["m01"] / moments["m00"]
340
301
  )
341
302
 
342
303
  # Third-order central moments
343
- blob._moments["mu30"] = (
344
- blob._moments["m30"]
345
- - 3
346
- * blob._moments["m20"]
347
- * blob._moments["m10"]
348
- / blob._moments["m00"]
349
- + 2 * (blob._moments["m10"] ** 3) / (blob._moments["m00"] ** 2)
304
+ moments["mu30"] = (
305
+ moments["m30"]
306
+ - 3 * moments["m20"] * moments["m10"] / moments["m00"]
307
+ + 2 * (moments["m10"] ** 3) / (moments["m00"] ** 2)
350
308
  )
351
- blob._moments["mu03"] = (
352
- blob._moments["m03"]
353
- - 3
354
- * blob._moments["m02"]
355
- * blob._moments["m01"]
356
- / blob._moments["m00"]
357
- + 2 * (blob._moments["m01"] ** 3) / (blob._moments["m00"] ** 2)
309
+ moments["mu03"] = (
310
+ moments["m03"]
311
+ - 3 * moments["m02"] * moments["m01"] / moments["m00"]
312
+ + 2 * (moments["m01"] ** 3) / (moments["m00"] ** 2)
358
313
  )
359
- blob._moments["mu21"] = (
360
- blob._moments["m21"]
361
- - 2
362
- * blob._moments["m11"]
363
- * blob._moments["m10"]
364
- / blob._moments["m00"]
365
- - blob._moments["m20"] * blob._moments["m01"] / blob._moments["m00"]
366
- + 2
367
- * (blob._moments["m10"] ** 2 * blob._moments["m01"])
368
- / (blob._moments["m00"] ** 2)
314
+ moments["mu21"] = (
315
+ moments["m21"]
316
+ - 2 * moments["m11"] * moments["m10"] / moments["m00"]
317
+ - moments["m20"] * moments["m01"] / moments["m00"]
318
+ + 2 * (moments["m10"] ** 2 * moments["m01"]) / (moments["m00"] ** 2)
369
319
  )
370
- blob._moments["mu12"] = (
371
- blob._moments["m12"]
372
- - 2
373
- * blob._moments["m11"]
374
- * blob._moments["m01"]
375
- / blob._moments["m00"]
376
- - blob._moments["m02"] * blob._moments["m10"] / blob._moments["m00"]
377
- + 2
378
- * (blob._moments["m01"] ** 2 * blob._moments["m10"])
379
- / (blob._moments["m00"] ** 2)
320
+ moments["mu12"] = (
321
+ moments["m12"]
322
+ - 2 * moments["m11"] * moments["m01"] / moments["m00"]
323
+ - moments["m02"] * moments["m10"] / moments["m00"]
324
+ + 2 * (moments["m01"] ** 2 * moments["m10"]) / (moments["m00"] ** 2)
380
325
  )
381
326
 
382
327
  # Normalised central moments
383
- blob._moments["nu20"] = blob._moments["mu20"] / (
384
- blob._moments["m00"] ** (1 + (2 / 2))
385
- )
386
- blob._moments["nu02"] = blob._moments["mu02"] / (
387
- blob._moments["m00"] ** (1 + (2 / 2))
388
- )
389
- blob._moments["nu11"] = blob._moments["mu11"] / (
390
- blob._moments["m00"] ** (1 + (2 / 2))
391
- )
328
+ moments["nu20"] = moments["mu20"] / (moments["m00"] ** (1 + (2 / 2)))
329
+ moments["nu02"] = moments["mu02"] / (moments["m00"] ** (1 + (2 / 2)))
330
+ moments["nu11"] = moments["mu11"] / (moments["m00"] ** (1 + (2 / 2)))
392
331
 
393
332
  # Third-order normalised moments
394
- blob._moments["nu30"] = blob._moments["mu30"] / (
395
- blob._moments["m00"] ** (1 + (3 / 2))
396
- )
397
- blob._moments["nu03"] = blob._moments["mu03"] / (
398
- blob._moments["m00"] ** (1 + (3 / 2))
399
- )
400
- blob._moments["nu21"] = blob._moments["mu21"] / (
401
- blob._moments["m00"] ** (1 + (3 / 2))
402
- )
403
- blob._moments["nu12"] = blob._moments["mu12"] / (
404
- blob._moments["m00"] ** (1 + (3 / 2))
405
- )
333
+ moments["nu30"] = moments["mu30"] / (moments["m00"] ** (1 + (3 / 2)))
334
+ moments["nu03"] = moments["mu03"] / (moments["m00"] ** (1 + (3 / 2)))
335
+ moments["nu21"] = moments["mu21"] / (moments["m00"] ** (1 + (3 / 2)))
336
+ moments["nu12"] = moments["mu12"] / (moments["m00"] ** (1 + (3 / 2)))
406
337
 
407
- allblobs.append(blob)
408
- self.data.append(blob)
338
+ blob.moments = moments
339
+ allblobs.append(blob) # append to the list of all blobs
409
340
 
410
341
  ## second pass: equivalent ellipse
411
342
 
412
- for blob, contour in zip(self.data, contours):
343
+ for blob, contour in zip(allblobs, contours):
413
344
  ## moment hierarchy
414
345
 
415
346
  # for moments in a hierarchy, for any pq moment of a blob ignoring its
@@ -418,28 +349,24 @@ class Blobs(UserList): # lgtm[py/missing-equals]
418
349
  # use to compute area, centroid etc. for each contour
419
350
 
420
351
  # TODO: this should recurse all the way down
421
- M = blob._moments
352
+ M = blob.moments
422
353
  for child in blob.children:
423
354
  # subtract moments of the child
424
- M = {key: M[key] - allblobs[child]._moments[key] for key in M}
425
-
426
- # convert dict to named tuple, easier to access using dot notation
427
- M = _moment_tuple._make([M[field] for field in _moment_tuple._fields])
428
- blob._moments = M
355
+ M = {key: M[key] - allblobs[child].moments[key] for key in M}
356
+ blob.moments = M
429
357
 
430
358
  ## centroid
431
- if M.m00 == 0:
359
+ if M["m00"] == 0:
432
360
  continue
433
361
 
434
- blob.uc = M.m10 / M.m00
435
- blob.vc = M.m01 / M.m00
436
-
362
+ blob.uc = M["m10"] / M["m00"]
363
+ blob.vc = M["m01"] / M["m00"]
437
364
  ## equivalent ellipse
438
- J = np.array([[M.mu20, M.mu11], [M.mu11, M.mu02]])
365
+ J = np.array([[M["mu20"], M["mu11"]], [M["mu11"], M["mu02"]]])
439
366
  e, X = np.linalg.eig(J)
440
367
 
441
- blob.a = 2.0 * np.sqrt(e.max() / M.m00)
442
- blob.b = 2.0 * np.sqrt(e.min() / M.m00)
368
+ blob.a = 2.0 * np.sqrt(e.max() / M["m00"])
369
+ blob.b = 2.0 * np.sqrt(e.min() / M["m00"])
443
370
 
444
371
  # find eigenvector for largest eigenvalue
445
372
  k = np.argmax(e)
@@ -462,13 +389,19 @@ class Blobs(UserList): # lgtm[py/missing-equals]
462
389
  kfactor = kulpa
463
390
  else:
464
391
  kfactor = 1.0
465
- blob.circularity = (4.0 * np.pi * M.m00) / (
392
+ blob.circularity = (4.0 * np.pi * M["m00"]) / (
466
393
  blob.perimeter_length * kfactor
467
394
  ) ** 2
468
395
 
396
+ for blob in allblobs:
397
+ M = blob.moments
398
+ # convert moments dict to named tuple, easier to access using dot notation
399
+ blob.moments = namedtuple("moment_tuple", M.keys())(*M.values())
400
+
469
401
  ## third pass, region tree coloring to determine vertex depth
470
- while any([b.level is None for b in self.data]): # while some uncolored
471
- for blob in self.data:
402
+ # level 0 is a parent, level > 0 is a child
403
+ while any([b.level is None for b in allblobs]): # while some uncolored
404
+ for blob in allblobs:
472
405
  if blob.level is None:
473
406
  if blob.parent == -1:
474
407
  blob.level = 0 # root level
@@ -478,17 +411,18 @@ class Blobs(UserList): # lgtm[py/missing-equals]
478
411
 
479
412
  self.filter(**kwargs)
480
413
 
481
- for blob in self.data:
414
+ for blob in allblobs:
482
415
  if blob.parent != -1:
483
416
  blob.parent = allblobs[blob.parent]
484
417
  else:
485
418
  blob.parent = None
486
419
  if len(blob.children) > 0:
487
420
  blob.children = [allblobs[i] for i in blob.children] ##
488
-
489
421
  if runts > 0:
490
422
  print(f"blobs: found {runts} runt blob{'s' if runts > 1 else ''}")
491
423
 
424
+ self.data = allblobs
425
+
492
426
  return
493
427
 
494
428
  def filter(self, area=None, circularity=None, color=None, touch=None, aspect=None):
@@ -683,7 +617,7 @@ class Blobs(UserList): # lgtm[py/missing-equals]
683
617
  b.id,
684
618
  b.parent.id if b.parent else -1,
685
619
  f"{b.uc:.1f}, {b.vc:.1f}",
686
- b._moments.m00,
620
+ b.moments.m00,
687
621
  b.touch,
688
622
  b.perimeter_length,
689
623
  b.circularity,
@@ -712,7 +646,7 @@ class Blobs(UserList): # lgtm[py/missing-equals]
712
646
  >>> blobs[0].area
713
647
  >>> blobs.area
714
648
  """
715
- return [b._moments.m00 for b in self.data]
649
+ return [b.moments.m00 for b in self.data]
716
650
 
717
651
  @property
718
652
  @scalar_result
@@ -991,7 +925,7 @@ class Blobs(UserList): # lgtm[py/missing-equals]
991
925
 
992
926
  :seealso: :meth:`bbox`
993
927
  """
994
- return [b._moments.m00 / (b.bbox[2] * b.bbox[3]) for b in self.data]
928
+ return [b.moments.m00 / (b.bbox[2] * b.bbox[3]) for b in self.data]
995
929
 
996
930
  @property
997
931
  @scalar_result
@@ -1192,7 +1126,7 @@ class Blobs(UserList): # lgtm[py/missing-equals]
1192
1126
 
1193
1127
  :seealso: :meth:`id` :meth:`children` :meth:`level` :meth:`dotfile`
1194
1128
  """
1195
- return [b.parent for b in self.data]
1129
+ return [b.parent.id if b.parent is not None else -1 for b in self.data]
1196
1130
 
1197
1131
  @property
1198
1132
  @scalar_result
@@ -1238,7 +1172,7 @@ class Blobs(UserList): # lgtm[py/missing-equals]
1238
1172
 
1239
1173
  :seealso: :meth:`parent` :meth:`level` :meth:`dotfile`
1240
1174
  """
1241
- return [b.children for b in self.data]
1175
+ return [[c.id for c in b.children] for b in self.data]
1242
1176
 
1243
1177
  @property
1244
1178
  @array_result
@@ -1272,7 +1206,7 @@ class Blobs(UserList): # lgtm[py/missing-equals]
1272
1206
 
1273
1207
  :seealso: :meth:`centroid` :meth:`humoments`
1274
1208
  """
1275
- return [b._moments for b in self.data]
1209
+ return [b.moments for b in self.data]
1276
1210
 
1277
1211
  @array_result
1278
1212
  def humoments(self):
@@ -1300,7 +1234,7 @@ class Blobs(UserList): # lgtm[py/missing-equals]
1300
1234
  """
1301
1235
 
1302
1236
  def hu(b):
1303
- m = b._moments
1237
+ m = b.moments
1304
1238
  phi = np.empty((7,))
1305
1239
  phi[0] = m.nu20 + m.nu02
1306
1240
  phi[1] = (m.nu20 - m.nu02) ** 2 + 4 * m.nu11**2
@@ -1863,7 +1797,7 @@ class Blobs(UserList): # lgtm[py/missing-equals]
1863
1797
  :seealso: :meth:`plot_axes` :meth:`plot_box` :meth:`plot_centroid` :func:`~spatialmath.base.plot_ellipse`
1864
1798
  """
1865
1799
  for blob in self:
1866
- m = blob._moments
1800
+ m = blob.moments
1867
1801
  # fmt: off
1868
1802
  J = np.array([
1869
1803
  [m.mu20, m.mu11],
@@ -2139,7 +2073,7 @@ class Blobs(UserList): # lgtm[py/missing-equals]
2139
2073
  for id, blob in enumerate(self):
2140
2074
  print(' "{:d}"'.format(id), file=f)
2141
2075
  print(
2142
- ' "{:d}" -> "{:d}"'.format(blob.parent.id if blob.parent else -1, id),
2076
+ ' "{:d}" -> "{:d}"'.format(blob.parent if blob.parent else -1, id),
2143
2077
  file=f,
2144
2078
  )
2145
2079
 
@@ -2195,18 +2129,37 @@ if __name__ == "__main__":
2195
2129
  from machinevisiontoolbox import Image
2196
2130
  import matplotlib.pyplot as plt
2197
2131
 
2198
- im = Image.Read("sharks.png")
2132
+ im = Image.String(
2133
+ r"""
2134
+ ..........
2135
+ ..###.....
2136
+ ..###.....
2137
+ ..###.....
2138
+ ..........
2139
+ ....####..
2140
+ ....####..
2141
+ ....####..
2142
+ ....####..
2143
+ ..........
2144
+ """,
2145
+ binary=True,
2146
+ )
2199
2147
  blobs = im.blobs()
2200
- im.disp()
2201
- blobs.plot_labelbox(color="yellow")
2202
- plt.show(block=True)
2203
- # frames = SE2.Empty()
2204
- # for blob in blobs:
2205
- # frames.append(SE2(*blob.centroid, blob.orientation))
2206
- frames = blobs.blob_frame()
2207
- print(frames)
2208
- print(blobs[1].moments.m00)
2209
- print(blobs.humoments())
2148
+ print(blobs)
2149
+ pass
2150
+
2151
+ # im = Image.Read("sharks.png")
2152
+ # blobs = im.blobs()
2153
+ # im.disp()
2154
+ # blobs.plot_labelbox(color="yellow")
2155
+ # plt.show(block=True)
2156
+ # # frames = SE2.Empty()
2157
+ # # for blob in blobs:
2158
+ # # frames.append(SE2(*blob.centroid, blob.orientation))
2159
+ # frames = blobs.blob_frame()
2160
+ # print(frames)
2161
+ # print(blobs[1].moments.m00)
2162
+ # print(blobs.humoments())
2210
2163
 
2211
2164
  # im.disp()
2212
2165
  # blobs = im.blobs()
@@ -2227,10 +2180,10 @@ if __name__ == "__main__":
2227
2180
  # fillstyle="full",
2228
2181
  # )
2229
2182
 
2230
- # im = Image.Read("multiblobs.png")
2183
+ im = Image.Read("multiblobs.png")
2231
2184
 
2232
- # f = im.blobs()
2233
- # # z = f.label_image()
2185
+ f = im.blobs()
2186
+ # z = f.label_image()
2234
2187
 
2235
2188
  # labels = f.label_image()
2236
2189
  # labels.disp(
@@ -2239,6 +2192,13 @@ if __name__ == "__main__":
2239
2192
  # colorbar=dict(shrink=0.8, aspect=20 * 0.8),
2240
2193
  # block=True,
2241
2194
  # )
2195
+ print(f)
2196
+ f2 = f[2]
2197
+
2198
+ print(f2.parent)
2199
+ f1 = f[1]
2200
+ print(f1.children)
2201
+ f.dotfile(show=True)
2242
2202
  # pass
2243
2203
 
2244
2204
  # im = Image.Read('sharks.png')