mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-16 05:10:00 +01:00
refactor and remove hysteresis (#327)
* refactor and remove hysteresis Signed-off-by: tech4GT <varun.gupta1798@gmail.com> * fixes #323 Signed-off-by: tech4GT <varun.gupta1798@gmail.com> * bump version #
This commit is contained in:
committed by
Jeffrey Warren
parent
6106e5ee0c
commit
0638a1c68c
@@ -1,179 +1,177 @@
|
||||
const _ = require('lodash')
|
||||
|
||||
//define kernels for the sobel filter
|
||||
const kernelx = [[-1,0,1],[-2,0,2],[-1,0,1]],
|
||||
kernely = [[-1,-2,-1],[0,0,0],[1,2,1]]
|
||||
const kernelx = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
|
||||
kernely = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]];
|
||||
|
||||
let angles = []
|
||||
let mags = []
|
||||
let strongEdgePixels = []
|
||||
let weakEdgePixels = []
|
||||
let notInUI
|
||||
module.exports = exports = function(pixels,highThresholdRatio,lowThresholdRatio,inBrowser){
|
||||
notInUI = !inBrowser
|
||||
for(var x = 0; x < pixels.shape[0]; x++) {
|
||||
angles.push([])
|
||||
mags.push([])
|
||||
for(var y = 0; y < pixels.shape[1]; y++) {
|
||||
let angles = [], mags = [], strongEdgePixels = [], weakEdgePixels = [], notInUI;
|
||||
module.exports = function(pixels, highThresholdRatio, lowThresholdRatio, inBrowser) {
|
||||
notInUI = !inBrowser;
|
||||
for (var x = 0; x < pixels.shape[0]; x++) {
|
||||
angles.push([]);
|
||||
mags.push([]);
|
||||
for (var y = 0; y < pixels.shape[1]; y++) {
|
||||
var result = changePixel(
|
||||
pixels,
|
||||
pixels.get(x,y,0),
|
||||
pixels.get(x, y, 0),
|
||||
pixels.get(x, y, 3),
|
||||
x,
|
||||
y
|
||||
)
|
||||
let pixel = result.pixel
|
||||
|
||||
);
|
||||
let pixel = result.pixel;
|
||||
|
||||
pixels.set(x, y, 0, pixel[0]);
|
||||
pixels.set(x, y, 1, pixel[1]);
|
||||
pixels.set(x, y, 2, pixel[2]);
|
||||
pixels.set(x, y, 3, pixel[3]);
|
||||
|
||||
mags.slice(-1)[0].push(pixel[3])
|
||||
angles.slice(-1)[0].push(result.angle)
|
||||
|
||||
mags.slice(-1)[0].push(pixel[3]);
|
||||
angles.slice(-1)[0].push(result.angle);
|
||||
}
|
||||
}
|
||||
|
||||
return hysteresis(doubleThreshold(nonMaxSupress(pixels),highThresholdRatio,lowThresholdRatio))
|
||||
|
||||
return doubleThreshold(nonMaxSupress(pixels), highThresholdRatio, lowThresholdRatio);
|
||||
}
|
||||
|
||||
//changepixel function that convolutes every pixel (sobel filter)
|
||||
function changePixel(pixels,val,a,x,y){
|
||||
let magX = 0.0
|
||||
for(let a = 0; a < 3; a++){
|
||||
for(let b = 0; b < 3; b++){
|
||||
|
||||
function changePixel(pixels, val, a, x, y) {
|
||||
let magX = 0.0;
|
||||
for (let a = 0; a < 3; a++) {
|
||||
for (let b = 0; b < 3; b++) {
|
||||
|
||||
let xn = x + a - 1;
|
||||
let yn = y + b - 1;
|
||||
|
||||
magX += pixels.get(xn,yn,0) * kernelx[a][b];
|
||||
|
||||
magX += pixels.get(xn, yn, 0) * kernelx[a][b];
|
||||
}
|
||||
}
|
||||
let magY = 0.0
|
||||
for(let a = 0; a < 3; a++){
|
||||
for(let b = 0; b < 3; b++){
|
||||
|
||||
let magY = 0.0;
|
||||
for (let a = 0; a < 3; a++) {
|
||||
for (let b = 0; b < 3; b++) {
|
||||
|
||||
let xn = x + a - 1;
|
||||
let yn = y + b - 1;
|
||||
|
||||
magY += pixels.get(xn,yn,0) * kernely[a][b];
|
||||
|
||||
magY += pixels.get(xn, yn, 0) * kernely[a][b];
|
||||
}
|
||||
}
|
||||
let mag = Math.sqrt(Math.pow(magX,2) + Math.pow(magY,2))
|
||||
let angle = Math.atan2(magY,magX)
|
||||
let mag = Math.sqrt(Math.pow(magX, 2) + Math.pow(magY, 2));
|
||||
let angle = Math.atan2(magY, magX);
|
||||
return {
|
||||
pixel:
|
||||
[val,val,val,mag],
|
||||
[val, val, val, mag],
|
||||
angle: angle
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//Non Maximum Supression without interpolation
|
||||
function nonMaxSupress(pixels) {
|
||||
angles = angles.map((arr)=>arr.map(convertToDegrees))
|
||||
|
||||
for(let i = 1;i<pixels.shape[0]-1;i++){
|
||||
for(let j=1;j<pixels.shape[1]-1;j++){
|
||||
|
||||
let angle = angles[i][j]
|
||||
let pixel = pixels.get(i,j)
|
||||
|
||||
if ((angle>=-22.5 && angle<=22.5) ||
|
||||
(angle<-157.5 && angle>=-180))
|
||||
|
||||
if ((mags[i][j]>= mags[i][j+1]) &&
|
||||
(mags[i][j] >= mags[i][j-1]))
|
||||
pixels.set(i,j,3,mags[i][j])
|
||||
else
|
||||
pixels.set(i,j,3,0)
|
||||
|
||||
else if ((angle>=22.5 && angle<=67.5) ||
|
||||
(angle<-112.5 && angle>=-157.5))
|
||||
|
||||
if ((mags[i][j] >= mags[i+1][j+1]) &&
|
||||
(mags[i][j] >= mags[i-1][j-1]))
|
||||
pixels.set(i,j,3,mags[i][j])
|
||||
else
|
||||
pixels.set(i,j,3,0)
|
||||
|
||||
else if ((angle>=67.5 && angle<=112.5) ||
|
||||
(angle<-67.5 && angle>=-112.5))
|
||||
|
||||
if ((mags[i][i] >= mags[i+1][j]) &&
|
||||
(mags[i][j] >= mags[i][j]))
|
||||
pixels.set(i,j,3,mags[i][j])
|
||||
else
|
||||
pixels.set(i,j,3,0)
|
||||
|
||||
else if ((angle>=112.5 && angle<=157.5) ||
|
||||
(angle<-22.5 && angle>=-67.5))
|
||||
|
||||
if ((mags[i][j] >= mags[i+1][j-1]) &&
|
||||
(mags[i][j] >= mags[i-1][j+1]))
|
||||
pixels.set(i,j,3,mags[i][j])
|
||||
else
|
||||
pixels.set(i,j,3,0)
|
||||
function nonMaxSupress(pixels) {
|
||||
|
||||
angles = angles.map((arr) => arr.map(convertToDegrees));
|
||||
|
||||
for (let i = 1; i < pixels.shape[0] - 1; i++) {
|
||||
for (let j = 1; j < pixels.shape[1] - 1; j++) {
|
||||
|
||||
let angle = angles[i][j];
|
||||
let pixel = pixels.get(i, j);
|
||||
|
||||
if ((angle >= -22.5 && angle <= 22.5) ||
|
||||
(angle < -157.5 && angle >= -180))
|
||||
|
||||
if ((mags[i][j] >= mags[i][j + 1]) &&
|
||||
(mags[i][j] >= mags[i][j - 1]))
|
||||
pixels.set(i, j, 3, mags[i][j]);
|
||||
else
|
||||
pixels.set(i, j, 3, 0);
|
||||
|
||||
else if ((angle >= 22.5 && angle <= 67.5) ||
|
||||
(angle < -112.5 && angle >= -157.5))
|
||||
|
||||
if ((mags[i][j] >= mags[i + 1][j + 1]) &&
|
||||
(mags[i][j] >= mags[i - 1][j - 1]))
|
||||
pixels.set(i, j, 3, mags[i][j]);
|
||||
else
|
||||
pixels.set(i, j, 3, 0);
|
||||
|
||||
else if ((angle >= 67.5 && angle <= 112.5) ||
|
||||
(angle < -67.5 && angle >= -112.5))
|
||||
|
||||
if ((mags[i][i] >= mags[i + 1][j]) &&
|
||||
(mags[i][j] >= mags[i][j]))
|
||||
pixels.set(i, j, 3, mags[i][j]);
|
||||
else
|
||||
pixels.set(i, j, 3, 0);
|
||||
|
||||
else if ((angle >= 112.5 && angle <= 157.5) ||
|
||||
(angle < -22.5 && angle >= -67.5))
|
||||
|
||||
if ((mags[i][j] >= mags[i + 1][j - 1]) &&
|
||||
(mags[i][j] >= mags[i - 1][j + 1]))
|
||||
pixels.set(i, j, 3, mags[i][j]);
|
||||
else
|
||||
pixels.set(i, j, 3, 0);
|
||||
|
||||
}
|
||||
}
|
||||
return pixels
|
||||
return pixels;
|
||||
}
|
||||
//Converts radians to degrees
|
||||
var convertToDegrees = radians => (radians * 180)/Math.PI
|
||||
var convertToDegrees = radians => (radians * 180) / Math.PI;
|
||||
|
||||
//Finds the max value in a 2d array like mags
|
||||
var findMaxInMatrix = arr => Math.max(...arr.map(el=>el.map(val=>!!val?val:0)).map(el=>Math.max(...el)))
|
||||
var findMaxInMatrix = arr => Math.max(...arr.map(el => el.map(val => !!val ? val : 0)).map(el => Math.max(...el)));
|
||||
|
||||
//Applies the double threshold to the image
|
||||
function doubleThreshold(pixels,highThresholdRatio,lowThresholdRatio){
|
||||
const highThreshold = findMaxInMatrix(mags) * 0.2
|
||||
const lowThreshold = highThreshold * lowThresholdRatio
|
||||
function doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio) {
|
||||
|
||||
for(let i =0;i<pixels.shape[0];i++){
|
||||
for(let j=0;j<pixels.shape[1];j++){
|
||||
let pixelPos = [i,j]
|
||||
|
||||
mags[i][j]>lowThreshold
|
||||
?mags[i][j]>highThreshold
|
||||
?strongEdgePixels.push(pixelPos)
|
||||
:weakEdgePixels.push(pixelPos)
|
||||
:pixels.set(i,j,3,0)
|
||||
const highThreshold = findMaxInMatrix(mags) * 0.2;
|
||||
const lowThreshold = highThreshold * lowThresholdRatio;
|
||||
|
||||
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||
for (let j = 0; j < pixels.shape[1]; j++) {
|
||||
let pixelPos = [i, j];
|
||||
|
||||
mags[i][j] > lowThreshold
|
||||
? mags[i][j] > highThreshold
|
||||
? strongEdgePixels.push(pixelPos)
|
||||
: weakEdgePixels.push(pixelPos)
|
||||
: pixels.set(i, j, 3, 0);
|
||||
}
|
||||
}
|
||||
|
||||
strongEdgePixels.forEach(pix=>pixels.set(pix[0],pix[1],3,255))
|
||||
|
||||
return pixels
|
||||
strongEdgePixels.forEach(pix => pixels.set(pix[0], pix[1], 3, 255));
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
// hysteresis edge tracking algorithm
|
||||
function hysteresis(pixels){
|
||||
function getNeighbouringPixelPositions(pixelPosition){
|
||||
let x = pixelPosition[0],y=pixelPosition[1]
|
||||
return [[x+1,y+1],
|
||||
[x+1,y],
|
||||
[x+1,y-1],
|
||||
[x,y+1],
|
||||
[x,y-1],
|
||||
[x-1,y+1],
|
||||
[x-1,y],
|
||||
[x-1,y-1]]
|
||||
// hysteresis edge tracking algorithm -- not working as of now
|
||||
/* function hysteresis(pixels) {
|
||||
function getNeighbouringPixelPositions(pixelPosition) {
|
||||
let x = pixelPosition[0], y = pixelPosition[1]
|
||||
return [[x + 1, y + 1],
|
||||
[x + 1, y],
|
||||
[x + 1, y - 1],
|
||||
[x, y + 1],
|
||||
[x, y - 1],
|
||||
[x - 1, y + 1],
|
||||
[x - 1, y],
|
||||
[x - 1, y - 1]]
|
||||
}
|
||||
|
||||
//This can potentially be improved see https://en.wikipedia.org/wiki/Connected-component_labeling
|
||||
for(weakPixel in weakEdgePixels){
|
||||
let neighbourPixels = getNeighbouringPixelPositions(weakEdgePixels[weakPixel])
|
||||
for(pixel in neighbourPixels){
|
||||
if(strongEdgePixels.find(el=> _.isEqual(el,neighbourPixels[pixel]))) {
|
||||
pixels.set(weakPixel[0],weakPixel[1],3,255)
|
||||
weakEdgePixels.splice(weakPixel,weakPixel)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
weakEdgePixels.forEach(pix=>pixels.set(pix[0],pix[1],3,0))
|
||||
return pixels
|
||||
}
|
||||
//This can potentially be improved see https://en.wikipedia.org/wiki/Connected-component_labeling
|
||||
for (weakPixel in weakEdgePixels) {
|
||||
let neighbourPixels = getNeighbouringPixelPositions(weakEdgePixels[weakPixel])
|
||||
for (pixel in neighbourPixels) {
|
||||
if (strongEdgePixels.find(el => _.isEqual(el, neighbourPixels[pixel]))) {
|
||||
pixels.set(weakPixel[0], weakPixel[1], 3, 255)
|
||||
weakEdgePixels.splice(weakPixel, weakPixel)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
weakEdgePixels.forEach(pix => pixels.set(pix[0], pix[1], 3, 0))
|
||||
return pixels
|
||||
} */
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user