Skip to content

Commit 1de6fce

Browse files
authored
[RSDK-6497] Vision Service (#236)
1 parent ea8f7cf commit 1de6fce

File tree

7 files changed

+433
-32
lines changed

7 files changed

+433
-32
lines changed

package-lock.json

+13-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main.ts

+7-19
Original file line numberDiff line numberDiff line change
@@ -379,29 +379,17 @@ export {
379379
*
380380
* Generated with https://github.com/improbable-eng/grpc-web
381381
*
382-
* @example
383-
*
384-
* ```ts
385-
* import { grpc } from '@improbable-eng/grpc-web';
386-
*
387-
* const client = {}; // replace with a connected robot client
388-
*
389-
* const request = new visionApi.GetDetectorNamesRequest();
390-
* request.setName('myvision');
391-
*
392-
* client.visionService.getDetectorNames(
393-
* request,
394-
* new grpc.Metadata(),
395-
* (error, response) => {
396-
* // do something with error or response
397-
* }
398-
* );
399-
* ```
400-
*
382+
* @deprecated Use {@link VisionClient} instead.
401383
* @alpha
402384
* @group Raw Protobufs
403385
*/
404386
export { default as visionApi } from './gen/service/vision/v1/vision_pb';
387+
export {
388+
type Detection,
389+
type Classification,
390+
type PointCloudObject,
391+
VisionClient,
392+
} from './services/vision';
405393

406394
/**
407395
* Raw Protobuf interfaces that are shared across multiple components and

src/services/vision.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export type { Vision } from './vision/vision';
2+
export type {
3+
Detection,
4+
Classification,
5+
PointCloudObject,
6+
} from './vision/types';
7+
export { VisionClient } from './vision/client';

src/services/vision/client.spec.ts

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
// @vitest-environment happy-dom
2+
3+
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
4+
import {
5+
Classification as PBClassification,
6+
Detection as PBDetection,
7+
} from '../../gen/service/vision/v1/vision_pb';
8+
import { PointCloudObject as PBPointCloudObject } from '../../gen/common/v1/common_pb';
9+
import { VisionServiceClient } from '../../gen/service/vision/v1/vision_pb_service';
10+
import { RobotClient } from '../../robot';
11+
import { VisionClient } from './client';
12+
import type { Classification, Detection, PointCloudObject } from './types';
13+
vi.mock('../../robot');
14+
vi.mock('../../gen/service/vision/v1/vision_pb_service');
15+
16+
const visionClientName = 'test-vision';
17+
18+
let vision: VisionClient;
19+
20+
describe('VisionClient Tests', () => {
21+
beforeEach(() => {
22+
RobotClient.prototype.createServiceClient = vi
23+
.fn()
24+
.mockImplementation(() => new VisionServiceClient(visionClientName));
25+
26+
vision = new VisionClient(new RobotClient('host'), visionClientName);
27+
});
28+
29+
describe('Detection Tests', () => {
30+
const testDetection: Detection = {
31+
xMin: 251,
32+
yMin: 225,
33+
xMax: 416,
34+
yMax: 451,
35+
confidence: 0.995_482_683_181_762_7,
36+
className: 'face',
37+
};
38+
let detection: Mock<[], PBDetection>;
39+
const encodeDetection = (det: Detection) => {
40+
const pbDetection = new PBDetection();
41+
pbDetection.setClassName(det.className);
42+
pbDetection.setConfidence(det.confidence);
43+
pbDetection.setXMin(det.xMin);
44+
pbDetection.setXMax(det.xMax);
45+
pbDetection.setYMin(det.yMin);
46+
pbDetection.setYMax(det.yMax);
47+
return pbDetection;
48+
};
49+
50+
beforeEach(() => {
51+
VisionServiceClient.prototype.getDetections = vi
52+
.fn()
53+
.mockImplementation((_req, _md, cb) => {
54+
cb(null, {
55+
getDetectionsList: () => [detection()],
56+
});
57+
});
58+
59+
VisionServiceClient.prototype.getDetectionsFromCamera = vi
60+
.fn()
61+
.mockImplementation((_req, _md, cb) => {
62+
cb(null, {
63+
getDetectionsList: () => [detection()],
64+
});
65+
});
66+
});
67+
68+
it('returns detections from a camera', async () => {
69+
detection = vi.fn(() => encodeDetection(testDetection));
70+
71+
const expected = [testDetection];
72+
73+
await expect(
74+
vision.getDetectionsFromCamera('camera')
75+
).resolves.toStrictEqual(expected);
76+
});
77+
78+
it('returns detections from an image', async () => {
79+
detection = vi.fn(() => encodeDetection(testDetection));
80+
81+
const expected = [testDetection];
82+
83+
await expect(
84+
vision.getDetections(new Uint8Array(), 1, 1, 'image/jpeg')
85+
).resolves.toStrictEqual(expected);
86+
});
87+
});
88+
89+
describe('Classification Tests', () => {
90+
const testClassification: Classification = {
91+
className: 'face',
92+
confidence: 0.995_482_683_181_762_7,
93+
};
94+
let classification: Mock<[], PBClassification>;
95+
const encodeClassification = (cls: Classification) => {
96+
const pbClassification = new PBClassification();
97+
pbClassification.setClassName(cls.className);
98+
pbClassification.setConfidence(cls.confidence);
99+
return pbClassification;
100+
};
101+
102+
beforeEach(() => {
103+
VisionServiceClient.prototype.getClassifications = vi
104+
.fn()
105+
.mockImplementation((_req, _md, cb) => {
106+
cb(null, {
107+
getClassificationsList: () => [classification()],
108+
});
109+
});
110+
111+
VisionServiceClient.prototype.getClassificationsFromCamera = vi
112+
.fn()
113+
.mockImplementation((_req, _md, cb) => {
114+
cb(null, {
115+
getClassificationsList: () => [classification()],
116+
});
117+
});
118+
});
119+
120+
it('returns classifications from a camera', async () => {
121+
classification = vi.fn(() => encodeClassification(testClassification));
122+
123+
const expected = [testClassification];
124+
125+
await expect(
126+
vision.getClassificationsFromCamera('camera', 1)
127+
).resolves.toStrictEqual(expected);
128+
});
129+
130+
it('returns classifications from an image', async () => {
131+
classification = vi.fn(() => encodeClassification(testClassification));
132+
133+
const expected = [testClassification];
134+
135+
await expect(
136+
vision.getClassifications(new Uint8Array(), 1, 1, 'image/jpeg', 1)
137+
).resolves.toStrictEqual(expected);
138+
});
139+
});
140+
141+
describe('Object Point Cloud Tests', () => {
142+
const testPCO: PointCloudObject = {
143+
pointCloud: 'This is a PointCloudObject',
144+
geometries: undefined,
145+
};
146+
let pointCloudObject: Mock<[], PBPointCloudObject>;
147+
const encodePCO = (pco: PointCloudObject) => {
148+
const pbPCO = new PBPointCloudObject();
149+
pbPCO.setPointCloud(pco.pointCloud);
150+
return pbPCO;
151+
};
152+
153+
beforeEach(() => {
154+
VisionServiceClient.prototype.getObjectPointClouds = vi
155+
.fn()
156+
.mockImplementation((_req, _md, cb) => {
157+
cb(null, {
158+
getObjectsList: () => [pointCloudObject()],
159+
});
160+
});
161+
});
162+
163+
it('returns a PointCloudObject from a camera', async () => {
164+
pointCloudObject = vi.fn(() => encodePCO(testPCO));
165+
166+
const expected = [testPCO];
167+
168+
await expect(
169+
vision.getObjectPointClouds('camera')
170+
).resolves.toStrictEqual(expected);
171+
});
172+
});
173+
});

0 commit comments

Comments
 (0)