Рисование краев BLOB-объектов, которые находятся на краю эскиза в Обработка
Я работал в обработке с библиотекой blobDetection, делая контурные карты из карт высот. Сейчас я экспортирую каждый слой в виде SVG для лазерной резки, но капли, которые находятся на краю эскиза, не завершены, вершины краев не нарисованы.
Вот упрощенный пример:
- Изображение, с которого я начинаю, белые области станут каплями
- Вывод 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
Если исходное значение уже было в пределах этих ограничений, оно не изменяется. Это должно нарисовать любые края, которые будут нарисованы на внешней стороне окна по краям. Попробуйте и дайте мне знать, если это работает!