скелетизация изображения на js

Пытаюсь реализовать алгоритм ZS + OPTA скелетизации изображения. Функция должна принимать изображение и выдавать результат скелетизации.

Я пытался сделать такой алгоритм для бинарного массива, затем картинку переводить в ч/б , делать из нее массив (черный пиксель = 1, белый = 0) и применять функцию ZhangSuen() к этому массиву, а потом как-нибуль выводить это в canvas.

Но у меня возникли проблемы с ZhangSuen(), работает правильно, но удаляет много лишнего. Раз на маленьком массиве есть сбои, то на больших изображениях скорее всего будет работать очень плохо.

Основным предназначением любого алгоритма скелетизации является максимальное утоншиение всех линий на бинарном изображении, что приводит к получению скелета, в котором все линии имеют толщину в один пиксель.

Может кто-то подскажет как реализовать этот алгоритм немного по другому, обойдя шаг перевода в массив или найдет ошибку в коде ниже

вот что получилось (Буква R без палочки)

результат работы

Целая программа должна работать так

работа программы

Алгоритм

алгоритм работы

код алгоритма ZS+OPTA

псевдо код

формулы

function Point(x, y) {
    this.x = x;
    this.y = y;
}

let ZhangSuen = (function () {
    function ZhangSuen() {
    }


 ZhangSuen.image =  [
          '00000000000000000000000000000000',
          '01111111110000000111111110000000',
          '01110001111000001111001111000000',
          '01110000111000001110000111000000',
          '01110001111000001110000000000000',
          '01111111110000001110000000000000',
          '01110111100000001110011111110000',
          '01110011110000001111001111000000',
          '01110001111000000111111110000000',
          '00000000000000000000000000000000'
    ];

    ZhangSuen.nbrs = [[0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1]];
 
    ZhangSuen.nbrGroups = [[[0, 2, 4], [2, 4, 6]], [[0, 2, 6], [0, 4, 6]]];

    ZhangSuen.toWhite = new Array();
    
    ZhangSuen.main = function (args) {
        ZhangSuen.grid = new Array(ZhangSuen.image.length);
        for (let r = 0; r < ZhangSuen.image.length; r++)
            ZhangSuen.grid[r] = (ZhangSuen.image[r]).split('');
        ZhangSuen.thinImage();
    };
    ZhangSuen.thinImage = function () {
        let firstStep = false;
        let hasChanged;
        do {
            hasChanged = false;
            firstStep = !firstStep;
            for (let r = 1; r < ZhangSuen.grid.length - 1; r++) {
                for (let c = 1; c < ZhangSuen.grid[0].length - 1; c++) {
                    if (ZhangSuen.grid[r][c] !== '1')
                        continue;
                    let nn = ZhangSuen.numNeighbors(r, c);
                    if (nn < 2 || nn > 6)
                        continue;
                    if (ZhangSuen.numTransitions(r, c) !== 1)
                        continue;
                    if (!ZhangSuen.atLeastOneIsWhite(r, c, firstStep ? 0 : 1))
                        continue;
                    ZhangSuen.toWhite.push(new Point(c, r));
                    hasChanged = true;
                }
            }
            for (let i = 0; i < ZhangSuen.toWhite.length; i++) {
                let p = ZhangSuen.toWhite[i];
                ZhangSuen.grid[p.y][p.x] = '0';
            }
            ZhangSuen.toWhite = new Array();
        } while ((firstStep || hasChanged));
        ZhangSuen.printResult();
    };
    ZhangSuen.numNeighbors = function (r, c) {
        let count = 0;
        for (let i = 0; i < ZhangSuen.nbrs.length - 1; i++)
            if (ZhangSuen.grid[r + ZhangSuen.nbrs[i][1]][c + ZhangSuen.nbrs[i][0]] === '1')
                count++;
        return count;
    };
    ZhangSuen.numTransitions = function (r, c) {
        let count = 0;
        for (let i = 0; i < ZhangSuen.nbrs.length - 1; i++)
            if (ZhangSuen.grid[r + ZhangSuen.nbrs[i][1]][c + ZhangSuen.nbrs[i][0]] === '0') {
                if (ZhangSuen.grid[r + ZhangSuen.nbrs[i + 1][1]][c + ZhangSuen.nbrs[i + 1][0]] === '1')
                    count++;
            }
        return count;
    };
    ZhangSuen.atLeastOneIsWhite = function (r, c, step) {
        let count = 0;
        let group = ZhangSuen.nbrGroups[step];
        for (let i = 0; i < 2; i++)
            for (let j = 0; j < group[i].length; j++) {
                let nbr = ZhangSuen.nbrs[group[i][j]];
                if (ZhangSuen.grid[r + nbr[1]][c + nbr[0]] === '0') {
                    count++;
                    break;
                }
            }
        return count > 1;
    };
    ZhangSuen.printResult = function () {
        for (let i = 0; i < ZhangSuen.grid.length; i++) {
            let row = ZhangSuen.grid[i];
            console.log(row.join(''));
        }
    };
    return ZhangSuen;
}());
ZhangSuen.main(null);



Ответы (0 шт):