machinevision-toolbox-python 1.0.1__py3-none-any.whl → 1.0.2__py3-none-any.whl

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 (30) hide show
  1. {machinevision_toolbox_python-1.0.1.dist-info → machinevision_toolbox_python-1.0.2.dist-info}/METADATA +30 -30
  2. {machinevision_toolbox_python-1.0.1.dist-info → machinevision_toolbox_python-1.0.2.dist-info}/RECORD +28 -17
  3. {machinevision_toolbox_python-1.0.1.dist-info → machinevision_toolbox_python-1.0.2.dist-info}/WHEEL +1 -2
  4. {machinevision_toolbox_python-1.0.1.dist-info → machinevision_toolbox_python-1.0.2.dist-info}/entry_points.txt +1 -0
  5. machinevisiontoolbox/ImageBlobs.py +142 -12
  6. machinevisiontoolbox/ImageCore.py +181 -35
  7. machinevisiontoolbox/ImageFiducials.py +208 -51
  8. machinevisiontoolbox/ImageIO.py +3 -5
  9. machinevisiontoolbox/ImagePointFeatures.py +2 -2
  10. machinevisiontoolbox/ImageReshape.py +51 -12
  11. machinevisiontoolbox/PointCloud.py +2 -3
  12. machinevisiontoolbox/Sources.py +0 -1
  13. machinevisiontoolbox/aruco0.pdf +0 -0
  14. machinevisiontoolbox/aruco50.pdf +0 -0
  15. machinevisiontoolbox/base/color.py +25 -18
  16. machinevisiontoolbox/base/graphics.py +324 -243
  17. machinevisiontoolbox/base/imageio.py +99 -20
  18. machinevisiontoolbox/bin/ce.py +27 -0
  19. machinevisiontoolbox/bin/imtool.py +161 -0
  20. machinevisiontoolbox/bin/mvtbtool.py +192 -0
  21. machinevisiontoolbox/bin/tagtool.py +250 -0
  22. machinevisiontoolbox/blocks/Icons/camera.png +0 -0
  23. machinevisiontoolbox/blocks/Icons/estpose_p.png +0 -0
  24. machinevisiontoolbox/blocks/Icons/icons.sh +4 -0
  25. machinevisiontoolbox/blocks/Icons/imageplane.png +0 -0
  26. machinevisiontoolbox/blocks/Icons/visjac_p.png +0 -0
  27. machinevisiontoolbox/blocks/test_blocks.py +0 -0
  28. machinevisiontoolbox/machinevision-toolbox-python.code-workspace +7 -0
  29. machinevision_toolbox_python-1.0.1.dist-info/top_level.txt +0 -1
  30. {machinevision_toolbox_python-1.0.1.dist-info → machinevision_toolbox_python-1.0.2.dist-info/licenses}/LICENSE +0 -0
@@ -1,51 +1,51 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: machinevision-toolbox-python
3
- Version: 1.0.1
3
+ Version: 1.0.2
4
4
  Summary: Python tools for machine vision - education and research
5
- Author: Dorian Tsai
6
- Author-email: Peter Corke <rvc@petercorke.com>
7
5
  Project-URL: Homepage, https://github.com/petercorke/machinevision-toolbox-python
8
6
  Project-URL: Bug Tracker, https://github.com/pypa/sampleproject/issues
9
7
  Project-URL: Documentation, https://petercorke.github.io/machinevision-toolbox-python
10
8
  Project-URL: GitHub Source, https://github.com/petercorke/machinevision-toolbox-python
11
9
  Project-URL: Changelog, https://github.com/petercorke/machinevision-toolbox-python/blob/master/CHANGELOG.md
12
- Keywords: machine vision,computer vision,multiview geometry,stereo vision,bundle adjustment,visual servoing,image features,color,blobs,morphology,image segmentation,opencv,open3d
10
+ Author: Dorian Tsai
11
+ Author-email: Peter Corke <rvc@petercorke.com>
12
+ License-File: LICENSE
13
+ Keywords: blobs,bundle adjustment,color,computer vision,image features,image segmentation,machine vision,morphology,multiview geometry,open3d,opencv,stereo vision,visual servoing
13
14
  Classifier: Development Status :: 5 - Production/Stable
14
15
  Classifier: Intended Audience :: Developers
15
- Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
16
18
  Classifier: Programming Language :: Python :: 3.10
17
19
  Classifier: Programming Language :: Python :: 3.11
18
20
  Classifier: Programming Language :: Python :: 3.12
19
- Classifier: License :: OSI Approved :: MIT License
20
- Classifier: Operating System :: OS Independent
21
- Requires-Python: >=3.7
22
- Description-Content-Type: text/markdown
23
- License-File: LICENSE
24
- Requires-Dist: numpy<2.0.0,>=1.17.4
25
- Requires-Dist: scipy
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: ansitable
26
23
  Requires-Dist: matplotlib
27
- Requires-Dist: opencv-python
28
- Requires-Dist: open3d
24
+ Requires-Dist: mvtb-data
25
+ Requires-Dist: numpy
29
26
  Requires-Dist: opencv-contrib-python
30
- Requires-Dist: spatialmath-python
27
+ Requires-Dist: opencv-python
31
28
  Requires-Dist: pgraph-python
32
- Requires-Dist: ansitable
33
- Requires-Dist: mvtb-data
29
+ Requires-Dist: scipy
30
+ Requires-Dist: spatialmath-python
34
31
  Provides-Extra: dev
35
- Requires-Dist: pytest; extra == "dev"
36
- Requires-Dist: coverage; extra == "dev"
37
- Requires-Dist: flake8; extra == "dev"
32
+ Requires-Dist: coverage; extra == 'dev'
33
+ Requires-Dist: flake8; extra == 'dev'
34
+ Requires-Dist: pytest; extra == 'dev'
38
35
  Provides-Extra: docs
39
- Requires-Dist: sphinx; extra == "docs"
40
- Requires-Dist: recommonmark; extra == "docs"
41
- Requires-Dist: sphinx-rtd-theme; extra == "docs"
42
- Requires-Dist: sphinx-autorun; extra == "docs"
43
- Requires-Dist: sphinxcontrib-jsmath; extra == "docs"
44
- Requires-Dist: sphinx-markdown-tables; extra == "docs"
45
- Requires-Dist: sphinx-favicon; extra == "docs"
36
+ Requires-Dist: recommonmark; extra == 'docs'
37
+ Requires-Dist: sphinx; extra == 'docs'
38
+ Requires-Dist: sphinx-autorun; extra == 'docs'
39
+ Requires-Dist: sphinx-favicon; extra == 'docs'
40
+ Requires-Dist: sphinx-markdown-tables; extra == 'docs'
41
+ Requires-Dist: sphinx-rtd-theme; extra == 'docs'
42
+ Requires-Dist: sphinxcontrib-jsmath; extra == 'docs'
46
43
  Provides-Extra: jupyter
47
- Requires-Dist: ipywidgets; extra == "jupyter"
48
- Requires-Dist: ipympl; extra == "jupyter"
44
+ Requires-Dist: ipympl; extra == 'jupyter'
45
+ Requires-Dist: ipywidgets; extra == 'jupyter'
46
+ Provides-Extra: open3d
47
+ Requires-Dist: open3d-python; extra == 'open3d'
48
+ Description-Content-Type: text/markdown
49
49
 
50
50
  # Machine Vision Toolbox for Python
51
51
 
@@ -1,47 +1,58 @@
1
1
  machinevisiontoolbox/BagOfWords.py,sha256=kHAt6P5Tz5iWpP9N-fcdL3KTwimBqxu9QQ1WRs04Lzc,19680
2
2
  machinevisiontoolbox/BundleAdjust.py,sha256=syBFkXwJcRWpNr0k6gu-J3shzH0ozbgOgwaZp844fqk,36081
3
3
  machinevisiontoolbox/Camera.py,sha256=Sz6MLiVpLEKX_EtBNcd3AhTjI3Qe_4E9JuB9ERgiugA,136424
4
- machinevisiontoolbox/ImageBlobs.py,sha256=O6ASg_gdiJ7f3HtogzsfDplCNSBTRyaB-8Xat_8Gc0Y,68961
4
+ machinevisiontoolbox/ImageBlobs.py,sha256=p9LL28SKUUVuRVb8wrxDPyXygmKqni9ReQFntrEv3ZY,73599
5
5
  machinevisiontoolbox/ImageColor.py,sha256=V4T_fs0EvFJegAQrNr-3pR7rg7Dye00g2V3JVEK4oOA,17111
6
6
  machinevisiontoolbox/ImageConstants.py,sha256=a9eCbfUFUiQj0HsEH291MjYYmXGJjYSIl6Lg7idDppw,20629
7
- machinevisiontoolbox/ImageCore.py,sha256=WHbd9L36bQFifzn89-IvDv3RH8i2TClK_KCYRgVyZlQ,92320
8
- machinevisiontoolbox/ImageFiducials.py,sha256=h0t5NJYr9M_wLRHifZeU2EStb3QllE7BsmRUXCq6vSk,16207
9
- machinevisiontoolbox/ImageIO.py,sha256=UbTzycJOE2Gf9pkya57-5Kzg3aEvNU4G0M_xFoApYo0,21843
7
+ machinevisiontoolbox/ImageCore.py,sha256=rTGHVYw9ayXmDKAXDaLAMuEKVk65aFQqeSUBxt_4qJ8,98404
8
+ machinevisiontoolbox/ImageFiducials.py,sha256=8QwHUrMclP3rLMr2swO44nORo6AJVuIZT777-1QSB44,22341
9
+ machinevisiontoolbox/ImageIO.py,sha256=9MOUSrM1xnkoHYk2W77G0IVPcVjX_YTCLfNg2ZbEFZ4,21935
10
10
  machinevisiontoolbox/ImageLineFeatures.py,sha256=IlWSZOrvLnzvLx1vf4GuXb4Icpj214jz9FCDleguV9s,9104
11
11
  machinevisiontoolbox/ImageMorph.py,sha256=1xn29MyEkrYRbw-Dg8X6qFKTf4_MDTQ5ddi7y8D-arw,23759
12
12
  machinevisiontoolbox/ImageMultiview.py,sha256=wQWcq2Er-EzNNQ7_0mZRuID9VFh4rCjXPxZ-yMiQ-W4,14703
13
- machinevisiontoolbox/ImagePointFeatures.py,sha256=mqG3ddncU_s4b_GiPh2EFgS-glBGa--PLjVivtCTyfk,75219
13
+ machinevisiontoolbox/ImagePointFeatures.py,sha256=Ran5vzBC3-_brg_X3b-qdXjpX0boEnzznhnkKD8J-wg,75269
14
14
  machinevisiontoolbox/ImageProcessing.py,sha256=pZuaVRlpskO2L3JCDh6BOVEfpTUhqKXwPh4usfcTKBM,38123
15
15
  machinevisiontoolbox/ImageRegionFeatures.py,sha256=MpqavHwkpevg_dD3zia0wMZMuOmatR2ndZ_TBQ_AbqE,14455
16
- machinevisiontoolbox/ImageReshape.py,sha256=mYxqVLMmDUMYsUSf70tZqpEXoUA_65HFcovv2Esg-Bk,45905
16
+ machinevisiontoolbox/ImageReshape.py,sha256=3DAlTBpUdljzJwxyCswRoNiTbGBBP8nTWNpsHoPn03I,47470
17
17
  machinevisiontoolbox/ImageSpatial.py,sha256=dxTiml3DLp3UXV5x4auo3IuQQJVXRKrjduOpogIeklE,71856
18
18
  machinevisiontoolbox/ImageWholeFeatures.py,sha256=OBGZ_elQ6LlOxN1Hgr4dGf4AOUdgxfAD2qkgAaA7uuU,34874
19
- machinevisiontoolbox/PointCloud.py,sha256=jTiqcOUe8MlpENHZJs_y9CurK3bwyVv8VIUP6BQ2ybk,23451
20
- machinevisiontoolbox/Sources.py,sha256=Z-cwsn8fuKzwVAPTx8h6Hr4axBhXi5i7NtcrlJKVWHI,28624
19
+ machinevisiontoolbox/PointCloud.py,sha256=AMQSXsgVneoEtecUVsvcup009Ja13NcsMZ2kMddyN-E,23455
20
+ machinevisiontoolbox/Sources.py,sha256=mcBYA9ccvqXjPK9npwt9zAnuP18sw-q2zhwem4xW_to,28572
21
21
  machinevisiontoolbox/VisualServo.py,sha256=PlHCz_jbvV1JFfDrePQQ7cP94Wr5nliulHtYEMGwJtw,59294
22
22
  machinevisiontoolbox/__init__.py,sha256=UcoSG7Cr9Qot3mg2q748jBbo3TUB2lch4VWzOydKe8U,1363
23
+ machinevisiontoolbox/aruco0.pdf,sha256=a_JZT-TfVv7tQNOvlHSZPf9QCNiOScm_q30jMF8T2ME,75233
24
+ machinevisiontoolbox/aruco50.pdf,sha256=wUwqNaDmZ5EFNl1GNF_O3YRztWOZBhTq7DdMdMTskQw,77285
23
25
  machinevisiontoolbox/camera_derivatives.py,sha256=uChdvsXC-25Cg7-xH7tIbxe3tcxxJGQ_nslSiCvnL88,17557
24
26
  machinevisiontoolbox/decorators.py,sha256=hBZzLFQDhVOS3mj5Rs4GHbIIf30g_C2LO5m2xyLzH7s,2281
25
27
  machinevisiontoolbox/fiducial.py,sha256=syC7iIz95nYBTr_njo4ZzLXOyAdAIqoAZq_wRVhyUHQ,1374
28
+ machinevisiontoolbox/machinevision-toolbox-python.code-workspace,sha256=pQBvdNW9qEbMp3qYKhvOgd3NYoO7vqnnbPMh4H8op_Y,44
26
29
  machinevisiontoolbox/mvtb_types.py,sha256=66Oa8-J0UyBTtZQ0hH1B9qPqqw7i7dTCYe3CvgnGpXg,434
27
30
  machinevisiontoolbox/newcameras.py,sha256=iQ8Fduiub4Clh1JIEVvQTXZVqXrmgzf0Y5iMPGTOW-w,1225
28
31
  machinevisiontoolbox/base/__init__.py,sha256=nQTxEyan6bOvovQKUWjag-VZzfM6P20CwUv7sbCrJEs,1547
29
- machinevisiontoolbox/base/color.py,sha256=0O_yyfOg2KV6Xk4gks728bc737rcRH_037MFSQUfYEQ,54329
32
+ machinevisiontoolbox/base/color.py,sha256=GQSQIHUKrKWxuBJ4a6kfTy05RQKUhFKA4q4JyjIU358,55067
30
33
  machinevisiontoolbox/base/data.py,sha256=tDwUOHzpvGnkzlUaA3p5jQr1rlv9WIr6taRBv3gnmeU,5988
31
34
  machinevisiontoolbox/base/esttheta.py,sha256=pYFguhXwo9FoaH0sRAXxrcEkECYttDPnHWBi1YMfISY,2323
32
35
  machinevisiontoolbox/base/findpeaks.py,sha256=e0dcG6ZqHMwpzRFQrZH9-OITzhspi6Lq1TZoS37IPQY,10377
33
- machinevisiontoolbox/base/graphics.py,sha256=WkqJPLKzZvSIJE5tFQ07Fa5dK8gBmJxGEvCwmxkVtrU,24663
34
- machinevisiontoolbox/base/imageio.py,sha256=mWYqjTEC1sGLR0HL1fwWw0J6EzdeaWRvmnhY2gTAdXM,37418
36
+ machinevisiontoolbox/base/graphics.py,sha256=L0YuIi-HHOhogtmfwMSy9SD5tG0zdxWAYojbhCrRYCc,28956
37
+ machinevisiontoolbox/base/imageio.py,sha256=qUZL7xz-S3o9Xh8vLVQAWqsL7HQQNtSUROERWsUimSo,40393
35
38
  machinevisiontoolbox/base/meshgrid.py,sha256=82u1ijws1zoXl5NLzTAMJjry9VEZuWqb_Akz6f1JJ8k,2937
36
39
  machinevisiontoolbox/base/shapes.py,sha256=2FmjeuDnehNF5ZmssFDawmblDpKhuVUI3CmXCcILJxg,9926
37
40
  machinevisiontoolbox/base/types.py,sha256=3znb81yTFb7sLrgjgt0P5q5wZa9_iRZGw_hWbINhCxc,4716
38
41
  machinevisiontoolbox/base/version.py,sha256=Wf76g7w1Ikff-3e-hlExYVRxvV92p04K1m_PZLH9T_I,875
42
+ machinevisiontoolbox/bin/ce.py,sha256=012zsKMT58WZxIsLq8nzDO6b-YK04kduaTwZLSwTdrI,846
43
+ machinevisiontoolbox/bin/imtool.py,sha256=7nHNMuoI0-5y4EdWWPkWlwKdgKVqDDbYPw2bozICLQk,4920
44
+ machinevisiontoolbox/bin/mvtbtool.py,sha256=ehzLW6mwkNsQJVW599NFZ3k5W3ANm9UHBnAP_wLCnsg,5740
45
+ machinevisiontoolbox/bin/tagtool.py,sha256=Gfre8skzAwZystfGFv18W6rNcnIykvtBoCvik80TWzw,7224
39
46
  machinevisiontoolbox/blocks/__init__.py,sha256=EsdfK2WxYLSo0SA5HSmlgsivLT1kDnoH9v-RTBDnWwc,142
40
47
  machinevisiontoolbox/blocks/camera.py,sha256=qWT_LoDFcZkCAlRqQkRDzX0fr4EvkEgdtGo0QPoO_8s,9776
41
48
  machinevisiontoolbox/blocks/test_blocks.py,sha256=ZKsDG_nG9g1t_OIFR6vX823yJojEAi5mtqj9PxKoDrg,1701
42
- machinevision_toolbox_python-1.0.1.dist-info/LICENSE,sha256=niCzY_CzbIMKuUZlUkGimjrKp0vkLAtcwFmoSuSKrdw,1068
43
- machinevision_toolbox_python-1.0.1.dist-info/METADATA,sha256=ZNSpL78lcKjOUrPmTmKiy6el3djAvjMZj1dHhtt3rrk,19866
44
- machinevision_toolbox_python-1.0.1.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
45
- machinevision_toolbox_python-1.0.1.dist-info/entry_points.txt,sha256=WkGwGZcQb334xVPQLt1cktOcWL3wXljzp1LkMO1PS30,114
46
- machinevision_toolbox_python-1.0.1.dist-info/top_level.txt,sha256=HC0K-k55L-H_l8QzNMmP1_vLgBkdTrsM0Kj_rjRrulo,21
47
- machinevision_toolbox_python-1.0.1.dist-info/RECORD,,
49
+ machinevisiontoolbox/blocks/Icons/camera.png,sha256=CGcTB_llMoucN-rfnP6ZP_7AfE_92z6JnCdam-hDLgs,1642
50
+ machinevisiontoolbox/blocks/Icons/estpose_p.png,sha256=1XrwL4OkotGWMwKmhnar3tt8cQWUdZiO7PxXD354T-E,4320
51
+ machinevisiontoolbox/blocks/Icons/icons.sh,sha256=teezrmF3es8c3-MvwG1lDCt9SKWEqA0eVHOKFeBugig,115
52
+ machinevisiontoolbox/blocks/Icons/imageplane.png,sha256=34FYQMzkq6foxvRU8pn0KkcHxpHRvsJRJSYKfNu13Eg,3902
53
+ machinevisiontoolbox/blocks/Icons/visjac_p.png,sha256=8X023l-C9Y5DfAN8wCdWYjSjq6wp1vRzuZ85sUbwxv8,3819
54
+ machinevision_toolbox_python-1.0.2.dist-info/METADATA,sha256=dLXvahd9CC0ah59W8SfIYchw7zDHjGz0AtKSLcvQiO8,19851
55
+ machinevision_toolbox_python-1.0.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
56
+ machinevision_toolbox_python-1.0.2.dist-info/entry_points.txt,sha256=ZX7Ox5l4VcwNurmTuD85Um5NpAipiKthfVe16cccWU8,162
57
+ machinevision_toolbox_python-1.0.2.dist-info/licenses/LICENSE,sha256=niCzY_CzbIMKuUZlUkGimjrKp0vkLAtcwFmoSuSKrdw,1068
58
+ machinevision_toolbox_python-1.0.2.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.1.0)
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
@@ -1,3 +1,4 @@
1
1
  [console_scripts]
2
2
  imtool = machinevisiontoolbox.bin.imtool:main
3
3
  mvtbtool = machinevisiontoolbox.bin.mvtbtool:main
4
+ tagtool = machinevisiontoolbox.bin.tagtool:main
@@ -17,7 +17,7 @@ import matplotlib.pyplot as plt
17
17
 
18
18
  import cv2 as cv
19
19
  from ansitable import ANSITable, Column
20
- from machinevisiontoolbox.base import color_bgr, plot_labelbox
20
+ from machinevisiontoolbox.base import plot_labelbox
21
21
  from spatialmath.base import plot_box, plot_point, isscalar
22
22
  from spatialmath import SE2, base
23
23
  from machinevisiontoolbox.decorators import scalar_result, array_result
@@ -81,6 +81,7 @@ class Blob:
81
81
  uc = None
82
82
  vc = None
83
83
  level = None
84
+ _moments = None
84
85
 
85
86
  def __init__(self):
86
87
  """Constructor for Blob class
@@ -99,7 +100,7 @@ class Blob:
99
100
  :return: compact string representation
100
101
  :rtype: str
101
102
  """
102
- return f"Blob[{self.id}](area={self._moments.m00:.2g}, color={self.color}, parent={self.parent.id if self.parent else None}"
103
+ return f"Blob[{self.id}](area={self.moments.m00:.2g}, color={self.color}, parent={self.parent.id if self.parent else None}"
103
104
 
104
105
  def __repr__(self):
105
106
  return str(self)
@@ -301,13 +302,110 @@ class Blobs(UserList): # lgtm[py/missing-equals]
301
302
 
302
303
  blob.contourpoint = blob.perimeter[:, 0]
303
304
 
304
- ## For a single set pixel OpenCV returns all moments as zero, skip such blobs
305
- ## TODO handle this situation by setting m00=1, m10=x, m01=y etc.
305
+ ## For a single set pixel OpenCV returns all moments as zero, let's fix it
306
306
  if blob._moments["m00"] == 0:
307
307
  runts += 1
308
- else:
309
- self.data.append(blob)
308
+
309
+ # Raw moments
310
+ for uv in contour:
311
+ for p, q in [
312
+ (0, 0),
313
+ (1, 0),
314
+ (0, 1),
315
+ (2, 0),
316
+ (1, 1),
317
+ (0, 2),
318
+ (3, 0),
319
+ (2, 1),
320
+ (1, 2),
321
+ (0, 3),
322
+ ]:
323
+ u = uv[0]
324
+ v = uv[1]
325
+ blob._moments[f"m{p}{q}"] += u**p * v**q
326
+
327
+ # 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"]
340
+ )
341
+
342
+ # 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)
350
+ )
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)
358
+ )
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)
369
+ )
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)
380
+ )
381
+
382
+ # 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
+ )
392
+
393
+ # 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
+ )
406
+
310
407
  allblobs.append(blob)
408
+ self.data.append(blob)
311
409
 
312
410
  ## second pass: equivalent ellipse
313
411
 
@@ -330,6 +428,9 @@ class Blobs(UserList): # lgtm[py/missing-equals]
330
428
  blob._moments = M
331
429
 
332
430
  ## centroid
431
+ if M.m00 == 0:
432
+ continue
433
+
333
434
  blob.uc = M.m10 / M.m00
334
435
  blob.vc = M.m01 / M.m00
335
436
 
@@ -1089,18 +1190,42 @@ class Blobs(UserList): # lgtm[py/missing-equals]
1089
1190
 
1090
1191
  A parent of -1 is the image background.
1091
1192
 
1092
- :seealso: :meth:`children` :meth:`level` :meth:`dotfile`
1193
+ :seealso: :meth:`id` :meth:`children` :meth:`level` :meth:`dotfile`
1093
1194
  """
1094
1195
  return [b.parent for b in self.data]
1095
1196
 
1197
+ @property
1198
+ @scalar_result
1199
+ def id(self):
1200
+ """
1201
+ Blob id number
1202
+
1203
+ :return: index of this blob
1204
+ :rtype: int
1205
+
1206
+ Example:
1207
+
1208
+ .. runblock:: pycon
1209
+
1210
+ >>> from machinevisiontoolbox import Image
1211
+ >>> im = Image.Read('multiblobs.png')
1212
+ >>> blobs = im.blobs()
1213
+ >>> print(blobs)
1214
+ >>> blobs[5].id
1215
+ >>> blobs[6].id
1216
+
1217
+
1218
+ :seealso: :meth:`parent` :meth:`children` :meth:`level` :meth:`dotfile`
1219
+ """
1220
+ return [b.id for b in self.data]
1221
+
1096
1222
  @property
1097
1223
  @array_result
1098
1224
  def children(self):
1099
1225
  """
1100
1226
  Child blobs
1101
1227
 
1102
- :return: list of indices of this blob's children
1103
- :rtype: list of int
1228
+ :return: list of indices of this blob's children :rtype: list of int
1104
1229
 
1105
1230
  Example:
1106
1231
 
@@ -1607,10 +1732,12 @@ class Blobs(UserList): # lgtm[py/missing-equals]
1607
1732
  :seealso: :meth:`plot_box` :meth:`plot_centroid` :meth:`plot_perimeter` :func:`~machinevisiontoolbox.base.graphics.plot_labelbox`
1608
1733
  """
1609
1734
 
1610
- for blob in enumerate(self):
1735
+ for blob in self:
1611
1736
  if label is None:
1612
- label = f"{blob.id}"
1613
- plot_labelbox(text=label, lrbt=blob.bbox, **kwargs)
1737
+ text = f"{blob.id}"
1738
+ else:
1739
+ text = label
1740
+ plot_labelbox(text=text, lrbt=blob.bbox, **kwargs)
1614
1741
 
1615
1742
  def plot_centroid(self, label=False, **kwargs):
1616
1743
  """
@@ -2070,6 +2197,9 @@ if __name__ == "__main__":
2070
2197
 
2071
2198
  im = Image.Read("sharks.png")
2072
2199
  blobs = im.blobs()
2200
+ im.disp()
2201
+ blobs.plot_labelbox(color="yellow")
2202
+ plt.show(block=True)
2073
2203
  # frames = SE2.Empty()
2074
2204
  # for blob in blobs:
2075
2205
  # frames.append(SE2(*blob.centroid, blob.orientation))