Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fb3c314
docs: add Vision service SDK + template design spec
HipsterBrown May 8, 2026
ba66c3d
docs: address spec review for Vision service design
HipsterBrown May 8, 2026
ce587c7
docs: resolve advisory items in Vision service spec
HipsterBrown May 8, 2026
2fc9b00
docs: add Vision service implementation plan
HipsterBrown May 8, 2026
78b1458
docs: address plan review for Vision service
HipsterBrown May 8, 2026
a9d8153
docs: align spec proto-conv signatures with plan
HipsterBrown May 8, 2026
80c7536
refactor: lift Camera raw_image proto-conv into common/private
HipsterBrown May 8, 2026
a86410a
feat(sdk): add Vision service public abstract class
HipsterBrown May 8, 2026
fa82d46
fix(sdk): clang-format vision.{hpp,cpp} and DRY point_cloud_object::o…
HipsterBrown May 8, 2026
0ace132
feat(sdk): add Vision proto-conv helpers + round-trip tests
HipsterBrown May 8, 2026
6cc972a
refactor(sdk): use impl::to/from_repeated_field for vision geometries
HipsterBrown May 8, 2026
19d2bd3
feat(sdk): add VisionClient skeleton (all methods throw)
HipsterBrown May 8, 2026
392e508
feat(sdk): add VisionServer skeleton + registry wiring
HipsterBrown May 8, 2026
e924b9a
test(sdk): add MockVision skeleton wired into viamsdk_test
HipsterBrown May 8, 2026
4e652d2
fix(test): move MockVision to viam::sdktests::vision namespace
HipsterBrown May 8, 2026
817b597
test(sdk): add vision_fixture helper for end-to-end RPC tests
HipsterBrown May 8, 2026
b1be15f
fix(test): order vision_fixture members so channel outlives client
HipsterBrown May 8, 2026
4480ec6
feat(sdk): implement Vision::get_properties end-to-end
HipsterBrown May 8, 2026
e777497
feat(sdk): implement Vision::get_status end-to-end
HipsterBrown May 8, 2026
02ea329
feat(sdk): implement Vision::do_command end-to-end
HipsterBrown May 8, 2026
d463bd1
feat(sdk): implement Vision::get_classifications{,_from_camera} end-t…
HipsterBrown May 8, 2026
e494533
feat(sdk): implement Vision::get_detections{,_from_camera} end-to-end
HipsterBrown May 8, 2026
d647ca6
feat(sdk): implement Vision::get_object_point_clouds end-to-end
HipsterBrown May 8, 2026
f127631
feat(sdk): implement Vision::capture_all_from_camera end-to-end
HipsterBrown May 8, 2026
7474f19
test(sdk): verify server exceptions map to non-OK grpc::Status
HipsterBrown May 8, 2026
1141779
chore(sdk): tidy up review comments on vision client and fixture
HipsterBrown May 8, 2026
1ad943d
chore: remove planning docs
HipsterBrown May 18, 2026
3913578
fix(sdk): address Vision service review feedback
HipsterBrown May 18, 2026
4d183b0
chore(sdk): restore dial.hpp formatting to match main
HipsterBrown May 18, 2026
63c2363
chore(sdk): brace single-line ifs in vision proto-conv
HipsterBrown May 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/viam/api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ if (VIAMCPPSDK_USE_DYNAMIC_PROTOS)
${PROTO_GEN_DIR}/service/slam/v1/slam.grpc.pb.h
${PROTO_GEN_DIR}/service/slam/v1/slam.pb.cc
${PROTO_GEN_DIR}/service/slam/v1/slam.pb.h
${PROTO_GEN_DIR}/service/vision/v1/vision.grpc.pb.cc
${PROTO_GEN_DIR}/service/vision/v1/vision.grpc.pb.h
${PROTO_GEN_DIR}/service/vision/v1/vision.pb.cc
${PROTO_GEN_DIR}/service/vision/v1/vision.pb.h
${PROTO_GEN_DIR}/tagger/v1/tagger.grpc.pb.cc
${PROTO_GEN_DIR}/tagger/v1/tagger.grpc.pb.h
${PROTO_GEN_DIR}/tagger/v1/tagger.pb.cc
Expand Down Expand Up @@ -381,6 +385,8 @@ target_sources(viamapi
${PROTO_GEN_DIR}/service/navigation/v1/navigation.pb.cc
${PROTO_GEN_DIR}/service/slam/v1/slam.grpc.pb.cc
${PROTO_GEN_DIR}/service/slam/v1/slam.pb.cc
${PROTO_GEN_DIR}/service/vision/v1/vision.grpc.pb.cc
${PROTO_GEN_DIR}/service/vision/v1/vision.pb.cc
${PROTO_GEN_DIR}/tagger/v1/tagger.grpc.pb.cc
${PROTO_GEN_DIR}/tagger/v1/tagger.pb.cc
PUBLIC FILE_SET viamapi_includes TYPE HEADERS
Expand Down Expand Up @@ -454,6 +460,8 @@ target_sources(viamapi
${PROTO_GEN_DIR}/../../viam/api/service/navigation/v1/navigation.pb.h
${PROTO_GEN_DIR}/../../viam/api/service/slam/v1/slam.grpc.pb.h
${PROTO_GEN_DIR}/../../viam/api/service/slam/v1/slam.pb.h
${PROTO_GEN_DIR}/../../viam/api/service/vision/v1/vision.grpc.pb.h
${PROTO_GEN_DIR}/../../viam/api/service/vision/v1/vision.pb.h
${PROTO_GEN_DIR}/../../viam/api/tagger/v1/tagger.pb.h
)

Expand Down
6 changes: 6 additions & 0 deletions src/viam/sdk/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ target_sources(viamsdk
common/utils.cpp
common/version_metadata.cpp
common/world_state.cpp
common/private/raw_image.cpp
common/private/service_helper.cpp
tracing/private/span_guard.cpp
tracing/private/tracer.cpp
Expand Down Expand Up @@ -154,6 +155,7 @@ target_sources(viamsdk
services/mlmodel.cpp
services/motion.cpp
services/navigation.cpp
services/vision.cpp
services/private/discovery_client.cpp
services/private/discovery_server.cpp
services/private/generic_client.cpp
Expand All @@ -165,6 +167,9 @@ target_sources(viamsdk
services/private/motion_server.cpp
services/private/navigation_client.cpp
services/private/navigation_server.cpp
services/private/vision.cpp
services/private/vision_client.cpp
services/private/vision_server.cpp
services/service.cpp
spatialmath/geometry.cpp
spatialmath/orientation.cpp
Expand Down Expand Up @@ -234,6 +239,7 @@ target_sources(viamsdk
../../viam/sdk/services/mlmodel.hpp
../../viam/sdk/services/motion.hpp
../../viam/sdk/services/navigation.hpp
../../viam/sdk/services/vision.hpp
../../viam/sdk/services/service.hpp
../../viam/sdk/spatialmath/geometry.hpp
../../viam/sdk/spatialmath/orientation.hpp
Expand Down
28 changes: 28 additions & 0 deletions src/viam/sdk/common/private/raw_image.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <viam/sdk/common/private/raw_image.hpp>

#include <viam/sdk/common/utils.hpp>

namespace viam {
namespace sdk {
namespace impl {

Camera::raw_image from_proto(const ::viam::component::camera::v1::Image& proto) {
Camera::raw_image raw_image;
std::string img_string = proto.image();
const std::vector<unsigned char> bytes(img_string.begin(), img_string.end());
raw_image.bytes = bytes;
raw_image.mime_type = proto.mime_type();
raw_image.source_name = proto.source_name();
return raw_image;
}

void to_proto(const Camera::raw_image& image, ::viam::component::camera::v1::Image* out) {
const std::string img_string = bytes_to_string(image.bytes);
out->set_source_name(image.source_name);
out->set_mime_type(image.mime_type);
out->set_image(img_string);
}

} // namespace impl
} // namespace sdk
} // namespace viam
21 changes: 21 additions & 0 deletions src/viam/sdk/common/private/raw_image.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// @file common/private/raw_image.hpp
///
/// @brief Proto conversion helpers for Camera::raw_image and Image proto.
#pragma once

#include <viam/api/component/camera/v1/camera.pb.h>
#include <viam/sdk/components/camera.hpp>

namespace viam {
namespace sdk {
namespace impl {

/// @brief Convert a proto Image to Camera::raw_image.
Camera::raw_image from_proto(const ::viam::component::camera::v1::Image& proto);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think these conversions should probably be public in camera.hpp, see summary comment


/// @brief Convert a Camera::raw_image to proto Image.
void to_proto(const Camera::raw_image& image, ::viam::component::camera::v1::Image* out);

} // namespace impl
} // namespace sdk
} // namespace viam
9 changes: 2 additions & 7 deletions src/viam/sdk/components/private/camera_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <viam/api/component/camera/v1/camera.grpc.pb.h>

#include <viam/sdk/common/client_helper.hpp>
#include <viam/sdk/common/private/raw_image.hpp>
#include <viam/sdk/common/utils.hpp>
#include <viam/sdk/components/camera.hpp>
#include <viam/sdk/config/resource.hpp>
Expand All @@ -27,13 +28,7 @@ Camera::image_collection from_proto(const viam::component::camera::v1::GetImages
Camera::image_collection image_collection;
std::vector<Camera::raw_image> images;
for (const auto& img : proto.images()) {
Camera::raw_image raw_image;
std::string img_string = img.image();
const std::vector<unsigned char> bytes(img_string.begin(), img_string.end());
raw_image.bytes = bytes;
raw_image.mime_type = img.mime_type();
raw_image.source_name = img.source_name();
images.push_back(raw_image);
images.push_back(impl::from_proto(img));
}
image_collection.images = std::move(images);
image_collection.metadata = from_proto(proto.response_metadata());
Expand Down
18 changes: 7 additions & 11 deletions src/viam/sdk/components/private/camera_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <viam/api/app/v1/robot.pb.h>

#include <viam/sdk/common/private/raw_image.hpp>
#include <viam/sdk/common/private/service_helper.hpp>
#include <viam/sdk/common/utils.hpp>
#include <viam/sdk/components/camera.hpp>
Expand Down Expand Up @@ -55,8 +56,8 @@ ::grpc::Status CameraServer::DoCommand(::grpc::ServerContext* context,
::viam::common::v1::DoCommandResponse* response) noexcept {
return make_service_helper<Camera>(
"CameraServer::DoCommand", this, context, request)([&](auto&, auto& camera) {
const ProtoStruct result = camera->do_command(from_proto(request->command()));
*response->mutable_result() = to_proto(result);
const ProtoStruct result = camera->do_command(sdk::from_proto(request->command()));
*response->mutable_result() = sdk::to_proto(result);
});
}

Expand All @@ -70,14 +71,9 @@ ::grpc::Status CameraServer::GetImages(
{request->filter_source_names().begin(), request->filter_source_names().end()},
helper.getExtra());
for (const auto& img : image_coll.images) {
::viam::component::camera::v1::Image proto_image;
const std::string img_string = bytes_to_string(img.bytes);
proto_image.set_source_name(img.source_name);
proto_image.set_mime_type(img.mime_type);
proto_image.set_image(img_string);
*response->mutable_images()->Add() = std::move(proto_image);
impl::to_proto(img, response->mutable_images()->Add());
}
*response->mutable_response_metadata() = to_proto(image_coll.metadata);
*response->mutable_response_metadata() = sdk::to_proto(image_coll.metadata);
});
}

Expand All @@ -102,7 +98,7 @@ ::grpc::Status CameraServer::GetGeometries(
"CameraServer::GetGeometries", this, context, request)([&](auto& helper, auto& camera) {
const std::vector<GeometryConfig> geometries = camera->get_geometries(helper.getExtra());
for (const auto& geometry : geometries) {
*response->mutable_geometries()->Add() = to_proto(geometry);
*response->mutable_geometries()->Add() = sdk::to_proto(geometry);
}
});
}
Expand All @@ -129,7 +125,7 @@ ::grpc::Status CameraServer::GetStatus(::grpc::ServerContext* context,
return make_service_helper<Camera>(
"CameraServer::GetStatus", this, context, request)([&](auto&, auto& camera) {
const ProtoStruct result = camera->get_status();
*response->mutable_result() = to_proto(result);
*response->mutable_result() = sdk::to_proto(result);
});
}

Expand Down
3 changes: 3 additions & 0 deletions src/viam/sdk/registry/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
#include <viam/sdk/services/private/motion_server.hpp>
#include <viam/sdk/services/private/navigation_client.hpp>
#include <viam/sdk/services/private/navigation_server.hpp>
#include <viam/sdk/services/private/vision_client.hpp>
#include <viam/sdk/services/private/vision_server.hpp>
#include <viam/sdk/services/service.hpp>

namespace viam {
Expand Down Expand Up @@ -229,6 +231,7 @@ void Registry::register_resources() {
register_resource<impl::MLModelServiceClient, impl::MLModelServiceServer>();
register_resource<impl::MotionClient, impl::MotionServer>();
register_resource<impl::NavigationClient, impl::NavigationServer>();
register_resource<impl::VisionClient, impl::VisionServer>();
}

void Registry::initialize() {
Expand Down
130 changes: 130 additions & 0 deletions src/viam/sdk/services/private/vision.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Copyright 2024 Viam Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <viam/sdk/services/private/vision.hpp>

#include <viam/sdk/common/private/repeated_ptr_convert.hpp>
#include <viam/sdk/common/proto_convert.hpp>
#include <viam/sdk/spatialmath/geometry.hpp>

namespace viam {
namespace sdk {
namespace impl {
namespace vision {

namespace vpb = ::viam::service::vision::v1;

vpb::Detection to_proto(const Vision::detection& d) {
vpb::Detection out;
if (d.x_min) {
out.set_x_min(*d.x_min);
}
if (d.y_min) {
out.set_y_min(*d.y_min);
}
if (d.x_max) {
out.set_x_max(*d.x_max);
}
if (d.y_max) {
out.set_y_max(*d.y_max);
}
if (d.x_min_normalized) {
out.set_x_min_normalized(*d.x_min_normalized);
}
if (d.y_min_normalized) {
out.set_y_min_normalized(*d.y_min_normalized);
}
if (d.x_max_normalized) {
out.set_x_max_normalized(*d.x_max_normalized);
}
if (d.y_max_normalized) {
out.set_y_max_normalized(*d.y_max_normalized);
}
out.set_class_name(d.class_name);
out.set_confidence(d.confidence);
return out;
}

Vision::detection from_proto(const vpb::Detection& p) {
Vision::detection out;
if (p.has_x_min()) {
out.x_min = p.x_min();
}
if (p.has_y_min()) {
out.y_min = p.y_min();
}
if (p.has_x_max()) {
out.x_max = p.x_max();
}
if (p.has_y_max()) {
out.y_max = p.y_max();
}
if (p.has_x_min_normalized()) {
out.x_min_normalized = p.x_min_normalized();
}
if (p.has_y_min_normalized()) {
out.y_min_normalized = p.y_min_normalized();
}
if (p.has_x_max_normalized()) {
out.x_max_normalized = p.x_max_normalized();
}
if (p.has_y_max_normalized()) {
out.y_max_normalized = p.y_max_normalized();
}
out.class_name = p.class_name();
out.confidence = p.confidence();
return out;
}

vpb::Classification to_proto(const Vision::classification& c) {
vpb::Classification out;
out.set_class_name(c.class_name);
out.set_confidence(c.confidence);
return out;
}

Vision::classification from_proto(const vpb::Classification& p) {
return Vision::classification{p.class_name(), p.confidence()};
}

void to_proto(const Vision::point_cloud_object& o, ::viam::common::v1::PointCloudObject* out) {
out->set_point_cloud(
std::string(reinterpret_cast<const char*>(o.cloud.pc.data()), o.cloud.pc.size()));
*(out->mutable_geometries()->mutable_geometries()) = impl::to_repeated_field(o.geometries);
}

Vision::point_cloud_object from_proto(const ::viam::common::v1::PointCloudObject& p) {
Vision::point_cloud_object out;
const auto& bytes = p.point_cloud();
out.cloud.pc.assign(reinterpret_cast<const unsigned char*>(bytes.data()),
reinterpret_cast<const unsigned char*>(bytes.data()) + bytes.size());
out.geometries = impl::from_repeated_field(p.geometries().geometries());
return out;
}

void to_proto(const Vision::properties& props, vpb::GetPropertiesResponse* out) {
out->set_classifications_supported(props.classifications_supported);
out->set_detections_supported(props.detections_supported);
out->set_object_point_clouds_supported(props.object_point_clouds_supported);
}

Vision::properties from_proto(const vpb::GetPropertiesResponse& p) {
return Vision::properties{
p.classifications_supported(), p.detections_supported(), p.object_point_clouds_supported()};
}

} // namespace vision
} // namespace impl
} // namespace sdk
} // namespace viam
41 changes: 41 additions & 0 deletions src/viam/sdk/services/private/vision.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2024 Viam Inc.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

a separate file for these conversions isn't really in line with other patterns we use in the sdk, but see comments below regarding the actual conversion functions

//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <viam/api/common/v1/common.pb.h>
#include <viam/api/service/vision/v1/vision.pb.h>
#include <viam/sdk/services/vision.hpp>

namespace viam {
namespace sdk {
namespace impl {
namespace vision {

::viam::service::vision::v1::Detection to_proto(const Vision::detection&);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

similarly detection, classification, and point_cloud_object should be public i think

Vision::detection from_proto(const ::viam::service::vision::v1::Detection&);

::viam::service::vision::v1::Classification to_proto(const Vision::classification&);
Vision::classification from_proto(const ::viam::service::vision::v1::Classification&);

void to_proto(const Vision::point_cloud_object&, ::viam::common::v1::PointCloudObject* out);
Vision::point_cloud_object from_proto(const ::viam::common::v1::PointCloudObject&);

void to_proto(const Vision::properties&, ::viam::service::vision::v1::GetPropertiesResponse* out);
Vision::properties from_proto(const ::viam::service::vision::v1::GetPropertiesResponse&);

} // namespace vision
} // namespace impl
} // namespace sdk
} // namespace viam
Loading
Loading