- StereoRectifier wrapping cv::stereoRectify + cv::initUndistortRectifyMap (CV_16SC2 maps) - PointCloudBuilder with cv::reprojectImageTo3D and depth/NaN filtering - CloudPointClient high-level facade: connect(), compute_cloud() -> std::expected<PointCloud, Error> - write_ply() ASCII PLY export helper - CLI options 4 (compute-cloud) and 5 (compute-cloud + save PLY) - Fix TcpServer to loop over multiple requests per connection - Expose num_disparities parameter through CloudPointClient and StereoMatcherFactory - Unity C# integration design spec - Sync README, AGENTS, openwiki with stereo pipeline (C++23) - E2E synthetic-scene test with constant-disparity stereo pair TG-9 #ready-for-test TG-4 #ready-for-test TG-2 #in-progress
6.8 KiB
RPC Protocol
JSON-RPC 2.0
The server implements JSON-RPC 2.0 over TCP with length-prefixed framing (see Architecture → Wire framing).
Batch requests are not supported — only single request objects are processed.
Request format
{
"jsonrpc": "2.0",
"method": "<method_name>",
"params": {},
"id": <integer|string>
}
The params field is accepted but currently ignored by all implemented methods. The id field is required; requests without it receive a -32600 Invalid Request error.
Success response
{
"jsonrpc": "2.0",
"result": <method_specific_result>,
"id": <matching_request_id>
}
Error response
{
"jsonrpc": "2.0",
"error": {
"code": <integer>,
"message": "<string>"
},
"id": <matching_request_id>
}
Error codes
| Code | Meaning | When |
|---|---|---|
-32700 |
Parse error | Request is not valid JSON |
-32600 |
Invalid Request | Missing jsonrpc, method, or id fields, or jsonrpc != "2.0" |
-32601 |
Method not found | No handler registered for the requested method name |
-32000 |
Server error | Handler threw an exception |
Known issue: Non-object JSON (arrays, strings, numbers, null) causes a
nlohmann::json::type_errorinstead of a clean-32600response. Seetests/test_rpc_edge_cases.cpp.
Source: src/rpc_server.cpp — RpcServer::process() and create_error().
Methods
get-stereo-calibration
Returns full stereo rig calibration: intrinsics for both cameras, stereo rotation and translation, and sensor resolution. Called once by CloudPointClient::connect().
Request:
{"jsonrpc": "2.0", "method": "get-stereo-calibration", "id": 1}
Response:
{
"left": { "camera_matrix": [9 doubles], "dist_coeffs": [5 doubles] },
"right": { "camera_matrix": [9 doubles], "dist_coeffs": [5 doubles] },
"rotation": [9 doubles],
"translation": [3 doubles],
"image_size": { "width": 640, "height": 480 }
}
All matrices are row-major. camera_matrix is the 3×3 intrinsic matrix; rotation is the 3×3 left-to-right rotation (OpenCV convention); translation is in metres. Calibration arrays are plain JSON doubles — not Base64.
Test mock defaults: fx=fy=800, cx=320, cy=240, zero distortion, R=I, T=[-0.06, 0, 0], 640×480.
get-image-pair
Returns a synchronised stereo frame as two base64-encoded images. Called on each CloudPointClient::compute_cloud().
Request:
{"jsonrpc": "2.0", "method": "get-image-pair", "id": 2}
Response:
{
"frame": 42,
"left": { "width": 640, "height": 480, "type": "BGR", "data": "<base64>" },
"right": { "width": 640, "height": 480, "type": "BGR", "data": "<base64>" }
}
data is Base64-encoded raw pixel bytes (standard alphabet, no line breaks). type is "BGR" (3 ch), "RGBA" (4 ch), or "DEPTH" (1 ch float32). Unity must flip GPU readback vertically before encoding (wire format is top-left-origin row-major).
DTOs: StereoCalibrationDto and ImagePairDto in include/cloud_point_rpc/rpc_dto.hpp. Decoded client-side via Base64RPCCoder.
get-intrinsic-params (legacy)
Retrieves left-camera intrinsic parameters as a flat 3×3 matrix (row-major, 9 doubles). Not used by CloudPointClient; kept for backward compatibility.
Request:
{"jsonrpc": "2.0", "method": "get-intrinsic-params", "id": 3}
Response:
{"jsonrpc": "2.0", "result": [fx, 0, cx, 0, fy, cy, 0, 0, 1], "id": 3}
Result: 9 plain JSON doubles. Not Base64.
get-extrinsic-params (legacy)
Retrieves left-camera extrinsic matrix as a flat 4×4 matrix (row-major, 16 doubles). Not used by CloudPointClient; kept for backward compatibility.
Request:
{"jsonrpc": "2.0", "method": "get-extrinsic-params", "id": 4}
Response:
{"jsonrpc": "2.0", "result": [16 doubles], "id": 4}
Result: 16 plain JSON doubles. Not Base64.
get-cloud-point
Retrieves the current field-of-view point cloud.
Request:
{"jsonrpc": "2.0", "method": "get-cloud-point", "id": 3}
Response:
{"jsonrpc": "2.0", "result": {"width": int, "height": int, "data": <base64-encoded-array>}, "id": 3}
Result type: matrix WxH (list of [x, y, z] points), Base64-encoded.
Note
: The standalone mock server (
server_main.cpp) returns these as raw JSON arrays (not Base64-encoded) viaService. The Base64 encoding is expected to be implemented on the Unity side perAPI.md.
Handler registration
Handlers are registered with RpcServer::register_method(). Two forms exist:
C++ handler
rpc_server.register_method("get-intrinsic-params", [&](const json& params) {
return service.get_intrinsic_params(); // returns vector<double>
});
The handler returns std::variant<nlohmann::json, std::string>. If a json is returned, it is placed directly in the result field. If a std::string is returned, it is placed as-is.
C callback handler
rpc_string* my_callback(rpc_string* params_json) {
// params_json->s contains the JSON params as a string
// return a result string (JSON or raw)
return crpc_str_create("result_data", 11);
}
rpc_server.register_method("my-method", my_callback);
The C callback receives the JSON params as a string in rpc_string->s. The return value's string is parsed as JSON if possible; otherwise it is used as a raw string in the result field.
Source: src/rpc_server.cpp — register_method(name, callback_t) overload.
Base64 encoding
include/cloud_point_rpc/rpc_coder.hpp, src/rpc_coder.cpp
Base64RPCCoderimplements theIRPCCoderinterface withencode()anddecode()methods.- Uses the aklomp/base64 library (Meson wrap
subprojects/aklomp-base64.wrap). encode(vector<char>) → stringanddecode(string) → vector<char>.- Includes overflow protection: throws
std::length_errorif input exceeds safe size limits.
Per
API.md: only image pixel data (get-image-pairdatafields) uses Base64. Calibration arrays (camera_matrix,dist_coeffs,rotation,translation) and legacy params are plain JSON doubles — never Base64. Unity encodes images before sending; the C++ client decodes them viaBase64RPCCoder.
Client-side usage
include/cloud_point_rpc/rpc_client.hpp
RpcClient wraps jsonrpccxx::JsonRpcClient and provides typed access:
score::TCPConnector connector(ip, port);
score::RpcClient client(connector);
auto intrinsic = client.get_intrinsic_params(); // vector<double>
auto extrinsic = client.get_extrinsic_params(); // vector<double>
auto cloud = client.get_cloud_point(); // vector<vector<double>>
The interactive CLI (src/cli.cpp) and minimal_client (src/minimal_client.cpp) demonstrate client usage.