eberly = {
let localArtTable = [
0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,
0,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,
0,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,
0,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
0,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,
0,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,
0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,
1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,
0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,
1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,
0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0
];
let neighbor8C = [
[-1, -1], [0, -1], [1,-1],
[1, 0], [1, 1], [0, 1],
[-1, 1], [-1, 0]];
function eberly (image) {
let wid = image.width;
let hgt = image.height;
let data = image.data;
let stepCounter = new StepCounter(wid,hgt);
// binarize
let bindata = new Uint8ClampedArray(image.data.length/4);
for (let i = 0; i < bindata.length; i++) bindata[i] = data[i*4+3]>0;
let get = (col,row) => bindata[col+row*wid];
let set = (col,row,value) => { bindata[col+row*wid] = value };
let isInterior = (col,row) => get(col,row) == 1 && (get(col+1,row) && get(col-1,row) &&
get(col,row-1) && get(col,row+1));
let is3Interior = (col,row) => get(col,row) == 1 && ((get (col+1,row) > 0) + (get (col-1,row)>0) +
(get(col,row-1) > 0) + (get(col,row+1)>0) == 3);
let isBoundary = (col,row) => get(col,row) == 1 && (get (col+1,row) == 0 || get (col-1,row) == 0 ||
get(col,row-1) == 0 || get(col,row+1) == 0);
let isLocalArticulation = (col, row) => {
if (get (col,row) == 0) return false;
let index = 0;
for (let i = 0; i < 8; i++) {
let [dcol,drow] = neighbor8C[i];
index |= (get (col+dcol,row+drow) > 0)<<i;
}
return localArtTable[index]>0;
}
// Marks the interior pixels with 2 and returns the total number of marked pixels
function markInterior () {
let count = 0;
for (let row = 1; row < hgt-1; row++) {
for (let col = 1; col < wid-1; col++) {
if (isInterior(col,row)) {
set (col,row,2);
count++;
}
}
}
return count;
}
// Marks the 3-interior pixels with 3 and returns the total number of
// marked pixels
function mark3Interior () {
let count = 0;
for (let row = 1; row < hgt-1; row++) {
for (let col = 1; col < wid-1; col++) {
if (is3Interior(col,row)) {
set (col,row,3);
count++;
}
}
}
return count;
}
// Returns true if pixel col,row has a neighbor which is
// an interior pixel. Method markInterior must have been
// called previously
function hasInteriorNeighbor (col, row) {
for (let i = 0; i < 8; i++) {
if (get (col+neighbor8C[i][0],row+neighbor8C[i][1])==2) return true;
}
return false;
}
// Returns true if pixel col,row has a neighbor which is
// a 3-interior pixel. Method mark3Interior must have been
// called previously
function has3InteriorNeighbor (col, row) {
for (let i = 0; i < 8; i++) {
if (get (col+neighbor8C[i][0],row+neighbor8C[i][1])==3) return true;
}
return false;
}
// Performs one step of the Large Scale Thinning Algorithm.
// Returns the number of removed pixels
function largeScaleThinStep () {
let result = 0;
if (markInterior () == 0) return 0;
for (let row = 1; row < hgt-1; row++) {
for (let col = 1; col < wid-1; col++) {
if (isBoundary (col,row) && (! isLocalArticulation(col,row)) &&
hasInteriorNeighbor(col,row)) {
stepCounter.mark(col,row);
set (col,row,0);
result++;
}
}
}
// Unmark interior points
for (let i = 0; i < bindata.length; i++) if (bindata[i] == 2) bindata[i] = 1;
return result;
}
// Performs the large scale thinning algorithm
function largeScaleThin () {
stepCounter.newStep();
while (largeScaleThinStep()>0) {stepCounter.newStep();}
}
// Performs one step of the smaller scale thinning algorithm
// returning the number of removed pixels
function smallerScaleThinStep () {
let result = 0;
if (mark3Interior () == 0) return 0;
for (let row = 1; row < hgt-1; row++) {
for (let col = 1; col < wid-1; col++) {
if (isBoundary (col,row) && (! isLocalArticulation(col,row)) &&
has3InteriorNeighbor(col,row)) {
set (col,row,0);
//stepCounter.mark(col,row);
result++;
}
}
}
// Unmark interior points
for (let i = 0; i < bindata.length; i++) if (bindata[i] == 3) bindata[i] = 1;
return result;
}
// Perforns the smaller scale thinning algorithm
function smallerScaleThin() {
while (smallerScaleThinStep()>0) {stepCounter.newStep();}
}
largeScaleThin()
smallerScaleThin()
// Unbinarize
for (let i = 0; i < bindata.length; i++) data[i*4+3] = bindata[i] == 1 ? 255 : 0;
// Collect skeleton
let collectSkeleton = () => {
let skeleton = [];
for (let row = 1; row < hgt-1; row++) {
for (let col = 1; col < wid-1; col++) {
if (get(col,row)) skeleton.push ([col,row,stepCounter.distance(col,row)]);
}
}
return skeleton;
}
return collectSkeleton();
}
return eberly
}