NodeJS Холст - Сохранить только обрезанную область на новый холст / файл - PullRequest
1 голос
/ 08 апреля 2020

Я столкнулся со следующей проблемой:

Мы получили много технических чертежей только черного и белого цвета. Такой рисунок содержит несколько объектов в одном изображении. Я закодировал детектор краев и сумел нарисовать линию / обрезать границу каждого отдельного объекта с помощью координат (полигонов).

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

Мне нужен каждый объект, так как это собственное изображение (например, jpg) без лишних пробелов вокруг объекта.

В целях тестирования я в настоящее время использую изображение Я написал ниже

multistar.jpg

Так выглядит мой текущий вывод, границы отмечены красным. Сначала пришлось инвертировать цвета, не обращайте на это внимания

multistar_currentOutput

var http = require('http')
var fs = require('fs') 
var Canvas = require('canvas');

function pixelIsTouching (coord1, coord2){

    if(coord1[0] == coord2[0] && 
      (coord1[1] == coord2[1]+1 ||
      coord1[1] == coord2[1]-1)){
        return true;
    }else if(coord1[1] == coord2[1] && 
            (coord1[0] == coord2[0]+1 ||
            coord1[0] == coord2[0]-1)){
        return true;
    }else{
        return false;
    }
}

http.createServer(function (req, res) {
    fs.readFile(__dirname + '/images/multistar.jpg', function(err, data) {
        if (err) throw err;

        var img = new Canvas.Image; // Create a new Image
        img.src = data;

        var canvas = Canvas.createCanvas(img.width, img.height);
        var ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, img.width, img.height);

        var pixeldata = ctx.getImageData(0, 0, img.width, img.height);

        // Filter out any black white noise + Invert 
        for(var x = 0; x < pixeldata.data.length; x+=4){

            if( pixeldata.data[x] > 127) {
                pixeldata.data[x] = 0;
                pixeldata.data[x+1] = 0;
                pixeldata.data[x+2] = 0;
            }else if(pixeldata.data[x] <= 127) {
                pixeldata.data[x] = 255;
                pixeldata.data[x+1] = 255;
                pixeldata.data[x+2] = 255;
            }
        }

        ctx.putImageData(pixeldata, 0, 0);

        var border = [];

        // Bilddaten pixelweise abarbeiten
        for (x = 0; x < pixeldata.width; x++) {

            for (y = 0; y < pixeldata.height; y++) {

                offset = (pixeldata.width * y + x) * 4;
                r = pixeldata.data[offset];   // rot
                g = pixeldata.data[offset + 1]; // grün
                b = pixeldata.data[offset + 2]; // blau
                a = pixeldata.data[offset + 3]; // Transparenz

                topOffset           = (pixeldata.width * (y-1) + x) * 4;
                rTop                = pixeldata.data[topOffset];

                topRightOffset      = (pixeldata.width * (y-1) + (x+1)) * 4;
                rTopRight           = pixeldata.data[topRightOffset];

                rightOffset         = (pixeldata.width * y + (x+1)) * 4;
                rRight              = pixeldata.data[rightOffset];

                bottomRightOffset   = (pixeldata.width * (y+1) + (x+1)) * 4;
                rBottomRight        = pixeldata.data[bottomRightOffset];

                bottomOffset        = (pixeldata.width * (y+1) + x) * 4;
                rBottom             = pixeldata.data[bottomOffset];

                bottomLeftOffset    = (pixeldata.width * (y+1) + (x-1)) * 4;
                rBottomLeft         = pixeldata.data[bottomLeftOffset];

                leftOffset          = (pixeldata.width * y + (x-1)) * 4;
                rLeft               = pixeldata.data[leftOffset];

                topLeftOffset       = (pixeldata.width * (y-1) + (x-1)) * 4;
                rTopLeft            = pixeldata.data[topLeftOffset];

                // Check around current white pixel if black one is near
                if( r == 255 && rTop == 0 ||
                    r == 255 && rTopRight == 0 ||
                    r == 255 && rRight == 0 ||
                    r == 255 && rBottomRight == 0 ||
                    r == 255 && rBottom == 0 || 
                    r == 255 && rBottomLeft == 0 ||
                    r == 255 && rLeft == 0 ||
                    r == 255 && rTopLeft == 0){

                        border.push([x, y]);
                    }
            }
        }

        //Order border array
        var borderscounter = 0;
        var borders = [[]];

        var coordFound = undefined;

        borders[borderscounter].push(border[0]);
        border.shift();


        while(border.length > 0){

            coordFound = false;

            for(a = 0; a < border.length; a++){

                lastBlobElement = borders[borderscounter].length-1;

                if(pixelIsTouching(border[a], borders[borderscounter][lastBlobElement])){

                    coordFound = true;
                    borders[borderscounter].push(border[a]);
                    border.splice(a, 1);

                }
            }

            if(coordFound == false && border.length > 0){
                borderscounter++;
                borders[borderscounter] = [];
                borders[borderscounter].push(border[0]);
                border.shift();
            }
        }

        // Draw Line via Border Array

        ctx.lineWidth = 1;
        ctx.strokeStyle = 'red';
        ctx.beginPath();

        for(b = 0; b < borders.length; b++){
            for(var a = 0; a < borders[b].length; a++){

                // + 0.5 to get rid of blurry lines
                if(a == 0){
                    ctx.moveTo(borders[b][a][0]+0.5, borders[b][a][1]);
                }else{
                    ctx.lineTo(borders[b][a][0]+0.5, borders[b][a][1]);
                }

                if(a == borders[b].length-1){
                    ctx.closePath();
                }
            }
        }

        ctx.stroke();

        //ctx.globalCompositeOperation = 'destination-out';
        // Crop images via coordinates
        ctx.beginPath();
        ctx.moveTo(borders[0][0][0], borders[0][0][1]);
        for(var i = 1; i < borders[0].length; i++){
            var p = borders[0][i];
            ctx.lineTo(borders[0][i][0], borders[0][i][1]);
        }
        ctx.closePath();

        ctx.clip();









        // save images as files
        var file = canvas.toDataURL("image/png");

        var data = file.replace(/^data:image\/\w+;base64,/, "");
        var buf = new Buffer(data, 'base64');
        fs.writeFile('cropped/image.png', buf);


        res.write('<html><body>');
        res.write('<img src="' + canvas.toDataURL() + '" />');
        res.write('</body></html>');
        res.end();
    });

}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');


1 Ответ

1 голос
/ 09 апреля 2020

Прежде всего, я хотел бы сказать, что это сложный способ только для одного вопроса StackOverflow: вам нужно уменьшить свою проблему до чего-то небольшого и точного, если вы хотите получить быстрые ответы ...


Если разбить ваш код, он выглядит так, ваш массив границ работает не совсем так, как я ожидал, посмотрите на это:

https://raw.githack.com/heldersepu/hs-scripts/master/HTML/canvas_parse.html

Там я получил четыре холст, вы можете распознать этапы вашего кода:

  • Первый - это изображение, такое же как
  • Второй примененный фильтр и инвертирование
  • Третий - это все границы в одном месте
  • Далее - анимация массива вашей границы

Я ожидал, что каждый элемент в границах был полигоном, но, кажется, что-то еще не совсем правильно, это первая часть, на которой вы должны сосредоточиться.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...