Skip to content

Instantly share code, notes, and snippets.

@Samsy
Last active January 11, 2016 14:45
Show Gist options
  • Save Samsy/8fe8a385eb696f238491 to your computer and use it in GitHub Desktop.
Save Samsy/8fe8a385eb696f238491 to your computer and use it in GitHub Desktop.
DepthDecoder Streetview
const base64 = require('base-64');
const zpipe = require("zpipe");
const jsonpClient = require('jsonp-client')
export default class DepthDecoder {
constructor(panoID) {
this.getDepth(panoID)
}
getDepth(panoID) {
let url = "http://maps.google.com/cbk?output=json&cb_client=maps_sv&v=4&dm=1&pm=1&ph=1&hl=en&panoid=" + panoID;
jsonpClient(this.addCallback(url), (err, data) => {
if (err) {
console.log(err)
return;
} else {
this.decodeDepth(data)
}
});
}
decodeDepth(data) {
let decoded = this.decode(data.model.depth_map);
this.depthMap = this.parse(decoded);
let canvas = document.createElement("canvas");
let context = canvas.getContext('2d');
let w = this.depthMap.width;
let h = this.depthMap.height;
canvas.setAttribute('width', w);
canvas.setAttribute('height', h);
let image = context.getImageData(0, 0, w, h);
let y = 0
while (y < h) {
let x = 0
while (x < w) {
let c = this.depthMap.depthMap[y * w + x] / 50 * 255;
image.data[4 * (y * w + x)] = c;
image.data[4 * (y * w + x) + 1] = c;
image.data[4 * (y * w + x) + 2] = c;
image.data[4 * (y * w + x) + 3] = 255;
x++
}
y++
}
context.putImageData(image, 0, 0);
// gDepthMap = this.depthMap;
canvas.style.top = '0px'
canvas.style.position = 'absolute'
document.body.appendChild(canvas);
}
parse(depthmap) {
let depthMapData;
let header;
let data;
let depthMap;
depthMapData = new DataView(depthmap.buffer);
header = this.parseHeader(depthMapData);
data = this.parsePlanes(header, depthMapData);
depthMap = this.computeDepthMap(header, data.indices, data.planes);
console.log(depthMap)
return depthMap;
}
parseHeader(depthMap) {
return {
headerSize: depthMap.getUint8(0),
numberOfPlanes: depthMap.getUint16(1, true),
width: depthMap.getUint16(3, true),
height: depthMap.getUint16(5, true),
offset: depthMap.getUint16(7, true)
};
}
parsePlanes(header, depthMap) {
var planes = [],
indices = [],
i,
n = [0, 0, 0],
d,
byteOffset;
for (i = 0; i < header.width * header.height; ++i) {
indices.push(depthMap.getUint8(header.offset + i));
}
for (i = 0; i < header.numberOfPlanes; ++i) {
byteOffset = header.offset + header.width * header.height + i * 4 * 4;
n[0] = depthMap.getFloat32(byteOffset, true);
n[1] = depthMap.getFloat32(byteOffset + 4, true);
n[2] = depthMap.getFloat32(byteOffset + 8, true);
d = depthMap.getFloat32(byteOffset + 12, true);
planes.push({
n: n.slice(0),
d: d
});
}
return {
planes: planes,
indices: indices
};
}
computeDepthMap(header, indices, planes) {
var depthMap = null,
x, y,
planeIdx,
phi, theta,
v = [0, 0, 0],
w = header.width,
h = header.height,
plane, t, p;
depthMap = new Float32Array(w * h);
var sin_theta = new Float32Array(h);
var cos_theta = new Float32Array(h);
var sin_phi = new Float32Array(w);
var cos_phi = new Float32Array(w);
for (y = 0; y < h; ++y) {
theta = (h - y - 0.5) / h * Math.PI;
sin_theta[y] = Math.sin(theta);
cos_theta[y] = Math.cos(theta);
}
for (x = 0; x < w; ++x) {
phi = (w - x - 0.5) / w * 2 * Math.PI + Math.PI / 2;
sin_phi[x] = Math.sin(phi);
cos_phi[x] = Math.cos(phi);
}
for (y = 0; y < h; ++y) {
for (x = 0; x < w; ++x) {
planeIdx = indices[y * w + x];
v[0] = sin_theta[y] * cos_phi[x];
v[1] = sin_theta[y] * sin_phi[x];
v[2] = cos_theta[y];
if (planeIdx > 0) {
plane = planes[planeIdx];
t = Math.abs(plane.d / (v[0] * plane.n[0] + v[1] * plane.n[1] + v[2] * plane.n[2]));
depthMap[y * w + (w - x - 1)] = t;
} else {
depthMap[y * w + (w - x - 1)] = 9999999999999999999.;
}
}
}
return {
width: w,
height: h,
depthMap: depthMap
};
}
decode(rawDepthMap) {
let compressedDepthMapData;
let depthMap;
let decompressedDepthMap;
// Append '=' in order to make the length of the array a multiple of 4
while (rawDepthMap.length % 4 != 0) {
rawDepthMap += '=';
}
// Replace '-' by '+' and '_' by '/'
rawDepthMap = rawDepthMap.replace(/-/g, '+');
rawDepthMap = rawDepthMap.replace(/_/g, '/');
// Decode and decompress data
compressedDepthMapData = base64.decode(rawDepthMap);
decompressedDepthMap = zpipe.inflate(compressedDepthMapData);
// Convert output of decompressor to Uint8Array
depthMap = new Uint8Array(decompressedDepthMap.length);
for (var i = 0; i < decompressedDepthMap.length; ++i) {
depthMap[i] = decompressedDepthMap.charCodeAt(i);
}
return depthMap;
}
ajaxGet(url) {
return new Promise(function(resolve, reject) {
let req = new XMLHttpRequest();
req.responseType = 'jsonp';
req.open("GET", url);
req.onload = function() {
if (req.status === 200) {
resolve(req.response);
} else {
reject(new Error(req.statusText));
}
};
req.onerror = function() {
reject(new Error("Network error"));
};
req.send();
});
}
addCallback(url) {
// The URL already has a callback
if (url.match(/callback=[a-z]/i)) {
return url;
}
return url + ("&callback=cb" + Math.random()).replace('.', '');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment