From 7ac41edf7e2ad88e3f8dfac5526dd62fc758d6dd Mon Sep 17 00:00:00 2001 From: Lillian Hwang-Geddes Date: Mon, 24 Nov 2025 11:48:17 -0500 Subject: [PATCH 1/3] update validate config and get images functions --- .viam-gen-info | 2 +- src/blurry_classifier_module.py | 18 ++++++++++++------ tests/fake_camera.py | 2 +- tests/test_blurry_classifier.py | 8 ++++++-- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/.viam-gen-info b/.viam-gen-info index 72073ff..8f276ce 100644 --- a/.viam-gen-info +++ b/.viam-gen-info @@ -3,7 +3,7 @@ "namespace": "viam", "language": "python", "resource_type": "service", - "resource_subtype": "vision", + "resource_api": "vision", "model_name": "blurry-classifier", "enable_cloud_build": true, "initialize_git": false, diff --git a/src/blurry_classifier_module.py b/src/blurry_classifier_module.py index d1e304c..68d32ef 100644 --- a/src/blurry_classifier_module.py +++ b/src/blurry_classifier_module.py @@ -1,4 +1,4 @@ -from typing import ClassVar, List, Mapping, Optional, Sequence +from typing import ClassVar, List, Mapping, Optional, Sequence, Tuple from typing_extensions import Self from viam.components.camera import Camera @@ -23,7 +23,7 @@ class BlurryClassifier(Vision, EasyResource): """ BlurryClassifier implements a vision service that only supports classifications. - It inherits from the built-in resource subtype Vision and conforms to the + It inherits from the built-in resource api Vision and conforms to the ``Reconfigurable`` protocol, which signifies that this component can be reconfigured. Additionally, it specifies a constructor function ``BlurryClassifier.new`` which confirms to the @@ -64,7 +64,7 @@ def new( return service @classmethod - def validate_config(cls, config: ComponentConfig) -> Sequence[str]: + def validate_config(cls, config: ComponentConfig) -> Tuple[Sequence[str], Sequence[str]]: """ This method allows you to validate the configuration object received from the machine, as well as to return any implicit dependencies based @@ -81,7 +81,7 @@ def validate_config(cls, config: ComponentConfig) -> Sequence[str]: raise ValueError( "A camera name is required for face_identification vision service module." ) - return [camera_name] + return [camera_name], [] def reconfigure( self, @@ -119,7 +119,10 @@ async def capture_all_from_camera( f"Camera name {camera_name} does not match the camera name " + f"{self.camera_name} in the config." ) - im = await self.camera.get_image(mime_type=CameraMimeType.JPEG) + imgs = await self.camera.get_images() + if len(imgs) == 0: + raise ValueError("No images returned by get_images") + im = imgs[0] classifications = None if return_classifications: classifications = await self.get_classifications( @@ -159,7 +162,10 @@ async def get_classifications_from_camera( f"Camera name {camera_name} does not match the camera name " + f"{self.camera_name} in the config." ) - im = await self.camera.get_image(mime_type=CameraMimeType.JPEG) + imgs = await self.camera.get_images() + if len(imgs) == 0: + raise ValueError("No images returned by get_images") + im = imgs[0] return await self.get_classifications(im, 1, extra=extra, timeout=timeout) async def get_classifications( diff --git a/tests/fake_camera.py b/tests/fake_camera.py index 92d427a..3cb6b46 100644 --- a/tests/fake_camera.py +++ b/tests/fake_camera.py @@ -24,7 +24,7 @@ async def get_image(self, mime_type: str = "") -> Coroutine[Any, Any, ViamImage] async def get_images( self, ) -> Coroutine[Any, Any, Tuple[Union[List[NamedImage], ResponseMetadata]]]: - raise NotImplementedError + return [pil.pil_to_viam_image(self.image, CameraMimeType.JPEG)] async def get_properties(self) -> Coroutine[Any, Any, GetPropertiesResponse]: raise NotImplementedError diff --git a/tests/test_blurry_classifier.py b/tests/test_blurry_classifier.py index d2d088d..5bd4c6c 100644 --- a/tests/test_blurry_classifier.py +++ b/tests/test_blurry_classifier.py @@ -47,8 +47,11 @@ async def test_get_classifications(self, fake_cam): blurry_classifier = get_vision_service(True) # Test with a blurry image + images = await blurry_classifier.camera.get_images() + image = images[0] + print(image) result = await blurry_classifier.get_classifications( - image= await blurry_classifier.camera.get_image(), + image = images[0], count=1, ) @@ -57,8 +60,9 @@ async def test_get_classifications(self, fake_cam): blurry_classifier = get_vision_service(False) # Test with a non-blurry image + images=await blurry_classifier.camera.get_images() result = await blurry_classifier.get_classifications( - image=await blurry_classifier.camera.get_image(), + image= images[0], count=1, ) From 93fcdf659db433f0f4bea1d8647c128d94958e9a Mon Sep 17 00:00:00 2001 From: Lillian Hwang-Geddes Date: Mon, 24 Nov 2025 11:48:59 -0500 Subject: [PATCH 2/3] remove old import --- src/blurry_classifier_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blurry_classifier_module.py b/src/blurry_classifier_module.py index 68d32ef..22e12a0 100644 --- a/src/blurry_classifier_module.py +++ b/src/blurry_classifier_module.py @@ -2,7 +2,7 @@ from typing_extensions import Self from viam.components.camera import Camera -from viam.media.video import CameraMimeType, ViamImage +from viam.media.video import ViamImage from viam.proto.app.robot import ComponentConfig from viam.proto.common import PointCloudObject, ResourceName from viam.proto.service.vision import Classification, Detection From 0b5da3fdb5235a9635b1f14f5be0a3a9e76b2c28 Mon Sep 17 00:00:00 2001 From: Lillian Hwang-Geddes Date: Tue, 2 Dec 2025 11:49:55 -0500 Subject: [PATCH 3/3] take metadata into account --- src/blurry_classifier_module.py | 8 ++++---- tests/fake_camera.py | 2 +- tests/test_blurry_classifier.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/blurry_classifier_module.py b/src/blurry_classifier_module.py index 22e12a0..c6ed2b3 100644 --- a/src/blurry_classifier_module.py +++ b/src/blurry_classifier_module.py @@ -119,8 +119,8 @@ async def capture_all_from_camera( f"Camera name {camera_name} does not match the camera name " + f"{self.camera_name} in the config." ) - imgs = await self.camera.get_images() - if len(imgs) == 0: + imgs, _ = await self.camera.get_images() + if imgs is None or len(imgs) == 0: raise ValueError("No images returned by get_images") im = imgs[0] classifications = None @@ -162,8 +162,8 @@ async def get_classifications_from_camera( f"Camera name {camera_name} does not match the camera name " + f"{self.camera_name} in the config." ) - imgs = await self.camera.get_images() - if len(imgs) == 0: + imgs, _ = await self.camera.get_images() + if imgs is None or len(imgs) == 0: raise ValueError("No images returned by get_images") im = imgs[0] return await self.get_classifications(im, 1, extra=extra, timeout=timeout) diff --git a/tests/fake_camera.py b/tests/fake_camera.py index 3cb6b46..211223b 100644 --- a/tests/fake_camera.py +++ b/tests/fake_camera.py @@ -24,7 +24,7 @@ async def get_image(self, mime_type: str = "") -> Coroutine[Any, Any, ViamImage] async def get_images( self, ) -> Coroutine[Any, Any, Tuple[Union[List[NamedImage], ResponseMetadata]]]: - return [pil.pil_to_viam_image(self.image, CameraMimeType.JPEG)] + return [pil.pil_to_viam_image(self.image, CameraMimeType.JPEG)], None async def get_properties(self) -> Coroutine[Any, Any, GetPropertiesResponse]: raise NotImplementedError diff --git a/tests/test_blurry_classifier.py b/tests/test_blurry_classifier.py index 5bd4c6c..eaf73bc 100644 --- a/tests/test_blurry_classifier.py +++ b/tests/test_blurry_classifier.py @@ -47,7 +47,7 @@ async def test_get_classifications(self, fake_cam): blurry_classifier = get_vision_service(True) # Test with a blurry image - images = await blurry_classifier.camera.get_images() + images, _ = await blurry_classifier.camera.get_images() image = images[0] print(image) result = await blurry_classifier.get_classifications( @@ -60,7 +60,7 @@ async def test_get_classifications(self, fake_cam): blurry_classifier = get_vision_service(False) # Test with a non-blurry image - images=await blurry_classifier.camera.get_images() + images, _ =await blurry_classifier.camera.get_images() result = await blurry_classifier.get_classifications( image= images[0], count=1,