Skip to content

Commit 5117914

Browse files
committed
Added sensor_modes property to list the available sensor modes for the attached camera.
1 parent 3c93d02 commit 5117914

File tree

3 files changed

+119
-21
lines changed

3 files changed

+119
-21
lines changed

docs/api_camera.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,9 @@ PiFramerateRange
4343
================
4444

4545
.. autoclass:: PiFramerateRange(low, high)
46+
47+
48+
PiSensorMode
49+
============
50+
51+
.. autoclass:: PiSensorMode(resolution, framerates, video, still, full_fov)

picamera/camera.py

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,27 @@ class PiCamera(object):
194194
DEFAULT_ANNOTATE_SIZE = 32
195195
CAPTURE_TIMEOUT = 60
196196

197+
SENSOR_MODES = {
198+
'ov5647': {
199+
1: mo.PiSensorMode('1080p', (1, 30), full_fov=False),
200+
2: mo.PiSensorMode('2592x1944', (1, 15), still=True),
201+
3: mo.PiSensorMode('2592x1944', (1/6, 1), still=True),
202+
4: mo.PiSensorMode('1296x972', (1, 42)),
203+
5: mo.PiSensorMode('1296x730', (1, 49)),
204+
6: mo.PiSensorMode('VGA', (42, 60)),
205+
7: mo.PiSensorMode('VGA', (60, 90)),
206+
},
207+
'imx219': {
208+
1: mo.PiSensorMode('1080p', (1/10, 30), full_fov=False),
209+
2: mo.PiSensorMode('3280x2464', (1/10, 15), still=True),
210+
3: mo.PiSensorMode('3280x2464', (1/10, 15), still=True),
211+
4: mo.PiSensorMode('1640x1232', (1/10, 40)),
212+
5: mo.PiSensorMode('1640x922', (1/10, 40)),
213+
6: mo.PiSensorMode('720p', (40, 90), full_fov=False),
214+
7: mo.PiSensorMode('VGA', (40, 90), full_fov=False),
215+
},
216+
}
217+
197218
METER_MODES = {
198219
'average': mmal.MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
199220
'spot': mmal.MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
@@ -508,7 +529,8 @@ def _init_preview(self):
508529
# Create a null-sink component, enable it and connect it to the
509530
# camera's preview port. If nothing is connected to the preview port,
510531
# the camera doesn't measure exposure and captured images gradually
511-
# fade to black (issue #22)
532+
# fade to black (issue #22; subsequently fixed in firmware but there's
533+
# no harm in leaving this in place for the sake of backwards compat)
512534
self._preview = PiNullSink(
513535
self, self._camera.outputs[self.CAMERA_PREVIEW_PORT])
514536

@@ -1769,10 +1791,10 @@ def exif_tags(self):
17691791
17701792
By default several Exif tags are automatically applied to any images
17711793
taken with the :meth:`capture` method: ``IFD0.Make`` (which is set to
1772-
``RaspberryPi``), ``IFD0.Model`` (which is set to ``RP_OV5647``), and
1773-
three timestamp tags: ``IFD0.DateTime``, ``EXIF.DateTimeOriginal``, and
1774-
``EXIF.DateTimeDigitized`` which are all set to the current date and
1775-
time just before the picture is taken.
1794+
``RaspberryPi``), ``IFD0.Model`` (which is set to the camera's revision
1795+
string), and three timestamp tags: ``IFD0.DateTime``,
1796+
``EXIF.DateTimeOriginal``, and ``EXIF.DateTimeDigitized`` which are all
1797+
set to the current date and time just before the picture is taken.
17761798
17771799
If you wish to set additional Exif tags, or override any of the
17781800
aforementioned tags, simply add entries to the exif_tags map before
@@ -1875,9 +1897,9 @@ def _set_led(self, value):
18751897
18761898
.. note::
18771899
1878-
At present, the camera's LED cannot be controlled on the Pi 3
1900+
At present, the camera's LED cannot be controlled on the Pi 3 or 3+
18791901
(the GPIOs used to control the camera LED were re-routed to GPIO
1880-
expander on the Pi 3).
1902+
expander on these models).
18811903
18821904
.. warning::
18831905
@@ -1886,8 +1908,8 @@ def _set_led(self, value):
18861908
resets the camera (as can happen with a CSI-2 timeout), the LED may
18871909
also be reset. If you wish to guarantee that the LED remain off at
18881910
all times, you may prefer to use the ``disable_camera_led`` option
1889-
in `config.txt`_ (this has the added advantage that sudo privileges
1890-
and GPIO access are not required, at least for LED control).
1911+
in `config.txt`_ (this has the added advantage that GPIO access is
1912+
not required, at least for LED control).
18911913
18921914
.. _config.txt: https://www.raspberrypi.org/documentation/configuration/config-txt.md
18931915
""")
@@ -2169,6 +2191,21 @@ def _set_framerate(self, value):
21692191
default to 30 if not specified.
21702192
""")
21712193

2194+
@property
2195+
def sensor_modes(self):
2196+
"""
2197+
Returns a mapping describing the available sensor modes for the
2198+
camera model.
2199+
2200+
This read-only attribute returns a dictionary mapping sensor mode
2201+
numbers (1..7) to instances of :class:`PiSensorMode` which contain the
2202+
resolution, range of framerates, and other details about the mode.
2203+
Note that the default mode (0) is not represented, as this indicates
2204+
that the mode should be selected automatically by the firmware based
2205+
on the requested :attr:`resolution` and :attr:`framerate`.
2206+
"""
2207+
return PiCamera.SENSOR_MODES[self.revision]
2208+
21722209
def _get_sensor_mode(self):
21732210
self._check_camera_open()
21742211
return self._camera.control.params[mmal.MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG]
@@ -2337,8 +2374,7 @@ def _get_framerate_range(self):
23372374
self.CAMERA_PREVIEW_PORT
23382375
)
23392376
mp = self._camera.outputs[port_num].params[mmal.MMAL_PARAMETER_FPS_RANGE]
2340-
return mo.PiFramerateRange(
2341-
mo.to_fraction(mp.fps_low), mo.to_fraction(mp.fps_high))
2377+
return mo.PiFramerateRange(mp.fps_low, mp.fps_high)
23422378
def _set_framerate_range(self, value):
23432379
self._check_camera_open()
23442380
self._check_recording_stopped()
@@ -2795,6 +2831,16 @@ def _set_iso(self, value):
27952831
explicitly set will be one of the following values (whichever is
27962832
closest): 100, 200, 320, 400, 500, 640, 800.
27972833
2834+
.. note::
2835+
2836+
Some users on the Pi camera forum have noted that higher ISO values
2837+
than 800 (specifically up to 1600) can be achieved in certain
2838+
conditions with :attr:`exposure_mode` set to ``'sports'`` and
2839+
:attr:`iso` set to 0. It doesn't appear to be possible to manually
2840+
request an ISO setting higher than 800, but the picamera library
2841+
will permit settings up to 1600 in case the underlying firmware
2842+
permits such settings in particular circumstances.
2843+
27982844
On the V1 camera module, non-zero ISO values attempt to fix overall
27992845
gain at various levels. For example, ISO 100 attempts to provide an
28002846
overall gain of 1.0, ISO 200 attempts to provide overall gain of 2.0,
@@ -2809,16 +2855,6 @@ def _set_iso(self, value):
28092855
progress. The default value is 0 which means automatically determine a
28102856
value according to image-taking conditions.
28112857
2812-
.. note::
2813-
2814-
Some users on the Pi camera forum have noted that higher ISO values
2815-
than 800 (specifically up to 1600) can be achieved in certain
2816-
conditions with :attr:`exposure_mode` set to ``'sports'`` and
2817-
:attr:`iso` set to 0. It doesn't appear to be possible to manually
2818-
request an ISO setting higher than 800, but the picamera library
2819-
will permit settings up to 1600 in case the underlying firmware
2820-
permits such settings in particular circumstances.
2821-
28222858
.. note::
28232859
28242860
Certain :attr:`exposure_mode` values override the ISO setting. For

picamera/mmalobj.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,66 @@ class PiFramerateRange(namedtuple('PiFramerateRange', ('low', 'high'))):
317317

318318
__slots__ = () # workaround python issue #24931
319319

320+
def __new__(cls, low, high):
321+
return super(PiFramerateRange, cls).__new__(cls, to_fraction(low),
322+
to_fraction(high))
323+
320324
def __str__(self):
321325
return '%s..%s' % (self.low, self.high)
322326

323327

328+
class PiSensorMode(namedtuple('PiSensorMode', ('resolution', 'framerates',
329+
'video', 'still', 'full_fov'))):
330+
"""
331+
This class is a :func:`~collections.namedtuple` derivative used to store
332+
the attributes describing a camera sensor mode.
333+
334+
.. attribute:: resolution
335+
336+
A :class:`PiResolution` specifying the size of frames output by the
337+
camera in this mode.
338+
339+
.. attribute:: framerates
340+
341+
A :class:`PiFramerateRange` specifying the minimum and maximum
342+
framerates supported by this sensor mode. Typically the low value is
343+
exclusive and high value inclusive.
344+
345+
.. attribute:: video
346+
347+
A :class:`bool` indicating whether or not the mode is capable of
348+
recording video. Currently this is always ``True``.
349+
350+
.. attribute:: still
351+
352+
A :class:`bool` indicating whether the mode can be used for still
353+
captures (cases where a capture method is called with
354+
``use_video_port`` set to ``False``).
355+
356+
.. attribute:: full_fov
357+
358+
A :class:`bool` indicating whether the full width of the sensor
359+
area is used to capture frames. This can be ``True`` even when the
360+
resolution is less than the camera's maximum resolution due to binning
361+
and skipping. See :ref:`camera_modes` for a diagram of the available
362+
fields of view.
363+
"""
364+
365+
__slots__ = () # workaround python issue #24931
366+
367+
def __new__(cls, resolution, framerates, video=True, still=False,
368+
full_fov=True):
369+
return super(PiSensorMode, cls).__new__(
370+
cls,
371+
resolution
372+
if isinstance(resolution, PiResolution) else
373+
to_resolution(resolution),
374+
framerates
375+
if isinstance(framerates, PiFramerateRange) else
376+
PiFramerateRange(*framerates),
377+
video, still, full_fov)
378+
379+
324380
def open_stream(stream, output=True, buffering=65536):
325381
"""
326382
This is the core of picamera's IO-semantics. It returns a tuple of a

0 commit comments

Comments
 (0)