/usr/lib/python3/dist-packages/morse/sensors/video_camera.py is in python3-morse-simulator 1.4-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | import logging; logger = logging.getLogger("morse." + __name__)
from morse.core.services import async_service
from morse.core import status
import morse.core.blenderapi
from morse.core import mathutils
import morse.sensors.camera
from morse.helpers.components import add_data
import copy
BLENDER_HORIZONTAL_APERTURE = 32.0
class VideoCamera(morse.sensors.camera.Camera):
"""
This sensor emulates a single video camera. It generates a series of
RGBA images. Images are encoded as binary char arrays, with 4 bytes
per pixel.
Camera calibration matrix
-------------------------
The camera configuration parameters implicitly define a geometric camera in
blender units. Knowing that the **cam_focal** attribute is a value that
represents the distance in Blender unit at which the largest image dimension is
32.0 Blender units, the camera intrinsic calibration matrix is defined as
+--------------+-------------+---------+
| **alpha_u** | 0 | **u_0** |
+--------------+-------------+---------+
| 0 | **alpha_v** | **v_0** |
+--------------+-------------+---------+
| 0 | 0 | 1 |
+--------------+-------------+---------+
where:
- **alpha_u** == **alpha_v** = **cam_width** . **cam_focal** / 32 (we suppose
here that **cam_width** > **cam_height**. If not, then use **cam_height** in
the formula)
- **u_0** = **cam_width** / 2
- **v_0** = **cam_height** / 2
See also :doc:`../sensors/camera` for generic informations about Morse cameras.
"""
_name = "Video camera"
_short_desc = "A camera capturing RGBA image"
add_data('image', 'none', 'buffer',
"The data captured by the camera, stored as a Python Buffer \
class object. The data is of size ``(cam_width * cam_height * 4)``\
bytes. The image is stored as RGBA.")
add_data('intrinsic_matrix', 'none', 'mat3<float>',
"The intrinsic calibration matrix, stored as a 3x3 row major Matrix.")
def __init__(self, obj, parent=None):
""" Constructor method.
Receives the reference to the Blender object.
The second parameter should be the name of the object's parent.
"""
logger.info('%s initialization' % obj.name)
# Call the constructor of the parent class
morse.sensors.camera.Camera.__init__(self, obj, parent)
# Prepare the exportable data of this sensor
self.local_data['image'] = ''
# Prepare the intrinsic matrix for this camera.
# Note that the matrix is stored in row major
intrinsic = mathutils.Matrix.Identity(3)
alpha_u = self.image_width * \
self.image_focal / BLENDER_HORIZONTAL_APERTURE
intrinsic[0][0] = alpha_u
intrinsic[1][1] = alpha_u
intrinsic[0][2] = self.image_width / 2.0
intrinsic[1][2] = self.image_height / 2.0
self.local_data['intrinsic_matrix'] = intrinsic
self.capturing = False
self._n = -1
# Variable to indicate this is a camera
self.camera_tag = True
# Position of the robot where the last shot is taken
self.robot_pose = copy.copy(self.robot_parent.position_3d)
logger.info("Component initialized, runs at %.2f Hz ", self.frequency)
def interrupt(self):
self._n = 0
morse.sensors.camera.Camera.interrupt(self)
@async_service
def capture(self, n):
"""
Capture **n** images
:param n: the number of images to take. A negative number means
take image indefinitely
"""
self._n = n
def default_action(self):
""" Update the texture image. """
# Grab an image from the texture
if self.bge_object['capturing'] and (self._n != 0) :
# Call the action of the parent class
morse.sensors.camera.Camera.default_action(self)
# NOTE: Blender returns the image as a binary string
# encoded as RGBA
image_data = morse.core.blenderapi.cameras()[self.name()].source
self.robot_pose = copy.copy(self.robot_parent.position_3d)
# Fill in the exportable data
self.local_data['image'] = image_data
self.capturing = True
if self._n > 0:
self._n -= 1
if self._n == 0:
self.completed(status.SUCCESS)
else:
self.capturing = False
|