Skip to content

Conversation

@hexbabe
Copy link
Member

@hexbabe hexbabe commented Aug 28, 2025

CLOSING since #995 fixes the issue

Fix bug by handling mime type type conversion in vision service server and client

Manual Tests

Test with python vision service

Created a fake vision model that serves only capture_all_from_camera and returns a blank white JPEG https://github.com/hexbabe/heart-beat-module/blob/6e167e9119c0d096bf0fb2cdef50cdcfdb5c3f4a/src/fake_vision.py#L59-L77

Uninstalled the pypi version of viam_sdk and manually installed my current feature branch built local wheel of the SDK to the virtual environment of the module

Used a Python client to call capture_all_from_camera

async def main():
    try:
        machine = await connect()
        fake_vision = VisionClient.from_robot(machine, "fake-vision-1")

        resp = await fake_vision.capture_all_from_camera("camera", True, True, True, True)
        print("captured all from camera")
        print("image.mime_type:", resp.image.mime_type)
        print("image.height:", resp.image.height)
        print("image.width:", resp.image.width)
        img = Image.open(io.BytesIO(resp.image.data))
        img.show()
        await fake_vision.close()
    except Exception as e:
        print("caught exception: ", e)
    finally:
        await machine.close()


if __name__ == '__main__':
  asyncio.run(main())

Output

(.venv) seanyu@ROBOT-G26PRFHC2H python-sdk-client % python3 test_capture_all_from_camera.py
2025-08-28 16:56:16,849         INFO    viam.rpc.dial (dial.py:336)     Connecting to socket: /tmp/proxy-TOxCLdoi.sock
captured all from camera
image.mime_type: CameraMimeType.JPEG
image.height: 480
image.width: 640

Also opened the image and confirmed it was a blank white jpeg

Regression test with oak-d

Ran the same test as from #982 (comment) and verified no regression for GetImages server and client.

@hexbabe hexbabe requested a review from a team as a code owner August 28, 2025 16:13
@hexbabe hexbabe requested review from dhritinaidu and njooma August 28, 2025 16:13
@github-actions
Copy link
Contributor

Warning your change may break code samples. If your change modifies any of the following functions please contact @viamrobotics/fleet-management. Thanks!

component function
base is_moving
board gpio_pin_by_name
button push
genericcomponent do_command
camera get_image
encoder get_position
motor is_moving
sensor get_readings
servo get_position
switch get_position
arm get_end_position
gantry get_lengths
gripper is_moving
movement_sensor get_linear_acceleration
input_controller get_controls
audio get_properties
pose_tracker get_poses
power_sensor get_power
motion get_pose
vision get_properties
mlmodel metadata
genericservice do_command
slam get_point_cloud_map

Copy link
Member

@njooma njooma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to use .value everywhere. According to the docs, an enum that subclasses from str should behave just like a string

Comment on lines 77 to 79
The extra parameter can be used to pass additional options to the camera resource. The filter_source_names parameter can be used to filter
only the images from the specified source names. When unspecified, all images are returned.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the filter_source_names arg like we do in the get_image docstring. no need to add extra to this list of args

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gotcha

else:
# TODO(RSDK-11728): remove this once we deleted the format field
mime_type = str(CameraMimeType.from_proto(img_data.format))
mime_type = CameraMimeType.from_proto(img_data.format).value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to happen? CameraMimeType is a string, and should be accepted wherever strs are accepted

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry this PR wasn't really ready to review yet. This repo seems to auto-request reviews. I was just doing this to see if more tests would fail as an experiment. I've changed them back

Args:
image (Image.Image): The image to convert.
mime_type (CameraMimeType): The mime type to convert the image to.
mime_type (str): The mime type to convert the image to. Must be one of the `CameraMimeType` enum string literals.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this must be one of the enum properties, why not keep this as CameraMimeType?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

Comment on lines 20 to 59
def __str__(self) -> str:
return self.value

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really only helpful for printing

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can remove

@hexbabe hexbabe force-pushed the RSDK-11704 branch 3 times, most recently from 769b30b to f8c39c7 Compare August 28, 2025 20:30
@hexbabe hexbabe marked this pull request as draft August 28, 2025 20:52
@hexbabe hexbabe force-pushed the RSDK-11704 branch 2 times, most recently from be404a7 to 162aa7e Compare August 28, 2025 21:05
@hexbabe hexbabe requested review from bhaney and njooma August 28, 2025 21:06
@hexbabe hexbabe marked this pull request as ready for review August 28, 2025 21:06
Comment on lines 42 to 45
# Make sure at runtime the mime_type string is actually a CameraMimeType
if not isinstance(mime_type, CameraMimeType):
raise ValueError(f"Unsupported mimetype str: {mime_type}")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were you running into issues here?

Copy link
Member Author

@hexbabe hexbabe Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but the user can pass str in runtime regardless of the hint, so I figured it'd be good to give a more explicit error when that happens.

request = await stream.recv_message()
assert request is not None
vision = self.get_resource(request.name)
vision: Vision = self.get_resource(request.name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you can also do to fix this type issue is on line 29, update the class inheritance to be VisionRPCService(UnimplementedVisionServiceBase, ResourceRPCServiceBase[Vision])

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice I like that. Done and removed inline hint

Copy link
Member

@bhaney bhaney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mostly questions about things for this PR

VISION_IMAGE = ViamImage(bytes([0, 100]), CameraMimeType.JPEG)
# Use string value of CameraMimeType because ViamImage accepts a string mime type in the worst case
# and it may not have the expected CameraMimeType methods defined on it.
VISION_IMAGE = ViamImage(bytes([0, 100]), CameraMimeType.JPEG.value)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still curious why we want to use a second VISION_IMAGE here when we already have an IMAGE variable (used in other tests) that could be used in the same way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it's to make writing the mock easier? @njooma ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't have an answer to this question, so won't approve until then

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants