PyOPIA 2.5.4__tar.gz → 2.5.6__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 (26) hide show
  1. {pyopia-2.5.4 → pyopia-2.5.6}/PKG-INFO +1 -1
  2. pyopia-2.5.6/pyopia/__init__.py +1 -0
  3. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/io.py +2 -2
  4. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/simulator/silcam.py +85 -19
  5. pyopia-2.5.4/pyopia/__init__.py +0 -1
  6. {pyopia-2.5.4 → pyopia-2.5.6}/LICENSE +0 -0
  7. {pyopia-2.5.4 → pyopia-2.5.6}/README.md +0 -0
  8. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/background.py +0 -0
  9. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/classify.py +0 -0
  10. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/cli.py +0 -0
  11. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/exampledata.py +0 -0
  12. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/instrument/__init__.py +0 -0
  13. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/instrument/common.py +0 -0
  14. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/instrument/holo.py +0 -0
  15. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/instrument/silcam.py +0 -0
  16. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/instrument/uvp.py +0 -0
  17. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/pipeline.py +0 -0
  18. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/plotting.py +0 -0
  19. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/process.py +0 -0
  20. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/simulator/__init__.py +0 -0
  21. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/statistics.py +0 -0
  22. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/tests/__init__.py +0 -0
  23. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/tests/test_classify.py +0 -0
  24. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/tests/test_notebooks.py +0 -0
  25. {pyopia-2.5.4 → pyopia-2.5.6}/pyopia/tests/test_pipeline.py +0 -0
  26. {pyopia-2.5.4 → pyopia-2.5.6}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyOPIA
3
- Version: 2.5.4
3
+ Version: 2.5.6
4
4
  Summary: A Python Ocean Particle Image Analysis toolbox.
5
5
  Home-page: https://github.com/sintef/pyopia
6
6
  Keywords: Ocean,Particles,Imaging,Measurement,Size distribution
@@ -0,0 +1 @@
1
+ __version__ = '2.5.6'
@@ -390,7 +390,7 @@ def load_toml(toml_file):
390
390
  return settings
391
391
 
392
392
 
393
- def StatsH5():
393
+ def StatsH5(**kwargs):
394
394
  '''.. deprecated:: 2.4.8
395
395
  :class:`pyopia.io.StatsH5` will be removed in version 3.0.0, it is replaced by
396
396
  :class:`pyopia.io.StatsToDisc`.
@@ -430,4 +430,4 @@ def StatsH5():
430
430
  append = true
431
431
  '''
432
432
  logger.warning('StatsH5 will be removed in version 3.0.0, it is replaced by pyopia.io.StatsToDisc')
433
- return StatsToDisc()
433
+ return StatsToDisc(**kwargs)
@@ -2,10 +2,11 @@
2
2
  Module containing tools for assessing statistical reliability of silcam size distributions
3
3
  '''
4
4
  import numpy as np
5
- from skimage.draw import disk
5
+ import skimage.draw
6
6
  import matplotlib.pyplot as plt
7
7
  import skimage.util
8
8
  import pandas as pd
9
+ import os
9
10
 
10
11
  import pyopia.statistics
11
12
  import pyopia.plotting
@@ -161,8 +162,21 @@ class SilcamSimulator():
161
162
  axis=0),
162
163
  self.dias)
163
164
 
164
- def synthesize(self):
165
- '''Synthesize an image and measure droplets
165
+ def synthesize(self, add_noise=False, noise_var=0.001, database_path='', database_image_ext='tiff'):
166
+ '''Synthesize an image and document the distributions of particles used as input
167
+
168
+ Parameters
169
+ ----------
170
+ add_noise : bool, optional
171
+ Uses skimage.util.random_noise() to add gaussian noise with variance defined by `noise_var`, by default False
172
+ noise_var : float, optional
173
+ Passed to the var argument of skimage.util.random_noise(), by default 0.001
174
+ database_path : str, optional
175
+ Path to a folder of particle ROI images to be randomly selected from to build the synthetic image.
176
+ If this is an empty string (default), then black discs will be used instead of real images., by default ''
177
+ database_image_ext : str, optional
178
+ Image file extension to look for within the folder specified by `database_path`
179
+ (must be a type that is loadable by skimage.io.imread() e.g. png of tiff), by default 'tiff'
166
180
 
167
181
  Parameters
168
182
  ----------
@@ -171,36 +185,52 @@ class SilcamSimulator():
171
185
  data['synthetic_image_data']['input_volume_distribution'] : array
172
186
  Volume distribution used to create the synthetic image
173
187
  '''
174
- nc = int(sum(self.data['number_distribution'])) # number concentration
188
+
189
+ number_concentration = int(sum(self.data['number_distribution'])) # number concentration
175
190
 
176
191
  # preallocate the image and logged volume distribution variables
177
192
  img = np.zeros((self.imx, self.imy, 3), dtype=np.uint8()) + 230 # scale the initial brightness down a bit
178
- log_ecd = np.zeros(nc)
193
+ log_ecd = np.zeros(number_concentration)
179
194
  # randomly select a droplet radii from the input distribution
180
195
  # radius is in pixels
181
- rad = np.random.choice(self.dias / 2,
182
- size=nc,
183
- p=self.data['number_distribution'] / sum(self.data['number_distribution'])) / self.PIX_SIZE
184
- log_ecd = rad * 2 * self.PIX_SIZE # log these sizes as a diameter in um
185
- for rad_ in rad:
186
- # randomly decide where to put particles within the image
187
- col = np.random.randint(1, high=self.imx - rad_)
188
- row = np.random.randint(1, high=self.imy - rad_)
196
+ radii = np.random.choice(self.dias / 2,
197
+ size=number_concentration,
198
+ p=self.data['number_distribution'] / sum(self.data['number_distribution'])) / self.PIX_SIZE
199
+ log_ecd = radii * 2 * self.PIX_SIZE # log these sizes as a diameter in um
189
200
 
190
- rr, cc = disk((col, row), rad_) # make a cirle of the radius selected from the distribution
191
- img[rr, cc, :] = 0
201
+ if database_path != '':
202
+ from pyopia.pipeline import FilesToProcess
203
+ file_list = FilesToProcess(os.path.join(database_path, '*.' + database_image_ext)).files
204
+
205
+ self.example_images = []
206
+ for radius in radii:
207
+ # randomly decide where to put particles within the image
208
+ row = np.random.randint(low=radius * 2, high=self.imx - (radius * 2))
209
+ col = np.random.randint(low=radius * 2, high=self.imy - (radius * 2))
210
+
211
+ if database_path != '':
212
+ example_image = extract_and_scale_example_image(radius, file_list)
213
+ img[row:row + example_image.shape[0],
214
+ col:col + example_image.shape[1],
215
+ :] = example_image
216
+ if np.min(np.shape(example_image[:, :, 0])) > 5:
217
+ self.example_images.append(example_image)
218
+ else:
219
+ rr, cc = skimage.draw.disk((row, col), radius) # make a cirle of the radius selected from the distribution
220
+ img[rr, cc, :] = 0
192
221
 
193
222
  necd, edges = np.histogram(log_ecd, self.bin_limits) # count the input diameters into a number distribution
194
223
  # convert to a volume distribution
195
- log_vd = pyopia.statistics.vd_from_nd(necd, self.dias, sample_volume=self.sample_volume)
224
+ temporal_volume_distribution = pyopia.statistics.vd_from_nd(necd, self.dias, sample_volume=self.sample_volume)
196
225
 
197
- # add some noise to the synthesized image
198
- img = np.uint8(255 * skimage.util.random_noise(np.float64(img) / 255))
226
+ if add_noise:
227
+ # add some noise to the synthesized image
228
+ img = np.uint8(255 * skimage.util.random_noise(np.float64(img) / 255, mode='gaussian', var=noise_var))
199
229
 
200
230
  img = np.uint8(img) # convert to uint8
201
231
  self.data['synthetic_image_data'] = dict()
202
232
  self.data['synthetic_image_data']['image'] = img
203
- self.data['synthetic_image_data']['input_volume_distribution'] = log_vd
233
+ self.data['synthetic_image_data']['input_volume_distribution'] = temporal_volume_distribution
204
234
 
205
235
  def process_synthetic_image(self):
206
236
  '''Put the synthetic image `data['synthetic_image_data']['image']` through a basic pyopia processing pipeline
@@ -278,3 +308,39 @@ class SilcamSimulator():
278
308
  plt.legend()
279
309
 
280
310
  plt.tight_layout()
311
+
312
+
313
+ def extract_and_scale_example_image(output_length, file_list):
314
+ '''Randomly select a file from the input file_list list,
315
+ load this and then scale it (maintaining aspect ratio) to match the longest x-y dimention
316
+ to rad_ number of pixel
317
+
318
+ Parameters
319
+ ----------
320
+ output_length : float
321
+ wanted longest dimention
322
+ file_list : list
323
+ list of filenames to chose from (to be read with skimage.io.imread)
324
+
325
+ Returns
326
+ -------
327
+ example_image : array
328
+ resized image
329
+ '''
330
+ filename = np.random.choice(file_list, size=1)[0]
331
+ raw_image = skimage.io.imread(filename).astype(float)
332
+
333
+ longest_axis = np.max(raw_image.shape[0:2])
334
+
335
+ scale_factor = output_length * 2 / longest_axis
336
+
337
+ size_row = scale_factor * np.float64(raw_image.shape[0])
338
+ size_col = scale_factor * np.float64(raw_image.shape[1])
339
+
340
+ example_image = skimage.transform.resize(raw_image,
341
+ (size_row, size_col),
342
+ anti_aliasing=True)
343
+
344
+ if np.min(np.shape(example_image)) > 0:
345
+ example_image += 255 - np.max(example_image)
346
+ return example_image
@@ -1 +0,0 @@
1
- __version__ = '2.5.4'
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
File without changes
File without changes
File without changes
File without changes
File without changes