Рисование краев BLOB-объектов, которые находятся на краю эскиза в Обработка

Я работал в обработке с библиотекой blobDetection, делая контурные карты из карт высот. Сейчас я экспортирую каждый слой в виде SVG для лазерной резки, но капли, которые находятся на краю эскиза, не завершены, вершины краев не нарисованы.

Вот упрощенный пример:

  1. Изображение, с которого я начинаю, белые области станут каплями

  1. Вывод SVG, пропуская края

import processing.svg.*;
import blobDetection.*;
import peasy.*;
import processing.pdf.*;
PeasyCam cam;

PImage img;

float levels = 10;

BlobDetection[] contours = new BlobDetection[int(levels)];

//Creating array to store the blob objects
ArrayList<Ring> rings = new ArrayList<Ring>();

void setup() {

  size(480, 360, P3D);
  surface.setResizable(true);

  img = loadImage("maptest2.jpg");
  surface.setSize(img.width, img.height);

  cam = new PeasyCam(this, img.width, img.height, 0, 1500);
  colorMode(HSB, 360, 100, 100);

  for (int i=0; i<levels; i++) {
    contours[i] = new BlobDetection(img.width, img.height);
    contours[i].setThreshold(i/levels);
    contours[i].computeBlobs(img.pixels);
  }

  for (int i = 0; i < rings.size(); i++) {
    System.out.println("id: " + rings.get(i).getId());
    System.out.println("lvl: " + rings.get(i).getLvl());
    System.out.println("x: " + rings.get(i).getX());
    System.out.println("y: " + rings.get(i).getY());
    System.out.println();
  }

  noLoop();
}


void draw() {

  for (int i=0; i<levels; i++) {  

    beginRecord(SVG, "level-"+i+".svg");

    drawContours(i);
    println("drew level " + i);

    println("saved as: level-"+i+".svg");
    endRecord();
    println();

    if(i == levels-1){
      println("finished");
    }

  }

  System.out.println("Number of blobs (rings.size()): " + rings.size());
   println();

   for (int i = 0; i < rings.size(); i++){
   System.out.println("id: " + rings.get(i).getId());
   System.out.println("lvl: " + rings.get(i).getLvl());
   System.out.println("x: " + rings.get(i).getX());
   System.out.println("y: " + rings.get(i).getY());
   System.out.println();
   }

}

void drawContours(int i) {
  Blob b;
  EdgeVertex eA, eB;
  for (int n=0; n<contours[i].getBlobNb(); n++) {
    b=contours[i].getBlob(n);

    //Condition for drawing only blobs bigger than 5% of width and 5% of height
    if(b.w*width>.05*width && b.h*height>.05*height){

      if (b!=null) {
        stroke(250, 75, 90);

        for (int m=0; m<b.getEdgeNb(); m++) {
          eA = b.getEdgeVertexA(m);
          eB = b.getEdgeVertexB(m);

          //This part draws the blobs.

          if (eA !=null && eB !=null)
           line(
           eA.x*img.width, eA.y*img.height, 
           eB.x*img.width, eB.y*img.height 
           );

           println("eA.x: " + eA.x);
           println("eA.y: " + eA.y);
           println("eB.x: " + eB.x);
           println("eB.y: " + eB.y);
           println();

           ////////////
           //Here are my various attempts at drawing these rogue edges!
           //I commented them out

           /*      
           //Checking if vertex has a point at x=0
           if (b.getEdgeVertexA(m).x == 0 && b.getEdgeVertexB(b.getEdgeNb()).x == 0){


                 line(  b.getEdgeVertexA(0).x*img.width, b.getEdgeVertexA(0).y*img.height, 
                        b.getEdgeVertexA(m).x*img.width, b.getEdgeVertexA(m).y*img.height   );

                 println("////");
                 println("x making line (scaled 0-1): ");
                 //println(eA.x, eA.y, eB.x, eB.y);
                 println(  b.getEdgeVertexA(0).x, b.getEdgeVertexA(0).y, 
                           b.getEdgeVertexA(m).x, b.getEdgeVertexA(m).y   );

                 println("////");
           }

           //Checking if vertex has a point at y=0
           if (b.getEdgeVertexA(m).y == 0 && b.getEdgeVertexB(b.getEdgeNb()).y == 0){

             line(  b.getEdgeVertexA(0).x*img.width, b.getEdgeVertexA(0).y*img.height, 
                    b.getEdgeVertexA(m).x*img.width, b.getEdgeVertexA(m).y*img.height   );

                 println("////");
                 println("y making line (scaled 0-1): ");
                 //println(eA.x, eA.y, eB.x, eB.y);
                 println(  b.getEdgeVertexA(0).x, b.getEdgeVertexA(0).y, 
                           b.getEdgeVertexA(m).x, b.getEdgeVertexA(m).y   );

                 println("////");

           }

           if (b.getEdgeVertexA(m).x == 0 && b.getEdgeVertexB(b.getEdgeNb()).y == 0){

             line(  b.getEdgeVertexA(0).x*img.width, b.getEdgeVertexA(0).y*img.height, 0, 0   );
             println("drew to 0,0");
           }

           if (b.getEdgeVertexA(m).y == 0 && b.getEdgeVertexB(b.getEdgeNb()).x == 0){

             line(  b.getEdgeVertexA(m).x*img.width, b.getEdgeVertexA(m ).y*img.height, 0, 0   );
             println("drew to 0,0");
           }
           */
           ////////////

        }

        //Adding objects to the rings ArrayList
        rings.add(new Ring(String.valueOf(rings.size()+1), (int) i, (double) b.x*100, (double) b.y*100));
        }
    }
  }
}

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

Я думал о:

  • проверка, равна ли любая координата вершины, составляющей блоб, 0 (минимальная ширина или высота) или 1 (максимальная ширина или высота)
  • рисуя прямую линию от конечных объектов капли к верхнему левому углу эскиза, если, например, капля перекрывает этот угол
  • много других условий, но так много я в замешательстве...

У любого есть представление о том, как заказать условия или как подойти к проблеме... Помощь с благодарностью!

2 ответа

Решение

Мой коллега наткнулся на умное решение этой проблемы, которое состоит в том, чтобы увеличить размер исходного изображения на один пиксель с каждой стороны и сделать эти пиксели черными. Таким образом, если изображение было 100x100px, тогда оно будет 102x102px. Мы добавляем черные пиксели в нашем случае, но я думаю, что лучший способ сделать это - вычислить цвет обрезки, который определяет, рисовать или нет каплю, и назначить этим новым пикселям границы цвет немного или чуть ниже / выше, (в зависимости от ваших потребностей).

Код в основном такой же, как в моем исходном вопросе, за исключением части, в которую мы импортируем и модифицируем изображение:

PImage ref;
PImage output;
String filename = "maptest2.jpg";

// // //

//Here I skip some parts that are unchanged

// // //

void setup() {

  size(480, 360, P3D);
  surface.setResizable(true);

  ref = loadImage(filename);

  // create a copy of reference image with a black border
  output = createImage(ref.width+2, ref.height+2, RGB);

  for(int i=0; i < output.pixels.length; i++){
    output.pixels[i] = color(0);
  }

  output.updatePixels();
  output.set(1, 1, ref);

  surface.setSize(output.width, output.height);

  cam = new PeasyCam(this, output.width, output.height, 0, 1500);

Результирующий SVG-вывод с желаемыми внешними границами:

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

Надеюсь это поможет!

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

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

          eA = b.getEdgeVertexA(m);
          eB = b.getEdgeVertexB(m);

          //This part draws the blobs.
        if (eA !=null && eB !=null){
          float x1 = eA.x*img.width;
          float y1 = eA.y*img.height;
          float x2 = eB.x*img.width;
          float y2 = eB.y*img.height;

          x1 = min(max(0,x1),WIDTH);
          y1 = min(max(0,y1),HEIGHT);
          x2 = min(max(0,x2),WIDTH);
          y2 = min(max(0,y2),HEIGHT);


          line(x1, y1, x2, y2);

           println("eA.x: " + eA.x + " x1: " + x1);
           println("eA.y: " + eA.y + " y1: " + y1);
           println("eB.x: " + eB.x + " x2: " + x2);
           println("eB.y: " + eB.y + " y2: " + y2);
           println();
         }

Логика такова: min(max(0,x1),WIDTH)

Сначала мы находим max(0,x1) таким образом, мы уверены, что x1 больше 0, если оно отрицательное, установите его в 0.

Затем мы берем результат предыдущей операции и делаем следующее min(result,WIDTH) поэтому пытаемся найти минимальное число между ними, мы знаем, что результат>= 0, а ширина окна>= 1, поэтому, если число больше ширины окна, ограничьте его значением ширина.

Мы получаем число, которое находится между 0 а также WIDTHЕсли исходное значение уже было в пределах этих ограничений, оно не изменяется. Это должно нарисовать любые края, которые будут нарисованы на внешней стороне окна по краям. Попробуйте и дайте мне знать, если это работает!

Другие вопросы по тегам