Skip to content

Commit 93c63c8

Browse files
authored
Revert camera API change for future implementation (#517)
1 parent ef20c68 commit 93c63c8

File tree

4 files changed

+34
-24
lines changed

4 files changed

+34
-24
lines changed

docs/examples/example.ipynb

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

src/viam/components/camera/camera.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import abc
22
import sys
3-
from typing import Any, Dict, Final, List, Optional, Tuple
3+
from typing import Any, Dict, Final, List, Optional, Tuple, Union
44

5-
from viam.media.video import NamedImage, ViamImage
5+
from PIL.Image import Image
6+
7+
from viam.media.video import NamedImage
68
from viam.proto.common import ResponseMetadata
79
from viam.proto.component.camera import GetPropertiesResponse
810
from viam.resource.types import RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, Subtype
911

1012
from ..component_base import ComponentBase
13+
from . import RawImage
1114

1215
if sys.version_info >= (3, 10):
1316
from typing import TypeAlias
@@ -33,8 +36,8 @@ class Camera(ComponentBase):
3336
@abc.abstractmethod
3437
async def get_image(
3538
self, mime_type: str = "", *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs
36-
) -> ViamImage:
37-
"""Get the next image from the camera as a ViamImage.
39+
) -> Union[Image, RawImage]:
40+
"""Get the next image from the camera as an Image or RawImage.
3841
Be sure to close the image when finished.
3942
4043
NOTE: If the mime type is ``image/vnd.viam.dep`` you can use :func:`viam.media.video.ViamImage.bytes_to_depth_array`
@@ -44,7 +47,7 @@ async def get_image(
4447
mime_type (str): The desired mime type of the image. This does not guarantee output type
4548
4649
Returns:
47-
ViamImage: The frame
50+
Image | RawImage: The frame
4851
"""
4952
...
5053

src/viam/components/camera/client.py

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

34
from grpclib.client import Channel
5+
from PIL import Image
46

5-
from viam.media.video import CameraMimeType, NamedImage, ViamImage
7+
from viam.media.video import LIBRARY_SUPPORTED_FORMATS, CameraMimeType, NamedImage
68
from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry, ResponseMetadata
79
from viam.proto.component.camera import (
810
CameraServiceStub,
@@ -17,14 +19,17 @@
1719
from viam.resource.rpc_client_base import ReconfigurableResourceRPCClientBase
1820
from viam.utils import ValueTypes, dict_to_struct, get_geometries, struct_to_dict
1921

20-
from . import Camera
22+
from . import Camera, RawImage
2123

2224

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

2934

3035
class CameraClient(Camera, ReconfigurableResourceRPCClientBase):
@@ -44,7 +49,7 @@ async def get_image(
4449
extra: Optional[Dict[str, Any]] = None,
4550
timeout: Optional[float] = None,
4651
**__,
47-
) -> ViamImage:
52+
) -> Union[Image.Image, RawImage]:
4853
if extra is None:
4954
extra = {}
5055
request = GetImageRequest(name=self.name, mime_type=mime_type, extra=dict_to_struct(extra))

tests/test_camera.py

Lines changed: 13 additions & 11 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, ViamImage
13+
from viam.media.video import LIBRARY_SUPPORTED_FORMATS, CameraMimeType, NamedImage, RawImage
1414
from viam.proto.common import DoCommandRequest, DoCommandResponse, GetGeometriesRequest, GetGeometriesResponse, ResponseMetadata
1515
from viam.proto.component.camera import (
1616
CameraServiceStub,
@@ -253,29 +253,30 @@ 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.Image)
257-
assert png_img.image.tobytes() == image.tobytes()
256+
assert isinstance(png_img, Image.Image)
257+
assert png_img.tobytes() == image.tobytes()
258+
assert isinstance(png_img, Image.Image)
259+
assert png_img.tobytes() == image.tobytes()
258260
assert camera.timeout == loose_approx(1.82)
259261

260262
# Test raw mime type
261263
rgba_img = await client.get_image(CameraMimeType.VIAM_RGBA)
262-
assert isinstance(rgba_img.image, Image.Image)
263-
rgba_bytes = rgba_img.image.tobytes()
264+
assert isinstance(rgba_img, Image.Image)
265+
rgba_bytes = rgba_img.tobytes()
266+
assert isinstance(rgba_img, Image.Image)
267+
rgba_bytes = rgba_img.tobytes()
264268
assert rgba_bytes == image.copy().convert("RGBA").tobytes()
265269

266270
# Test lazy mime type
267271
raw_img = await client.get_image(CameraMimeType.PNG.with_lazy_suffix)
268-
assert isinstance(raw_img, ViamImage)
269-
assert raw_img.image is None
272+
assert isinstance(raw_img, RawImage)
270273
assert raw_img.data == image.tobytes()
271274
assert raw_img.mime_type == CameraMimeType.PNG
272275

273276
# Test unknown mime type
274277
raw_img = await client.get_image("unknown")
275-
assert isinstance(raw_img, ViamImage)
276-
assert raw_img.image is None
277-
assert raw_img.data == image.tobytes()
278-
assert raw_img.mime_type == CameraMimeType.UNSUPPORTED
278+
assert isinstance(raw_img, RawImage)
279+
assert raw_img.mime_type == "unknown"
279280

280281
@pytest.mark.asyncio
281282
async def test_get_images(self, camera: MockCamera, service: CameraRPCService, image: Image.Image, metadata: ResponseMetadata):
@@ -286,6 +287,7 @@ async def test_get_images(self, camera: MockCamera, service: CameraRPCService, i
286287
imgs, md = await client.get_images(timeout=1.82)
287288
assert isinstance(imgs[0], NamedImage)
288289
assert imgs[0].name == camera.name
290+
assert imgs[0].image is not None
289291
assert imgs[0].image.tobytes() == image.tobytes()
290292
assert md == metadata
291293
assert camera.timeout == loose_approx(1.82)

0 commit comments

Comments
 (0)