Skip to content

Commit 35c64cb

Browse files
RSDK-4089: change camera api return types (#495)
1 parent fb2ee20 commit 35c64cb

File tree

5 files changed

+25
-32
lines changed

5 files changed

+25
-32
lines changed

docs/examples/example.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@
164164
"robot = await connect_with_channel()\n",
165165
"camera = Camera.from_robot(robot, \"camera0\")\n",
166166
"image = await camera.get_image(CameraMimeType.JPEG)\n",
167-
"image.save(\"foo.png\")\n",
167+
"image.image.save(\"foo.png\")\n",
168168
"\n",
169169
"# Don't forget to close the robot when you're done!\n",
170170
"await robot.close()\n"

src/viam/components/camera/camera.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import abc
2-
from typing import Any, Dict, Final, List, NamedTuple, Optional, Tuple, Union
2+
from typing import Any, Dict, Final, List, NamedTuple, Optional, Tuple
33

4-
from PIL.Image import Image
5-
6-
from viam.media.video import NamedImage
4+
from viam.media.video import NamedImage, ViamImage
75
from viam.proto.common import ResponseMetadata
86
from viam.resource.types import RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, Subtype
97

108
from ..component_base import ComponentBase
11-
from . import DistortionParameters, IntrinsicParameters, RawImage
9+
from . import DistortionParameters, IntrinsicParameters
1210

1311

1412
class Camera(ComponentBase):
@@ -37,8 +35,8 @@ class Properties(NamedTuple):
3735
@abc.abstractmethod
3836
async def get_image(
3937
self, mime_type: str = "", *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs
40-
) -> Union[Image, RawImage]:
41-
"""Get the next image from the camera as an Image or RawImage.
38+
) -> ViamImage:
39+
"""Get the next image from the camera as a ViamImage.
4240
Be sure to close the image when finished.
4341
4442
NOTE: If the mime type is ``image/vnd.viam.dep`` you can use :func:`viam.media.video.RawImage.bytes_to_depth_array`
@@ -48,7 +46,7 @@ async def get_image(
4846
mime_type (str): The desired mime type of the image. This does not guarantee output type
4947
5048
Returns:
51-
Image | RawImage: The frame
49+
ViamImage: The frame
5250
"""
5351
...
5452

src/viam/components/camera/client.py

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
from io import BytesIO
2-
from typing import Any, Dict, List, Mapping, Optional, Tuple, Union
1+
from typing import Any, Dict, List, Mapping, Optional, Tuple
32

43
from grpclib.client import Channel
5-
from PIL import Image
64

7-
from viam.media.video import LIBRARY_SUPPORTED_FORMATS, CameraMimeType, NamedImage
5+
from viam.media.video import CameraMimeType, NamedImage, ViamImage
86
from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry, ResponseMetadata
97
from viam.proto.component.camera import (
108
CameraServiceStub,
@@ -20,17 +18,14 @@
2018
from viam.resource.rpc_client_base import ReconfigurableResourceRPCClientBase
2119
from viam.utils import ValueTypes, dict_to_struct, get_geometries, struct_to_dict
2220

23-
from . import Camera, RawImage
21+
from . import Camera
2422

2523

26-
def get_image_from_response(data: bytes, response_mime_type: str, request_mime_type: str) -> Union[Image.Image, RawImage]:
24+
def get_image_from_response(data: bytes, response_mime_type: str, request_mime_type: str) -> ViamImage:
2725
if not request_mime_type:
2826
request_mime_type = response_mime_type
29-
mime_type, is_lazy = CameraMimeType.from_lazy(request_mime_type)
30-
if is_lazy or mime_type._should_be_raw:
31-
image = RawImage(data=data, mime_type=response_mime_type)
32-
return image
33-
return Image.open(BytesIO(data), formats=LIBRARY_SUPPORTED_FORMATS)
27+
mime_type, _ = CameraMimeType.from_lazy(request_mime_type)
28+
return ViamImage(data, mime_type)
3429

3530

3631
class CameraClient(Camera, ReconfigurableResourceRPCClientBase):
@@ -43,9 +38,7 @@ def __init__(self, name: str, channel: Channel):
4338
self.client = CameraServiceStub(channel)
4439
super().__init__(name)
4540

46-
async def get_image(
47-
self, mime_type: str = "", *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None
48-
) -> Union[Image.Image, RawImage]:
41+
async def get_image(self, mime_type: str = "", *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None) -> ViamImage:
4942
if extra is None:
5043
extra = {}
5144
request = GetImageRequest(name=self.name, mime_type=mime_type, extra=dict_to_struct(extra))

src/viam/components/camera/service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ async def GetImage(self, stream: Stream[GetImageRequest, GetImageResponse]) -> N
4747

4848
request.mime_type = self._camera_mime_types[camera.name]
4949

50-
mimetype, is_lazy = CameraMimeType.from_lazy(request.mime_type)
50+
mimetype, _ = CameraMimeType.from_lazy(request.mime_type)
5151
if CameraMimeType.is_supported(mimetype):
5252
response_mime = mimetype
5353
else:

tests/test_camera.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from viam.components.camera import Camera, CameraClient
1111
from viam.components.camera.service import CameraRPCService
1212
from viam.components.generic.service import GenericRPCService
13-
from viam.media.video import LIBRARY_SUPPORTED_FORMATS, CameraMimeType, NamedImage, RawImage
13+
from viam.media.video import LIBRARY_SUPPORTED_FORMATS, CameraMimeType, NamedImage, RawImage, ViamImage
1414
from viam.proto.common import DoCommandRequest, DoCommandResponse, GetGeometriesRequest, GetGeometriesResponse, ResponseMetadata
1515
from viam.proto.component.camera import (
1616
CameraServiceStub,
@@ -253,27 +253,29 @@ async def test_get_image(self, camera: MockCamera, service: CameraRPCService, im
253253

254254
# Test known mime type
255255
png_img = await client.get_image(timeout=1.82, mime_type=CameraMimeType.PNG)
256-
assert isinstance(png_img, Image.Image)
257-
assert png_img.tobytes() == image.tobytes()
256+
assert isinstance(png_img.image, Image.Image)
257+
assert png_img.image.tobytes() == image.tobytes()
258258
assert camera.timeout == loose_approx(1.82)
259259

260260
# Test raw mime type
261261
rgba_img = await client.get_image(CameraMimeType.VIAM_RGBA)
262-
assert isinstance(rgba_img, Image.Image)
263-
rgba_bytes = rgba_img.tobytes()
262+
assert isinstance(rgba_img.image, Image.Image)
263+
rgba_bytes = rgba_img.image.tobytes()
264264
assert rgba_bytes == image.copy().convert("RGBA").tobytes()
265265

266266
# Test lazy mime type
267267
raw_img = await client.get_image(CameraMimeType.PNG.with_lazy_suffix)
268-
assert isinstance(raw_img, RawImage)
268+
assert isinstance(raw_img, ViamImage)
269+
assert raw_img.image is None
269270
assert raw_img.data == image.tobytes()
270271
assert raw_img.mime_type == CameraMimeType.PNG
271272

272273
# Test unknown mime type
273274
raw_img = await client.get_image("unknown")
274-
assert isinstance(raw_img, RawImage)
275+
assert isinstance(raw_img, ViamImage)
276+
assert raw_img.image is None
275277
assert raw_img.data == image.tobytes()
276-
assert raw_img.mime_type == "unknown"
278+
assert raw_img.mime_type == CameraMimeType.UNSUPPORTED
277279

278280
@pytest.mark.asyncio
279281
async def test_get_images(self, camera: MockCamera, service: CameraRPCService, image: Image.Image, metadata: ResponseMetadata):

0 commit comments

Comments
 (0)