Skip to content

Commit f2fcf92

Browse files
committed
fix(tracking): don't translate width/height
Camera resolution does not match the dimensions of the rendered component. So when a QR code is detected we need to adjust it's coordinates before it's passed to the track function. For that xy-coordinates need to be scaled to account for responsiveness and they need to be translated to account for cropping (especially in fullscreen mode). However, widths/heights don't need to be translated since they only have magnitude but no position. That error caused tracking to messed up in fullscreen mode for tracking functions that use width/height in the boundingBox property. Issue: #244
1 parent 094fd2f commit f2fcf92

File tree

1 file changed

+41
-34
lines changed

1 file changed

+41
-34
lines changed

src/components/QrcodeStream.vue

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -200,55 +200,62 @@ export default {
200200
201201
if (canvas !== undefined) {
202202
if (detectedCodes.length > 0 && this.track !== undefined && video !== undefined) {
203+
// The visually occupied area of the video element.
204+
// Because the component is responsive and fills the available space,
205+
// this can be more or less than the actual resolution of the camera.
206+
const displayWidth = video.offsetWidth;
207+
const displayHeight = video.offsetHeight;
208+
209+
// The actual resolution of the camera.
210+
// These values are fixed no matter the screen size.
211+
const resolutionWidth = video.videoWidth;
212+
const resolutionHeight = video.videoHeight;
213+
214+
// Dimensions of the video element as if there would be no
215+
// object-fit: cover;
216+
// Thus, the ratio is the same as the cameras resolution but it's
217+
// scaled down to the size of the visually occupied area.
218+
const largerRatio = Math.max(
219+
displayWidth / resolutionWidth,
220+
displayHeight / resolutionHeight
221+
);
222+
const uncutWidth = resolutionWidth * largerRatio;
223+
const uncutHeight = resolutionHeight * largerRatio;
224+
225+
const xScalar = uncutWidth / resolutionWidth;
226+
const yScalar = uncutHeight / resolutionHeight;
227+
const xOffset = (displayWidth - uncutWidth) / 2;
228+
const yOffset = (displayHeight - uncutHeight) / 2;
229+
230+
const scale = ({ x, y }) => {
231+
return {
232+
x: Math.floor(x * xScalar),
233+
y: Math.floor(y * yScalar)
234+
};
235+
}
203236
204-
const adjustPoint = ({ x, y }) => {
205-
// The visually occupied area of the video element.
206-
// Because the component is responsive and fills the available space,
207-
// this can be more or less than the actual resolution of the camera.
208-
const displayWidth = video.offsetWidth;
209-
const displayHeight = video.offsetHeight;
210-
211-
// The actual resolution of the camera.
212-
// These values are fixed no matter the screen size.
213-
const resolutionWidth = video.videoWidth;
214-
const resolutionHeight = video.videoHeight;
215-
216-
// Dimensions of the video element as if there would be no
217-
// object-fit: cover;
218-
// Thus, the ratio is the same as the cameras resolution but it's
219-
// scaled down to the size of the visually occupied area.
220-
const largerRatio = Math.max(
221-
displayWidth / resolutionWidth,
222-
displayHeight / resolutionHeight
223-
);
224-
const uncutWidth = resolutionWidth * largerRatio;
225-
const uncutHeight = resolutionHeight * largerRatio;
226-
227-
const xScalar = uncutWidth / resolutionWidth;
228-
const yScalar = uncutHeight / resolutionHeight;
229-
const xOffset = (displayWidth - uncutWidth) / 2;
230-
const yOffset = (displayHeight - uncutHeight) / 2;
231-
237+
const translate = ({ x, y }) => {
232238
return {
233-
x: Math.floor(x * xScalar + xOffset),
234-
y: Math.floor(y * yScalar + yOffset)
239+
x: Math.floor(x + xOffset),
240+
y: Math.floor(y + yOffset)
235241
};
236242
}
237243
238244
const adjustedCodes = detectedCodes.map(detectedCode => {
239245
const { boundingBox, cornerPoints } = detectedCode
240-
const { x, y } = adjustPoint({
246+
247+
const { x, y } = translate(scale({
241248
x: boundingBox.x,
242249
y: boundingBox.y
243-
})
244-
const { x: width, y: height } = adjustPoint({
250+
}))
251+
const { x: width, y: height } = scale({
245252
x: boundingBox.width,
246253
y: boundingBox.height
247254
})
248255
249256
return {
250257
...detectedCode,
251-
cornerPoints: cornerPoints.map(adjustPoint),
258+
cornerPoints: cornerPoints.map(point => translate(scale(point))),
252259
boundingBox: DOMRectReadOnly.fromRect({ x, y, width, height })
253260
}
254261
})

0 commit comments

Comments
 (0)