Skip to content

Commit 9a286e8

Browse files
RSDK-7470: Add GetProperties and CaptureAllFromCamera (#312)
1 parent 63029c3 commit 9a286e8

File tree

4 files changed

+247
-106
lines changed

4 files changed

+247
-106
lines changed

src/services/vision/client.spec.ts

+129-105
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @vitest-environment happy-dom
22

3-
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
3+
import { beforeEach, describe, expect, it, vi } from 'vitest';
44
import {
55
Classification as PBClassification,
66
Detection as PBDetection,
@@ -17,68 +17,121 @@ const visionClientName = 'test-vision';
1717

1818
let vision: VisionClient;
1919

20+
const classification: Classification = {
21+
className: 'face',
22+
confidence: 0.995_482_683_181_762_7,
23+
};
24+
const pbClassification = (() => {
25+
const pb = new PBClassification();
26+
pb.setClassName(classification.className);
27+
pb.setConfidence(classification.confidence);
28+
return pb;
29+
})();
30+
31+
const detection: Detection = {
32+
xMin: 251,
33+
yMin: 225,
34+
xMax: 416,
35+
yMax: 451,
36+
confidence: 0.995_482_683_181_762_7,
37+
className: 'face',
38+
};
39+
const pbDetection = (() => {
40+
const pb = new PBDetection();
41+
pb.setClassName(detection.className);
42+
pb.setConfidence(detection.confidence);
43+
pb.setXMin(detection.xMin);
44+
pb.setXMax(detection.xMax);
45+
pb.setYMin(detection.yMin);
46+
pb.setYMax(detection.yMax);
47+
return pb;
48+
})();
49+
50+
const pco: PointCloudObject = {
51+
pointCloud: 'This is a PointCloudObject',
52+
geometries: undefined,
53+
};
54+
const pbPCO = (() => {
55+
const pb = new PBPointCloudObject();
56+
pb.setPointCloud(pco.pointCloud);
57+
return pb;
58+
})();
59+
2060
describe('VisionClient Tests', () => {
2161
beforeEach(() => {
2262
RobotClient.prototype.createServiceClient = vi
2363
.fn()
2464
.mockImplementation(() => new VisionServiceClient(visionClientName));
2565

66+
VisionServiceClient.prototype.getDetections = vi
67+
.fn()
68+
.mockImplementation((_req, _md, cb) => {
69+
cb(null, {
70+
getDetectionsList: () => [pbDetection],
71+
});
72+
});
73+
VisionServiceClient.prototype.getDetectionsFromCamera = vi
74+
.fn()
75+
.mockImplementation((_req, _md, cb) => {
76+
cb(null, {
77+
getDetectionsList: () => [pbDetection],
78+
});
79+
});
80+
VisionServiceClient.prototype.getClassifications = vi
81+
.fn()
82+
.mockImplementation((_req, _md, cb) => {
83+
cb(null, {
84+
getClassificationsList: () => [pbClassification],
85+
});
86+
});
87+
VisionServiceClient.prototype.getClassificationsFromCamera = vi
88+
.fn()
89+
.mockImplementation((_req, _md, cb) => {
90+
cb(null, {
91+
getClassificationsList: () => [pbClassification],
92+
});
93+
});
94+
VisionServiceClient.prototype.getObjectPointClouds = vi
95+
.fn()
96+
.mockImplementation((_req, _md, cb) => {
97+
cb(null, {
98+
getObjectsList: () => [pbPCO],
99+
});
100+
});
101+
VisionServiceClient.prototype.getProperties = vi
102+
.fn()
103+
.mockImplementation((_req, _md, cb) => {
104+
cb(null, {
105+
getClassificationsSupported: () => true,
106+
getDetectionsSupported: () => true,
107+
getObjectPointCloudsSupported: () => true,
108+
});
109+
});
110+
VisionServiceClient.prototype.captureAllFromCamera = vi
111+
.fn()
112+
.mockImplementation((_req, _md, cb) => {
113+
cb(null, {
114+
getImage: () => undefined,
115+
getClassificationsList: () => [pbClassification],
116+
getDetectionsList: () => [pbDetection],
117+
getObjectsList: () => [pbPCO],
118+
});
119+
});
120+
26121
vision = new VisionClient(new RobotClient('host'), visionClientName);
27122
});
28123

29124
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-
68125
it('returns detections from a camera', async () => {
69-
detection = vi.fn(() => encodeDetection(testDetection));
70-
71-
const expected = [testDetection];
126+
const expected = [detection];
72127

73128
await expect(
74129
vision.getDetectionsFromCamera('camera')
75130
).resolves.toStrictEqual(expected);
76131
});
77132

78133
it('returns detections from an image', async () => {
79-
detection = vi.fn(() => encodeDetection(testDetection));
80-
81-
const expected = [testDetection];
134+
const expected = [detection];
82135

83136
await expect(
84137
vision.getDetections(new Uint8Array(), 1, 1, 'image/jpeg')
@@ -87,50 +140,16 @@ describe('VisionClient Tests', () => {
87140
});
88141

89142
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-
120143
it('returns classifications from a camera', async () => {
121-
classification = vi.fn(() => encodeClassification(testClassification));
122-
123-
const expected = [testClassification];
144+
const expected = [classification];
124145

125146
await expect(
126147
vision.getClassificationsFromCamera('camera', 1)
127148
).resolves.toStrictEqual(expected);
128149
});
129150

130151
it('returns classifications from an image', async () => {
131-
classification = vi.fn(() => encodeClassification(testClassification));
132-
133-
const expected = [testClassification];
152+
const expected = [classification];
134153

135154
await expect(
136155
vision.getClassifications(new Uint8Array(), 1, 1, 'image/jpeg', 1)
@@ -139,35 +158,40 @@ describe('VisionClient Tests', () => {
139158
});
140159

141160
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-
163161
it('returns a PointCloudObject from a camera', async () => {
164-
pointCloudObject = vi.fn(() => encodePCO(testPCO));
165-
166-
const expected = [testPCO];
162+
const expected = [pco];
167163

168164
await expect(
169165
vision.getObjectPointClouds('camera')
170166
).resolves.toStrictEqual(expected);
171167
});
172168
});
169+
170+
describe('Properties', () => {
171+
it('returns properties', async () => {
172+
await expect(vision.getProperties()).resolves.toStrictEqual({
173+
classificationsSupported: true,
174+
detectionsSupported: true,
175+
objectPointCloudsSupported: true,
176+
});
177+
});
178+
});
179+
180+
describe('Capture All', () => {
181+
it('returns captured values', async () => {
182+
await expect(
183+
vision.captureAllFromCamera('camera', {
184+
returnImage: true,
185+
returnClassifications: true,
186+
returnDetections: true,
187+
returnObjectPointClouds: true,
188+
})
189+
).resolves.toStrictEqual({
190+
image: undefined,
191+
classifications: [classification],
192+
detections: [detection],
193+
objectPointClouds: [pco],
194+
});
195+
});
196+
});
173197
});

src/services/vision/client.ts

+61
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { Struct } from 'google-protobuf/google/protobuf/struct_pb';
22
import pb from '../../gen/service/vision/v1/vision_pb';
33
import { VisionServiceClient } from '../../gen/service/vision/v1/vision_pb_service';
4+
import commonPB from '../../gen/common/v1/common_pb';
45
import type { MimeType } from '../../main';
56
import type { RobotClient } from '../../robot';
67
import type { Options, StructType } from '../../types';
78
import { doCommandFromClient, promisify } from '../../utils';
89
import type { Vision } from './vision';
10+
import type { CaptureAllOptions } from './types';
911

1012
/**
1113
* A gRPC-web client for a Vision service.
@@ -142,6 +144,65 @@ export class VisionClient implements Vision {
142144
return response.getObjectsList().map((x) => x.toObject());
143145
}
144146

147+
async getProperties(extra = {}) {
148+
const { service } = this;
149+
const request = new pb.GetPropertiesRequest();
150+
request.setName(this.name);
151+
request.setExtra(Struct.fromJavaScript(extra));
152+
153+
this.options.requestLogger?.(request);
154+
155+
const response = await promisify<
156+
pb.GetPropertiesRequest,
157+
pb.GetPropertiesResponse
158+
>(service.getProperties.bind(service), request);
159+
return {
160+
classificationsSupported: response.getClassificationsSupported(),
161+
detectionsSupported: response.getDetectionsSupported(),
162+
objectPointCloudsSupported: response.getObjectPointCloudsSupported(),
163+
};
164+
}
165+
166+
async captureAllFromCamera(
167+
cameraName: string,
168+
{
169+
returnImage,
170+
returnClassifications,
171+
returnDetections,
172+
returnObjectPointClouds,
173+
}: CaptureAllOptions,
174+
extra = {}
175+
) {
176+
const { service } = this;
177+
const request = new pb.CaptureAllFromCameraRequest();
178+
request.setName(this.name);
179+
request.setCameraName(cameraName);
180+
request.setReturnImage(returnImage);
181+
request.setReturnClassifications(returnClassifications);
182+
request.setReturnDetections(returnDetections);
183+
request.setReturnObjectPointClouds(returnObjectPointClouds);
184+
request.setExtra(Struct.fromJavaScript(extra));
185+
186+
this.options.requestLogger?.(request);
187+
188+
const response = await promisify<
189+
pb.CaptureAllFromCameraRequest,
190+
pb.CaptureAllFromCameraResponse
191+
>(service.captureAllFromCamera.bind(service), request);
192+
return {
193+
image: response.getImage()?.toObject(),
194+
classifications: response
195+
.getClassificationsList()
196+
.map((classification: pb.Classification) => classification.toObject()),
197+
detections: response
198+
.getDetectionsList()
199+
.map((detection: pb.Detection) => detection.toObject()),
200+
objectPointClouds: response
201+
.getObjectsList()
202+
.map((pbObject: commonPB.PointCloudObject) => pbObject.toObject()),
203+
};
204+
}
205+
145206
async doCommand(command: StructType): Promise<StructType> {
146207
const { service } = this;
147208
return doCommandFromClient(service, this.name, command, this.options);

0 commit comments

Comments
 (0)