Skip to content

Instantly share code, notes, and snippets.

@Sphinxxxx
Created January 29, 2021 11:29
Show Gist options
  • Save Sphinxxxx/09a1d1cdf46db5ddb2cf8128bb6e20c6 to your computer and use it in GitHub Desktop.
Save Sphinxxxx/09a1d1cdf46db5ddb2cf8128bb6e20c6 to your computer and use it in GitHub Desktop.
Canny edge detection with jsfeat
<script>console.clear();</script>
<script type="text/javascript" src="https://unpkg.com/[email protected]/build/dat.gui.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/inspirit/jsfeat@master/build/jsfeat.js"></script>
<canvas id="canv"></canvas>
<input type="file" id="source" accept="image/*"/>
(function() {
"use strict";
const _canvas = document.querySelector('#canv'),
_options = {
blur_radius: 5,
low_threshold: 1,
high_threshold: 70,
};
let _img, _w, _h, _ctx, _bitmap;
function init(img) {
_img = img;
_w = img.width;
_h = img.height;
const measure = Math.max(_w, _h);
if(measure > 600) {
const shrink = 600/measure;
_w = Math.round(_w * shrink);
_h = Math.round(_h * shrink);
}
_canvas.width = _w;
_canvas.height = _h;
_ctx = _canvas.getContext("2d");
_bitmap = new jsfeat.matrix_t(_w, _h, jsfeat.U8C1_t);
}
function render() {
const ctx = _ctx;
_ctx.drawImage(_img, 0, 0, _w, _h);
var imageData = ctx.getImageData(0, 0, _w, _h);
console.log("grayscale");
jsfeat.imgproc.grayscale(imageData.data, _w, _h, _bitmap);
var r = _options.blur_radius | 0.0;
var kernel_size = (r + 1) << 1;
console.log("gauss blur " + r + ' ' + kernel_size);
jsfeat.imgproc.gaussian_blur(_bitmap, _bitmap, kernel_size, 0);
console.log("canny edge");
jsfeat.imgproc.canny(
_bitmap,
_bitmap,
_options.low_threshold,
_options.high_threshold
);
// render result back to canvas
//console.log("render", _bitmap);
var data_u32 = new Uint32Array(imageData.data.buffer);
var alpha = 0xff << 24;
var i = _bitmap.cols * _bitmap.rows,
pix = 0;
while (--i >= 0) {
pix = _bitmap.data[i];
data_u32[i] = alpha | (pix << 16) | (pix << 8) | pix;
}
ctx.putImageData(imageData, 0, 0);
}
(function load() {
const gui = new dat.GUI();
gui.add(_options, "blur_radius", 0, 10).step(1).onChange(render);
gui.add(_options, "low_threshold", 1, 200).step(1).onChange(render);
gui.add(_options, "high_threshold", 1, 200).step(1).onChange(render);
const img = new Image();
img.onload = e => {
init(img);
render();
}
document.querySelector('#source').onchange = function(e) {
var url = URL.createObjectURL(this.files[0]);
img.src = url;
};
img.src = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAIVcZHVkU4V1bHWWjoWeyP/ZyLe3yP////L/////////////////////////////////////////////////////2wBDAY6WlsivyP/Z2f//////////////////////////////////////////////////////////////////////////wgARCAHSAlgDAREAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECA//EABYBAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABtgAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAABQACAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQCAAAAAAAAAAAAAAAAAAAAAAAAAAoIUAAAAAAAAAkKAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAhQAAARkhF3YAAAAAAAAAAAAAAAAAAABQAAAAAACRRSIaURAFSAMrAAbsAAAAAAAAAAAAAAAAAAAoAAAAAJEIRQNIIu4pzN0QYUQAFEUuoAAAAAAAAAAAAAAAAAAKAAACEgoRKgLAlAU6QMkJUAAALGgNSggAAAAAAAAAAAAAAAAgqygAEjJF0CEKCRKgAKUAAAGopDJTRRqAQAAAAAAAAAAAAAAAFhLAXUAkZIoAoBkgBYlAAUAoig0CA0UE1ABAAAAAAAUEAAAAAABRCWAupIyRQBQQyAWKVRmyAoKIAFNGgZIbAJqACAoABAACgAEAAAAAKAIsuQZoQoBCEBYq0AAzYBYAoKAaKDINAE1AAAAAAAAAAABAAAUAAQlySoCkIQFirQUGoGKEQUFAABTQIZKUoJqAAAAAAAAAAAAAAAAIhlQBCEBYq0AGixmtQM1AlAKAAAaBCFBQTUAAAAAAAAAAAAAAAkFyQAhAWKtABTUShZM20sktyCpQAA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';
})();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment