PyOPIA 1.0.0__tar.gz → 1.1.0__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.
@@ -1,12 +1,16 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyOPIA
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: A Python Ocean Particle Image Analysis toolbox.
5
+ Home-page: https://github.com/sintef/pyopia
6
+ Keywords: Ocean,Particles,Imaging,Measurement,Size distribution
5
7
  Author: Emlyn Davies
6
8
  Author-email: emlyn.davies@sintef.no
7
9
  Requires-Python: >=3.10,<3.11
8
10
  Classifier: Programming Language :: Python :: 3
9
11
  Classifier: Programming Language :: Python :: 3.10
12
+ Provides-Extra: classification
13
+ Provides-Extra: classification-arm64
10
14
  Requires-Dist: cmocean (>=3.0.3,<4.0.0)
11
15
  Requires-Dist: flake8 (>=6.1.0,<7.0.0)
12
16
  Requires-Dist: gdown (>=4.7.1,<5.0.0)
@@ -30,13 +34,16 @@ Requires-Dist: sphinx-copybutton (>=0.5.2,<0.6.0)
30
34
  Requires-Dist: sphinx-rtd-theme (>=0.5.0)
31
35
  Requires-Dist: sphinx-togglebutton (>=0.3.2,<0.4.0)
32
36
  Requires-Dist: sphinxcontrib-napoleon (>=0.7)
33
- Requires-Dist: tensorflow-cpu (==2.11.0)
34
- Requires-Dist: tensorflow-io-gcs-filesystem (==0.31.0)
37
+ Requires-Dist: tensorflow-cpu (==2.11.0) ; extra == "classification"
38
+ Requires-Dist: tensorflow-io-gcs-filesystem (>=0.31.0) ; extra == "classification-arm64" or extra == "classification"
39
+ Requires-Dist: tensorflow-macos (==2.11.0) ; (sys_platform == "darwin" and platform_machine == "arm64") and (extra == "classification-arm64")
35
40
  Requires-Dist: toml (>=0.10.2,<0.11.0)
36
41
  Requires-Dist: tqdm (>=4.66.1,<5.0.0)
37
42
  Requires-Dist: typer[all] (>=0.9.0,<0.10.0)
38
43
  Requires-Dist: urllib3 (<2.0)
39
44
  Requires-Dist: xarray (>=2023.8.0,<2024.0.0)
45
+ Project-URL: Documentation, https://pyopia.readthedocs.io
46
+ Project-URL: Repository, https://github.com/sintef/pyopia
40
47
  Description-Content-Type: text/markdown
41
48
 
42
49
  PyOpia
@@ -53,18 +60,14 @@ A Python Ocean Particle Image Analysis toolbox
53
60
 
54
61
  - Under development. See/regester issues, [here](https://github.com/SINTEF/pyopia/issues)
55
62
 
56
- - Refining a structure for a standard [processing piplines](https://pyopia.readthedocs.io/en/latest/pyopia.pipeline.html)
57
-
58
- - Building a system for metadata and [output files](https://pyopia.readthedocs.io/en/latest/pyopia.io.html)
59
-
60
63
  ----
61
64
 
62
65
  # Installing for users
63
66
 
64
- Users are expected to be familiar with Python, and have [Python](https://github.com/conda-forge/miniforge/#download), [pip](https://pypi.org/project/pip/) and [git](https://github.com/git-guides/install-git) installed. You can then install Pyopia like this:
67
+ Users are expected to be familiar with Python, and have [Python](https://github.com/conda-forge/miniforge/#download), [pip](https://pypi.org/project/pip/). You can then install Pyopia like this:
65
68
 
66
69
  ```
67
- pip install git+https://github.com/SINTEF/pyopia.git@main
70
+ pip install pyopia
68
71
  ```
69
72
 
70
73
  We would usually recommend installing within a virtual python environment, which you can read more about [here](https://jni.github.io/using-python-for-science/intro-to-environments.html).
@@ -98,7 +101,7 @@ We welcome additions and improvements to the code! We request that you follow a
98
101
  4. All pull requests must be reviewed by a person. The benefits from code review are plenty, but we like to emphasise that code reviews help spreading the awarenes of code changes. Please note that code reviews should be a pleasant experience, so be plesant, polite and remember that there is a human being with good intentions on the other side of the screen.
99
102
  5. All contributions are linted with flake8. We recommend that you run flake8 on your code while developing to fix any issues as you go. We recommend using autopep8 to autoformat your Python code (but please check the code behaviour is not affected by autoformatting before pushing). This makes flake8 happy, and makes it easier for us all to maintain a consistent and readable code base.
100
103
 
101
- ## Installing for developers
104
+ ## Installing from source for developers
102
105
 
103
106
  Install [Python](https://github.com/conda-forge/miniforge/#download).
104
107
 
@@ -12,18 +12,14 @@ A Python Ocean Particle Image Analysis toolbox
12
12
 
13
13
  - Under development. See/regester issues, [here](https://github.com/SINTEF/pyopia/issues)
14
14
 
15
- - Refining a structure for a standard [processing piplines](https://pyopia.readthedocs.io/en/latest/pyopia.pipeline.html)
16
-
17
- - Building a system for metadata and [output files](https://pyopia.readthedocs.io/en/latest/pyopia.io.html)
18
-
19
15
  ----
20
16
 
21
17
  # Installing for users
22
18
 
23
- Users are expected to be familiar with Python, and have [Python](https://github.com/conda-forge/miniforge/#download), [pip](https://pypi.org/project/pip/) and [git](https://github.com/git-guides/install-git) installed. You can then install Pyopia like this:
19
+ Users are expected to be familiar with Python, and have [Python](https://github.com/conda-forge/miniforge/#download), [pip](https://pypi.org/project/pip/). You can then install Pyopia like this:
24
20
 
25
21
  ```
26
- pip install git+https://github.com/SINTEF/pyopia.git@main
22
+ pip install pyopia
27
23
  ```
28
24
 
29
25
  We would usually recommend installing within a virtual python environment, which you can read more about [here](https://jni.github.io/using-python-for-science/intro-to-environments.html).
@@ -57,7 +53,7 @@ We welcome additions and improvements to the code! We request that you follow a
57
53
  4. All pull requests must be reviewed by a person. The benefits from code review are plenty, but we like to emphasise that code reviews help spreading the awarenes of code changes. Please note that code reviews should be a pleasant experience, so be plesant, polite and remember that there is a human being with good intentions on the other side of the screen.
58
54
  5. All contributions are linted with flake8. We recommend that you run flake8 on your code while developing to fix any issues as you go. We recommend using autopep8 to autoformat your Python code (but please check the code behaviour is not affected by autoformatting before pushing). This makes flake8 happy, and makes it easier for us all to maintain a consistent and readable code base.
59
55
 
60
- ## Installing for developers
56
+ ## Installing from source for developers
61
57
 
62
58
  Install [Python](https://github.com/conda-forge/miniforge/#download).
63
59
 
@@ -0,0 +1,38 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ authors:
4
+ - family-names: Davies
5
+ given-names: Emlyn
6
+ - family-names: Nimmo-Smith
7
+ given-names: Alex
8
+ - family-names: Nepstad
9
+ given-names: Raymond
10
+ - family-names: Nordam
11
+ given-names: Tor
12
+ - family-names: Brönner
13
+ given-names: Ute
14
+ - family-names: Steinvika
15
+ given-names: Andreas
16
+ - family-names: Sari
17
+ given-names: Giering
18
+ - family-names: Masoudi
19
+ given-names: Mojtaba
20
+ - family-names: Liu
21
+ given-names: Zonghua
22
+ - family-names: Hélaouët
23
+ given-names: Pierre
24
+ - family-names: Cursons
25
+ given-names: Kairan
26
+ - family-names: Rau
27
+ given-names: Matthew
28
+ - family-names: Song
29
+ given-names: Yixuan
30
+ - family-names: Mostaani
31
+ given-names: Arsalan
32
+ - family-names: Barstein
33
+ given-names: Karoline
34
+ - family-names: Buscombe
35
+ given-names: Daniel
36
+ title: "PyOPIA: A Python Ocean Particle Image Analysis toolbox"
37
+ url: "https://pyopia.readthedocs.io"
38
+ repository-code: "https://github.com/sintef/pyopia"
@@ -0,0 +1 @@
1
+ __version__ = '1.1.0'
@@ -40,6 +40,16 @@ class Classify():
40
40
  pipeline_class = 'pyopia.classify.Classify'
41
41
  model_path = 'keras_model.h5' # path to trained nn model
42
42
 
43
+ If `[steps.classifier]`is not defined, the classification will be skipped and no probabilities reported.
44
+
45
+ If you want to use an example trained model for SilCam data
46
+ (no guarantee of accuracy for other applications), you can get it using `exampledata`
47
+ within the notebooks folder (https://github.com/SINTEF/pyopia/blob/main/notebooks/exampledata.py):
48
+
49
+ .. code-block:: python
50
+
51
+ model_path = exampledata.get_example_model()
52
+
43
53
  '''
44
54
  def __init__(self, model_path=None):
45
55
  self.model_path = model_path
@@ -62,12 +72,12 @@ class Classify():
62
72
  try:
63
73
  from tensorflow import keras
64
74
  except ImportError:
65
- info_str = 'WARNING: Could not import Keras, Classify will not work'
66
- info_str += ' until you install tensorflow (pip install tensorflow-cpu)'
67
- print(info_str)
68
- self.model = lambda x: None
69
- self.class_labels = []
70
- return
75
+ info_str = 'ERROR: Could not import Keras. Classify will not work'
76
+ info_str += ' until you install tensorflow.\n'
77
+ info_str += 'Use: pip install pyopia[classification]\n'
78
+ info_str += ' or: pip install pyopia[classification-arm64]'
79
+ info_str += ' for tensorflow-macos (silicon chips)'
80
+ raise ImportError(info_str)
71
81
 
72
82
  os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
73
83
  keras.backend.clear_session()
@@ -65,6 +65,7 @@ class Pipeline():
65
65
  self.initial_steps = initial_steps
66
66
  print('Initialising pipeline')
67
67
  self.data = Data()
68
+ self.data['cl'] = None
68
69
  self.data['settings'] = settings
69
70
 
70
71
  self.pass_general_settings()
@@ -192,6 +192,29 @@ def write_segmented_images(imbw, imc, settings, timestamp):
192
192
  imsave(fname, imc)
193
193
 
194
194
 
195
+ def put_roi_in_h5(export_outputpath, HDF5File, roi, filename, i):
196
+ '''Adds rois to an open hdf file if export_outputpath is not None.
197
+ For use within {func}`pyopia.process.export_particles`
198
+
199
+ Parameters
200
+ ----------
201
+ export_outputpath : str
202
+ HDF5File : h5 file object
203
+ roi : uint8
204
+ i : int
205
+ particle number
206
+
207
+ Returns
208
+ -------
209
+ str
210
+ filename
211
+ '''
212
+ filename = filename + '-PN' + str(i)
213
+ if export_outputpath is not None:
214
+ HDF5File.create_dataset('PN' + str(i), data=roi)
215
+ return filename
216
+
217
+
195
218
  def extract_particles(imc, timestamp, Classification, region_properties,
196
219
  export_outputpath=None, min_length=0, propnames=['major_axis_length', 'minor_axis_length',
197
220
  'equivalent_diameter']):
@@ -213,11 +236,12 @@ def extract_particles(imc, timestamp, Classification, region_properties,
213
236
  '''
214
237
  filenames = ['not_exported'] * len(region_properties)
215
238
 
216
- # pre-allocation
217
- predictions = np.zeros((len(region_properties),
218
- len(Classification.class_labels)),
219
- dtype='float64')
220
- predictions *= np.nan
239
+ if Classification is not None:
240
+ # pre-allocation
241
+ predictions = np.zeros((len(region_properties),
242
+ len(Classification.class_labels)),
243
+ dtype='float64')
244
+ predictions *= np.nan
221
245
 
222
246
  # obtain the original image filename from the timestamp
223
247
  filename = timestamp.strftime('D%Y%m%dT%H%M%S.%f')
@@ -239,6 +263,8 @@ def extract_particles(imc, timestamp, Classification, region_properties,
239
263
  meta.attrs['Raw image name'] = filename
240
264
  # @todo include more useful information in this meta data, e.g. possibly raw image location and background
241
265
  # stack file list.
266
+ else:
267
+ HDF5File = None
242
268
 
243
269
  # pre-allocate some things
244
270
  data = np.zeros((len(region_properties), len(propnames)), dtype=np.float64)
@@ -258,15 +284,13 @@ def extract_particles(imc, timestamp, Classification, region_properties,
258
284
  # extract the region of interest from the corrected colour image
259
285
  roi = extract_roi(imc, bboxes[i, :].astype(int))
260
286
 
261
- # add the roi to the HDF5 file
262
- filenames[int(i)] = filename + '-PN' + str(i)
263
- if export_outputpath is not None:
264
- HDF5File.create_dataset('PN' + str(i), data=roi)
265
- # @todo also include particle stats here too.
287
+ if Classification is not None:
288
+ # run a prediction on what type of particle this might be
289
+ prediction = Classification.proc_predict(roi.astype(np.uint8))
290
+ predictions[int(i), :] = prediction[0]
266
291
 
267
- # run a prediction on what type of particle this might be
268
- prediction = Classification.proc_predict(roi.astype(np.uint8))
269
- predictions[int(i), :] = prediction[0]
292
+ # add the roi to the HDF5 file
293
+ filenames[int(i)] = put_roi_in_h5(export_outputpath, HDF5File, roi, filename, i)
270
294
 
271
295
  if export_outputpath is not None:
272
296
  # close the HDF5 file
@@ -283,9 +307,10 @@ def extract_particles(imc, timestamp, Classification, region_properties,
283
307
 
284
308
  print('EXTRACTING {0} IMAGES from {1}'.format(nb_extractable_part, len(stats['major_axis_length'])))
285
309
 
286
- # add classification predictions to the particle statistics data
287
- for n, c in enumerate(Classification.class_labels):
288
- stats['probability_' + c] = predictions[:, n]
310
+ if Classification is not None:
311
+ # add classification predictions to the particle statistics data
312
+ for n, c in enumerate(Classification.class_labels):
313
+ stats['probability_' + c] = predictions[:, n]
289
314
 
290
315
  # add the filenames of the HDF5 file and particle number tag to the
291
316
  # particle statistics data
@@ -356,7 +381,8 @@ def segment(img, threshold=0.98, minimum_area=12, fill_holes=True):
356
381
  return imbw
357
382
 
358
383
 
359
- def statextract(imbw, timestamp, imc, Classification,
384
+ def statextract(imbw, timestamp, imc,
385
+ Classification=None,
360
386
  max_coverage=30,
361
387
  max_particles=5000,
362
388
  export_outputpath=None,
@@ -510,7 +536,8 @@ class CalculateStats():
510
536
 
511
537
  def __call__(self, data):
512
538
  print('statextract')
513
- stats, saturation = statextract(data['imbw'], data['timestamp'], data['imc'], data['cl'],
539
+ stats, saturation = statextract(data['imbw'], data['timestamp'], data['imc'],
540
+ Classification=data['cl'],
514
541
  max_coverage=self.max_coverage,
515
542
  max_particles=self.max_particles,
516
543
  export_outputpath=self.export_outputpath,
@@ -2,8 +2,14 @@
2
2
  name = "PyOPIA"
3
3
  version = "0"
4
4
  description = "A Python Ocean Particle Image Analysis toolbox."
5
- authors = ["Emlyn Davies <emlyn.davies@sintef.no>"]
5
+ authors = [
6
+ "Emlyn Davies <emlyn.davies@sintef.no>",
7
+ "Alex Nimmo Smith@plymouth.ac.uk <alex.nimmo.smith@plymouth.ac.uk>"
8
+ ]
6
9
  readme = "README.md"
10
+ repository = "https://github.com/sintef/pyopia"
11
+ documentation = "https://pyopia.readthedocs.io"
12
+ keywords = ["Ocean", "Particles", "Imaging", "Measurement", "Size distribution"]
7
13
  packages = [{include = "pyopia"}]
8
14
 
9
15
  [tool.poetry.dependencies]
@@ -35,9 +41,16 @@ xarray = "^2023.8.0"
35
41
  typer = {extras = ["all"], version = "^0.9.0"}
36
42
  pandas = {version = "^2.1.1", extras = ["computation"]}
37
43
  h5py = "^3.9.0"
38
- tensorflow-io-gcs-filesystem = "0.31.0"
39
- tensorflow-cpu = "2.11.0"
40
44
  poetry-version-plugin = "^0.2.0"
45
+ tensorflow-macos = {version = "2.11.0", optional = true, markers = "sys_platform == 'darwin' and platform_machine == 'arm64'"}
46
+ tensorflow-cpu = {version = "2.11.0", optional = true}
47
+ tensorflow-io-gcs-filesystem = [
48
+ {version = ">=0.31.0", optional=true}
49
+ ]
50
+
51
+ [tool.poetry.extras]
52
+ classification-arm64 = ["tensorflow-io-gcs-filesystem", "tensorflow-macos"]
53
+ classification = ["tensorflow-io-gcs-filesystem", "tensorflow-cpu"]
41
54
 
42
55
  [tool.poetry-version-plugin]
43
56
  source = "init"
@@ -1 +0,0 @@
1
- __version__ = '1.0.0'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes