blob: e2ba0b92ae16b376ec5e8b644aa241b9b793ac40 [file] [log] [blame]
Alex Perryd5e13572020-02-22 15:15:08 -08001import {CameraImage} from 'y2020/vision/vision_generated';
Austin Schuhf6e71392020-02-26 23:10:15 -08002import {ImageMatchResult} from 'y2020/vision/sift/sift_generated'
Alex Perry5f474f22020-02-01 12:14:24 -08003
4export class ImageHandler {
5 private canvas = document.createElement('canvas');
Alex Perryb41d5782020-02-09 17:06:40 -08006 private imageBuffer: Uint8ClampedArray|null = null;
Alex Perry3dfcb812020-03-04 19:32:17 -08007 private image: CameraImage|null = null;
Alex Perryb41d5782020-02-09 17:06:40 -08008 private imageTimestamp: flatbuffers.Long|null = null;
Austin Schuhf6e71392020-02-26 23:10:15 -08009 private result: ImageMatchResult|null = null;
Alex Perryb41d5782020-02-09 17:06:40 -080010 private resultTimestamp: flatbuffers.Long|null = null;
Alex Perry22824d72020-02-29 17:11:43 -080011 private width = 0;
12 private height = 0;
13 private imageSkipCount = 3;
Alex Perry5f474f22020-02-01 12:14:24 -080014
15 constructor() {
16 document.body.appendChild(this.canvas);
17 }
18
Alex Perryb41d5782020-02-09 17:06:40 -080019 handleImage(data: Uint8Array): void {
Alex Perry3dfcb812020-03-04 19:32:17 -080020 console.log('got an image to process');
Alex Perry22824d72020-02-29 17:11:43 -080021 if (this.imageSkipCount != 0) {
22 this.imageSkipCount--;
23 return;
24 } else {
25 this.imageSkipCount = 3;
26 }
27
Alex Perry5f474f22020-02-01 12:14:24 -080028 const fbBuffer = new flatbuffers.ByteBuffer(data);
Alex Perry3dfcb812020-03-04 19:32:17 -080029 this.image = CameraImage.getRootAsCameraImage(fbBuffer);
30 this.imageTimestamp = this.image.monotonicTimestampNs();
Alex Perry5f474f22020-02-01 12:14:24 -080031
Alex Perry3dfcb812020-03-04 19:32:17 -080032 this.width = this.image.cols();
33 this.height = this.image.rows();
Alex Perry22824d72020-02-29 17:11:43 -080034 if (this.width === 0 || this.height === 0) {
Alex Perry5f474f22020-02-01 12:14:24 -080035 return;
36 }
Alex Perry5f474f22020-02-01 12:14:24 -080037
Alex Perry3dfcb812020-03-04 19:32:17 -080038 this.draw();
39 }
40
41 convertImage(): void {
42 this.imageBuffer = new Uint8ClampedArray(this.width * this.height * 4); // RGBA
Alex Perry5f474f22020-02-01 12:14:24 -080043 // Read four bytes (YUYV) from the data and transform into two pixels of
44 // RGBA for canvas
Alex Perry22824d72020-02-29 17:11:43 -080045 for (const j = 0; j < this.height; j++) {
46 for (const i = 0; i < this.width; i += 2) {
Alex Perry3dfcb812020-03-04 19:32:17 -080047 const y1 = this.image.data((j * this.width + i) * 2);
48 const u = this.image.data((j * this.width + i) * 2 + 1);
49 const y2 = this.image.data((j * this.width + i + 1) * 2);
50 const v = this.image.data((j * this.width + i + 1) * 2 + 1);
Alex Perry5f474f22020-02-01 12:14:24 -080051
52 // Based on https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB
53 const c1 = y1 - 16;
54 const c2 = y2 - 16;
55 const d = u - 128;
56 const e = v - 128;
57
Alex Perry22824d72020-02-29 17:11:43 -080058 this.imageBuffer[(j * this.width + i) * 4 + 0] = (298 * c1 + 409 * e + 128) >> 8;
59 this.imageBuffer[(j * this.width + i) * 4 + 1] = (298 * c1 - 100 * d - 208 * e + 128) >> 8;
60 this.imageBuffer[(j * this.width + i) * 4 + 2] = (298 * c1 + 516 * d + 128) >> 8;
61 this.imageBuffer[(j * this.width + i) * 4 + 3] = 255;
62 this.imageBuffer[(j * this.width + i) * 4 + 4] = (298 * c2 + 409 * e + 128) >> 8;
63 this.imageBuffer[(j * this.width + i) * 4 + 5] = (298 * c2 - 100 * d - 208 * e + 128) >> 8;
64 this.imageBuffer[(j * this.width + i) * 4 + 6] = (298 * c2 + 516 * d + 128) >> 8;
65 this.imageBuffer[(j * this.width + i) * 4 + 7] = 255;
Alex Perry5f474f22020-02-01 12:14:24 -080066 }
67 }
Alex Perryb41d5782020-02-09 17:06:40 -080068 }
69
70 handleImageMetadata(data: Uint8Array): void {
Alex Perry3dfcb812020-03-04 19:32:17 -080071 console.log('got an image match result to process');
Alex Perryb41d5782020-02-09 17:06:40 -080072 const fbBuffer = new flatbuffers.ByteBuffer(data);
Austin Schuhf6e71392020-02-26 23:10:15 -080073 this.result = ImageMatchResult.getRootAsImageMatchResult(fbBuffer);
Alex Perry22824d72020-02-29 17:11:43 -080074 this.resultTimestamp = this.result.imageMonotonicTimestampNs();
75 this.draw();
Alex Perryb41d5782020-02-09 17:06:40 -080076 }
77
78 draw(): void {
Alex Perry22824d72020-02-29 17:11:43 -080079 if (!this.imageTimestamp || !this.resultTimestamp ||
80 this.imageTimestamp.low !== this.resultTimestamp.low ||
81 this.imageTimestamp.high !== this.resultTimestamp.high) {
Alex Perry3dfcb812020-03-04 19:32:17 -080082 console.log('image and result do not match');
83 console.log(this.imageTimestamp.low, this.resultTimestamp.low);
84 console.log(this.imageTimestamp.high, this.resultTimestamp.high);
Alex Perryb41d5782020-02-09 17:06:40 -080085 return;
86 }
Alex Perry3dfcb812020-03-04 19:32:17 -080087 this.convertImage();
Alex Perry5f474f22020-02-01 12:14:24 -080088 const ctx = this.canvas.getContext('2d');
89
Alex Perry22824d72020-02-29 17:11:43 -080090 this.canvas.width = this.width;
91 this.canvas.height = this.height;
92 const idata = ctx.createImageData(this.width, this.height);
Alex Perryb41d5782020-02-09 17:06:40 -080093 idata.data.set(this.imageBuffer);
Alex Perry5f474f22020-02-01 12:14:24 -080094 ctx.putImageData(idata, 0, 0);
Alex Perry22824d72020-02-29 17:11:43 -080095 for (const i = 0; i < this.result.featuresLength(); i++) {
96 const feature = this.result.features(i);
Alex Perryb41d5782020-02-09 17:06:40 -080097 // Based on OpenCV drawKeypoint.
Alex Perry22824d72020-02-29 17:11:43 -080098 ctx.beginPath();
99 ctx.arc(feature.x(), feature.y(), feature.size(), 0, 2 * Math.PI);
100 ctx.stroke();
101
102 ctx.beginPath();
103 ctx.moveTo(feature.x(), feature.y());
104 const angle = feature.angle() * Math.PI / 180;
Alex Perryb41d5782020-02-09 17:06:40 -0800105 ctx.lineTo(
Alex Perry22824d72020-02-29 17:11:43 -0800106 feature.x() + feature.size() * Math.cos(angle),
107 feature.y() + feature.size() * Math.sin(angle));
108 ctx.stroke();
Alex Perryb41d5782020-02-09 17:06:40 -0800109 }
Alex Perry5f474f22020-02-01 12:14:24 -0800110 }
111
Alex Perryb41d5782020-02-09 17:06:40 -0800112 getId(): string {
Alex Perryd5e13572020-02-22 15:15:08 -0800113 return CameraImage.getFullyQualifiedName();
Alex Perry5f474f22020-02-01 12:14:24 -0800114 }
Alex Perryb41d5782020-02-09 17:06:40 -0800115
116 getResultId(): string {
Austin Schuhf6e71392020-02-26 23:10:15 -0800117 return ImageMatchResult.getFullyQualifiedName();
Alex Perryb41d5782020-02-09 17:06:40 -0800118 }
Alex Perry5f474f22020-02-01 12:14:24 -0800119}