Обработка с высоким разрешением

Я ищу помощь с языком программирования / средой обработки.

Я довольно новичок в обработке, и я экспериментирую с куском кода от кого-то из openprocessing.org. Мне очень нравятся визуальные результаты, которые дает этот код, и я хотел бы продолжить работу с ним. К сожалению, на выходе очень низкое разрешение. Поэтому я ищу кого-то, кто мог бы помочь мне понять, как: а) увеличить размер или разрешение сгенерированных фигур и б) сохранить все как файл pdf.

Вы можете найти оригинальный код в действии здесь: https://www.openprocessing.org/sketch/377730

Это код:

import java.util.Arrays;
float[][] z, v, a;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup() {
  size(512, 512);
  colorMode(RGB, 2);
  z = new float[width][height];
  v = new float[width][height];
  a = new float[width][height];
  loadPixels();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void draw() {
  for (int x = 1; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
      a[x][y] = (v[x-1][y] + v[x+1][y] + v[x][y-1] + v[x][y+1])/4 - v[x][y];
    }
  }
  for (int x = 1; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
      v[x][y] += a[x][y];
      z[x][y] += v[x][y];
      pixels[width*y+x] = color(sin(z[x][y]) + 1, cos(z[x][y]), 1);
    }
  }
  updatePixels();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void move() {
  if (mouseX > -1    &&    mouseX < width    &&    mouseY > -1    &&    mouseY < height) {
    v[mouseX][mouseY] = randomGaussian() * TAU;
  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseClicked() { move(); }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseDragged() { move(); }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void keyPressed() {
  noLoop();
  for (int x = 0; x < width; x++)    Arrays.fill(z[x], 0);
  for (int x = 0; x < width; x++)    Arrays.fill(v[x], 0);
  loop();
}

До сих пор я экспериментировал с предполагаемым методом с высоким разрешением, опубликованным на Processing-Forum, который мне не помог, хотя бы не в контексте приведенного выше кода, с которым я работаю. Вот фрагмент кода с форума, который демонстрирует способ сохранения вывода обработки в одном разрешении одним пользователем:

int dim = 5000;
int dimScreen = dim/10;
color c1 = #AFA786;
color c2 = #000000;

void setup() { size(dimScreen,dimScreen); }
void draw()  { exampleSketch(); }

void exampleSketch() {
  for (int y=0; y<=height; y++) {
    stroke(lerpColor(c1,c2,float(y)/height));
    line(0,y,width,y);
  }
  stroke(#FFFFFF);
  fill(#BBBBBB);
  ellipse(width/2, height/2, width/2, height/2);
  line(0, 0, width, height);
}

void keyPressed() {
  if (key ==' ') {
    g = createGraphics(dim,dim,JAVA2D);
    this.height = dim;
    this.width = dim;
    g.beginDraw();
    exampleSketch();
    g.endDraw();
    save("result.png");
    println("screenshot saved");
    this.height = dimScreen;
    this.width = dimScreen;
  }
}

Я был бы чрезвычайно признателен всем, кто достаточно опытен в обработке и Java, чтобы выручить меня. Большое спасибо и спокойной ночи.

Вот моя попытка внедрения второго кода в первый:

import processing.pdf.*;
import java.util.Arrays;
float[][] z, v, a;

int dim = 900;
int dimScreen = dim/10;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup() {
  size(900, 900);
  smooth(8);
  colorMode(RGB, 2);
  z = new float[width][height];
  v = new float[width][height];
  a = new float[width][height];
  loadPixels();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void draw()  { exampleSketch(); }


void exampleSketch() {

  for (int x = 1; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
      a[x][y] = (v[x-1][y] + v[x+1][y] + v[x][y-1] + v[x][y+1])/4 - v[x][y];
    }
  }
  for (int x = 1; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
      v[x][y] += a[x][y];
      z[x][y] += v[x][y];
      pixels[width*y+x] = color(sin(z[x][y]) + 1, cos(z[x][y]), 1);
    }
  }
  updatePixels();


}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void move() {
  if (mouseX > -1    &&    mouseX < width    &&    mouseY > -1    &&    mouseY < height) {
    v[mouseX][mouseY] = randomGaussian() * TAU;

  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseClicked() { move(); }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseDragged() { move(); }


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void keyPressed() {
  if (key ==' ') {
    g = createGraphics(dim,dim,JAVA2D);
    this.height = dim;
    this.width = dim;
    g.beginDraw();
    exampleSketch();
    g.endDraw();
    save("result2.png");
    println("screenshot saved");
    this.height = 900;
    this.width = 900;
  }
}

Изменить: два снимка экрана, сравнивающие различные визуальные результаты до и после реализации решения Джорджа для белого фона:

До После

2 ответа

В дополнение к ответу Кевина вы можете использовать JVisualVM, чтобы увидеть, на что тратится большая часть процессорного времени. После выборки и профилирования ЦП в разное время на удивление большую часть времени вычислялись значения RGB:

jvisualvm screenshot1

jvisualvm screenshot2

jvisualvm screenshot3

Лучше всего начать с функций, занимающих большую часть процессора при оптимизации.

Вот версия эскиза, которая использует диапазон по умолчанию 0-255 RGB и вычисляет встроенное значение RGB (объединяя байты A,R,G,B):

import processing.pdf.*;
import java.util.Arrays;
float[][] z, v, a;

int dim = 900;
int dimScreen = dim/10;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup() {
  size(900, 900);
  smooth(8);
  //colorMode(RGB, 2);
  z = new float[width][height];
  v = new float[width][height];
  a = new float[width][height];
  loadPixels();

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void draw()  { exampleSketch(); }


void exampleSketch() {

  int r,g,b = 255;
  for (int x = 1; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
      a[x][y] = (v[x-1][y] + v[x+1][y] + v[x][y-1] + v[x][y+1]) * .25 - v[x][y];
    //}
  //}
//  //for (int x = 1; x < width-1; x++) {
    //for (int y = 1; y < height-1; y++) {
      v[x][y] += a[x][y];
      z[x][y] += v[x][y];
      r = ((int)((sin(z[x][y]) + 1) * 128) << 16);
      g = ((int)((cos(z[x][y]) * 128)) << 8);
      pixels[width*y+x] = 0xff000000 | r | g | b;
    }
  }
  updatePixels();
  fill(0);
  text((int)frameRate+"fps",15,15);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void move() {
  if (mouseX > -1    &&    mouseX < width    &&    mouseY > -1    &&    mouseY < height) {
    v[mouseX][mouseY] = randomGaussian() * TAU;

  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseClicked() { move(); }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseDragged() { move(); }


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int screenshotCount=1;
void keyPressed() {
  if (key ==' ') {
    save("result"+nf(screenshotCount,4)+".png");
    println("screenshot saved");
  }
}

//http://stackru.com/questions/40350644/high-resolution-processing-output

Обновление: вот модифицированная функция, которая отображает значения так, чтобы фон был белым:

void exampleSketch() {
  float rv,gv;
  int r,g,b = 255;
  for (int x = 1; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
      //compute accumulated value of neighbour cells(left+right+top+bottom), average (/4 or * .25) then subtract the current cell from v
      a[x][y] = (v[x-1][y] + v[x+1][y] + v[x][y-1] + v[x][y+1]) * .25 - v[x][y];
      //increment current v cell by the current accumulated cell
      v[x][y] += a[x][y];
      //increment current z (final/result) cell by the updated v cell
      z[x][y] += v[x][y];
      //in short z[x][y] += v[x][y] + ((v[-1][0] + v[+1][0] + v[0][-1] + v[0][+1]) / 4 - v[x][y])
      //scale sin(z) and cos(z) results to 0-255: sin/cos returns -1.0 to 1.0 then 1.0 is added -> 0.0 to 2.0 , then 128 is multiplied = 0-255
      rv = (sin(z[x][y]) + 1.0) * 128;
      gv = (cos(z[x][y]) + 1.0) * 128;
      //contrain to 0-255
      if(rv < 0)   rv = 0;
      if(rv > 255) rv = 255;
      if(gv < 0)   gv = 0;
      if(gv > 255) gv = 255;
      //cast to int and shift
      r = ((int)(rv) << 16);
      g = ((int)(gv) << 8);
      //alpha (0xff000000) cobined with r , g, b 
      int argb = 0xff000000 | r | g | b;
      pixels[width*y+x] = argb;
    }
  }
  updatePixels();
  fill(0);
  text((int)frameRate+"fps",15,15);
}

Вот что я мог спасти:

результат 1

результат 2

результат 3

Обновление 2. Вот версия, которая вычисляет значение прозрачности вместо белого:

import processing.pdf.*;
import java.util.Arrays;
float[][] z, v, a;

int dim = 900;
int dimScreen = dim/10;

PImage canvas;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup() {
  size(900, 900);
  smooth(8);
  //colorMode(RGB, 2);
  z = new float[width][height];
  v = new float[width][height];
  a = new float[width][height];
  loadPixels();


  canvas = createImage(width,height,ARGB);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void draw()  { exampleSketch(); }


void exampleSketch() {
  float rs,gc,rv,gv;
  int r,g,b = 255;
  for (int x = 1; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
      //compute accumulated value of neighbour cells(left+right+top+bottom), average (/4 or * .25) then subtract the current cell from v
      a[x][y] = (v[x-1][y] + v[x+1][y] + v[x][y-1] + v[x][y+1]) * .25 - v[x][y];
      //increment current v cell by the current accumulated cell
      v[x][y] += a[x][y];
      //increment current z (final/result) cell by the updated v cell
      z[x][y] += v[x][y];
      //in short z[x][y] += v[x][y] + ((v[-1][0] + v[+1][0] + v[0][-1] + v[0][+1]) / 4 - v[x][y])
      //scale sin(z) and cos(z) results to 0-255
      rs = sin(z[x][y]) + 1.0;
      gc = cos(z[x][y]) + 1.0;
      rv = rs * 128;
      gv = gc * 128;
      //contrain to 0-255
      if(rv < 0)   rv = 0;
      if(rv > 255) rv = 255;
      if(gv < 0)   gv = 0;
      if(gv > 255) gv = 255;
      //cast to int and shift
      r = ((int)(rv) << 16);
      g = ((int)(gv) << 8);
      //average sin/cos results = use the sin/cos results used for red/green channels, scale them by half (128) brightness and add them up
      //then subtract that from the max (255) to invert the alpha(transparency) value
      int alpha = 255-(int)((rs * 128) + (gc * 128));
      int argb = alpha << 24 | r | g | b;
      canvas.pixels[width*y+x] = argb;
    }
  }
  canvas.updatePixels();
  image(canvas,0,0);
  fill(0);
  text((int)frameRate+"fps",15,15);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void move() {
  if (mouseX > -1    &&    mouseX < width    &&    mouseY > -1    &&    mouseY < height) {
    v[mouseX][mouseY] = randomGaussian() * TAU;

  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseClicked() { move(); }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseDragged() { move(); }


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int screenshotCount=1;
void keyPressed() {
  if (key ==' ') {
    canvas.save("result"+nf(screenshotCount,4)+".png");
    println("screenshot saved");
  }
}

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

Это выглядит как упрощенное моделирование диффузии реакции Бж или Грея Скотта:

просмотр видео на YouTube

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

Даниэль Шиффман Реакция диффузии

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

  1. Распараллелить задачу на GPU, переписав алгоритм в качестве шейдера Processing GLSL (PShader) - кроме того, если вы не возражаете против немного другой реализации, может быть проще настроить шейдерные реакционные диффузионные фрагментные шейдеры для запуска в качестве PShaders (например, этот или этот)
  2. Распараллелить задачу на процессоре (см. Java Multiprocessing resources - sorta dry material)

игрушка шейдерной реакции диффузия 1

игрушка шейдерной реакции диффузия 2

Вы действительно говорите о двух разных вещах:

Первая вещь: сделать цветные капли больше. Это немного раздражает, потому что алгоритм использует массив пикселей, поэтому это не так просто, как вызов scale() функция.

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

некачественно

Решение, которое вы получили на форуме, заключается в использовании закадрового буфера, который фактически не меняет размер больших двоичных объектов. Единственный способ изменить размер BLOB-объектов - это изменить ваш алгоритм.

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

Вещь вторая: экспорт в виде изображения.

Самый простой способ сделать это - просто позвонить save("ImageNameHere.png") функция. Это создаст изображение того же размера, что и ваш эскиз, в котором содержится то, что отображалось на экране при вызове функции.

Решение, которое вы нашли на форуме, использует внеэкранный буфер, но опять же: это не поможет с размером больших двоичных объектов. Вы действительно можете использовать внеэкранный буфер для рисования изображения, которое больше, чем окно эскиза, но это только половина того, что вы хотите. Сохранять этот способ бесполезно, если ваши капли еще маленькие!

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

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