Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
onto ``min_amp`` and the largest onto ``max_amp``.
pulse : :py:class:`~pulse2percept.stimuli.Stimulus`, optional
A valid pulse or pulse train to be used for the encoding.
If None given, a :py:class:`~pulse2percept.stimuli.BiphasicPulse`
(0.46 ms phase duration, 500 ms total duration) will be used.
Returns
-------
stim : :py:class:`~pulse2percept.stimuli.Stimulus`
Encoded stimulus
"""
if pulse is None:
pulse = BiphasicPulse(1, 0.46, stim_dur=500)
else:
if not isinstance(pulse, Stimulus):
raise TypeError("'pulse' must be a Stimulus object.")
if pulse.time is None:
raise ValueError("'pulse' must have a time component.")
# Make sure the provided pulse has max amp 1:
enc_data = pulse.data
if not np.isclose(np.abs(enc_data).max(), 0):
enc_data /= np.abs(enc_data).max()
# Normalize the range of pixel values:
px_data = self.data - self.data.min()
if not np.isclose(np.abs(px_data).max(), 0):
px_data /= np.abs(px_data).max()
# Amplitude modulation:
stim = []
for px, e in zip(px_data.ravel(), self.electrodes):
amp = px * (amp_range[1] - amp_range[0]) + amp_range[0]
stim.append(Stimulus(amp * enc_data, time=pulse.time,
compress=False)
self.freq = freq
self.pulse_type = pulse.__class__.__name__
self.charge_balanced = np.isclose(np.trapz(data, time)[0], 0,
atol=MIN_AMP)
def _pprint_params(self):
"""Return a dict of class arguments to pretty-print"""
params = super(PulseTrain, self)._pprint_params()
params.update({'freq': self.freq,
'pulse_type': self.pulse_type,
'charge_balanced': self.charge_balanced})
return params
class BiphasicPulseTrain(Stimulus):
"""Symmetric biphasic pulse train
A train of symmetric biphasic pulses.
.. versionadded:: 0.6
Parameters
----------
freq : float
Pulse train frequency (Hz).
amp : float
Current amplitude (uA). Negative currents: cathodic, positive: anodic.
The sign will be converted automatically depending on
``cathodic_first``.
phase_dur : float
Duration (ms) of the cathodic/anodic phase.
from skimage import img_as_float32
from skimage.io import imread, imsave
from skimage.color import rgba2rgb, rgb2gray
from skimage.measure import moments as img_moments
from skimage.transform import (resize as img_resize, rotate as img_rotate,
warp as img_warp, SimilarityTransform)
from skimage.filters import (threshold_mean, threshold_minimum, threshold_otsu,
threshold_local, threshold_isodata, scharr, sobel,
median)
from skimage.feature import canny
from .base import Stimulus
from .pulses import BiphasicPulse
class ImageStimulus(Stimulus):
"""ImageStimulus
A stimulus made from an image, where each pixel gets assigned to an
electrode, and grayscale values in the range [0, 255] get converted to
activation values in the range [0, 1].
.. seealso ::
* `Basic Concepts > Electrical Stimuli `
* :py:class:`~pulse2percept.stimuli.VideoStimulus`
.. versionadded:: 0.7
Parameters
----------
source : str
dt=dt, metadata=metadata)
super().__init__(pt.data, time=pt.time, compress=False)
self.freq = freq
self.cathodic_first = cathodic_first
self.charge_balanced = pt.charge_balanced
def _pprint_params(self):
"""Return a dict of class arguments to pretty-print"""
params = super(BiphasicPulseTrain, self)._pprint_params()
params.update({'cathodic_first': self.cathodic_first,
'charge_balanced': self.charge_balanced,
'freq': self.freq})
return params
class AsymmetricBiphasicPulseTrain(Stimulus):
"""Asymmetric biphasic pulse
A simple stimulus consisting of a single biphasic pulse: a cathodic and an
anodic phase, optionally separated by an interphase gap.
The two pulse phases can have different amplitudes and duration
("asymmetric").
The order of the two phases is given by the ``cathodic_first`` flag.
.. versionadded:: 0.6
Parameters
----------
freq : float
Pulse train frequency (Hz).
amp1, amp2 : float
Current amplitude (uA) of the first and second pulse phases.
time, idx = np.unique(time, return_index=True)
data = data[:, idx]
super().__init__(data, electrodes=electrode, time=time, compress=False)
self.cathodic_first = cathodic_first
self.charge_balanced = np.isclose(np.trapz(data, time)[0], 0,
atol=MIN_AMP)
def _pprint_params(self):
"""Return a dict of class arguments to pretty-print"""
params = super(BiphasicPulse, self)._pprint_params()
params.update({'cathodic_first': self.cathodic_first,
'charge_balanced': self.charge_balanced})
return params
class AsymmetricBiphasicPulse(Stimulus):
"""Asymmetric biphasic pulse
A simple stimulus consisting of a single biphasic pulse: a cathodic and an
anodic phase, optionally separated by an interphase gap.
The two pulse phases can have different amplitudes and duration
("asymmetric").
.. versionadded:: 0.6
Parameters
----------
amp1, amp2 : float
Current amplitude (uA) of the first and second pulse phases.
Negative currents: cathodic, positive: anodic.
The signs will be converted automatically depending on
``cathodic_first``.
raise ValueError("'pulse' must have a time component.")
# Make sure the provided pulse has max amp 1:
enc_data = pulse.data
if not np.isclose(np.abs(enc_data).max(), 0):
enc_data /= np.abs(enc_data).max()
# Normalize the range of pixel values:
px_data = self.data - self.data.min()
if not np.isclose(np.abs(px_data).max(), 0):
px_data /= np.abs(px_data).max()
# Amplitude modulation:
stim = []
for px, e in zip(px_data.ravel(), self.electrodes):
amp = px * (amp_range[1] - amp_range[0]) + amp_range[0]
stim.append(Stimulus(amp * enc_data, time=pulse.time,
electrodes=e))
return Stimulus(stim)
"""`PulseTrain`, `BiphasicPulseTrain`, `AsymmetricBiphasicPulseTrain`"""
import numpy as np
import copy
import logging
from . import MIN_AMP
from .base import Stimulus
from .pulses import BiphasicPulse, AsymmetricBiphasicPulse
class PulseTrain(Stimulus):
"""Generic pulse train
Can be used to concatenate single pulses into a pulse train.
.. seealso ::
* :py:class:`~pulse2percept.stimuli.BiphasicPulseTrain`
* :py:class:`~pulse2percept.stimuli.AsymmetricBiphasicPulseTrain`
.. versionadded:: 0.6
Parameters
----------
freq : float
Pulse train frequency (Hz).
pulse : :py:class:`~pulse2percept.stimuli.Stimulus`
"""`MonophasicPulse`, `BiphasicPulse`, `AsymmetricBiphasicPulse`"""
import numpy as np
from . import MIN_AMP
from .base import Stimulus
class MonophasicPulse(Stimulus):
"""Monophasic pulse
A simple stimulus consisting of a single monophasic pulse (either
cathodic/negative or anodic/positive).
.. versionadded:: 0.6
Parameters
----------
amp : float
Current amplitude (uA). Negative currents: cathodic, positive: anodic.
phase_dur : float
Duration (ms) of the cathodic or anodic phase.
delay_dur : float
Delay duration (ms). Zeros will be inserted at the beginning of the
stimulus to deliver the pulse after ``delay_dur`` ms.
time = None
electrodes = None
elif isinstance(source, (list, tuple)):
# List or touple with N elements: 1 electrode, N time points
data = np.array(source, dtype=np.float32).reshape((1, -1))
time = np.arange(data.shape[-1], dtype=np.float32)
electrodes = None
elif isinstance(source, np.ndarray):
if source.ndim > 1:
raise ValueError("Cannot create Stimulus object from a %d-D "
"NumPy array. Must be 1-D." % source.ndim)
# 1D NumPy array with N elements: 1 electrode, N time points
data = source.astype(np.float32).reshape((1, -1))
time = np.arange(data.shape[-1], dtype=np.float32)
electrodes = None
elif isinstance(source, Stimulus):
# e.g. from a dictionary of Stimulus objects
data = source.data
time = source.time
electrodes = source.electrodes
else:
raise TypeError("Cannot create Stimulus object from %s. Choose "
"from: scalar, tuple, list, NumPy array, or "
"Stimulus." % type(source))
return time, data, electrodes
"""`VideoStimulus`, `BostonTrain`"""
from os.path import dirname, join
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from skimage.color import rgb2gray
from skimage.transform import resize as vid_resize
from skimage import img_as_float32
from imageio import get_reader as video_reader
from .base import Stimulus
class VideoStimulus(Stimulus):
"""VideoStimulus
A stimulus made from a movie file, where each pixel gets assigned to an
electrode, and grayscale values in the range [0, 255] get assigned to
activation values in the range [0, 1].
The frame rate of the movie is used to infer the time points at which to
stimulate.
.. seealso ::
* `Basic Concepts > Electrical Stimuli `
* :py:class:`~pulse2percept.stimuli.ImageStimulus`
.. versionadded:: 0.7