Рубрики
Без рубрики

Воссоздание цифрового искусства (Часть 2)

Это второй пост о моем проекте по воссозданию серии портретов Эспена Клюге с использованием proc… С тегами java, обработка, креатив, графика.

Это второй пост о моем проекте по воссозданию серии портретов Эспена Клюге с использованием обработки с помощью Java. Часть 1 можно найти здесь.

До сих пор мы могли случайным образом разбрасывать точки на рисунке, используя функции loadPixels() и random(), предлагаемые обработкой. Следующим шагом было бы соединить эти случайные точки поперек рисунка, чтобы создать эффект пересекающейся линии в реальном художественном произведении.

Теперь мы должны пройти по всем точкам на рисунке, которые мы установили, и соединить это со всеми остальными. Возможно, есть более быстрый способ достичь всех точек, чем время выполнения O(n^2), но время выполнения не очень важно для моих целей здесь. Следовательно, у нас будет один цикл for, который циклически проходит через наш массив точек, и другой цикл, который создает линию между всеми предыдущими точками перед ним в списке массивов (это позволяет избежать двойного подсчета). Это означает, что мы будем делать 1 + 2 + 3 + … +n строк, что хорошо суммируется как n*(n+1)/2. Это означает O(n^2).

Мой код выглядит так:

PImage portrait;

ArrayList points = new ArrayList(); 
float threshold = .2;

void setup() {
  size(580, 625);
  portrait = loadImage("portrait_technique_0014.png");
  loadPixels();
  portrait.loadPixels();
  for (int i = 0; i < width; i++) {
    for (int j = 0; j < height; j++) {
      Integer loc = i + j*width;
      float r = red(portrait.pixels[loc]);
      float g = green(portrait.pixels[loc]);
      float b = blue(portrait.pixels[loc]);
      if (r > 250 & g > 250 & b > 250) {
      } else {
        float val = random(0, 100);
        if (val < threshold) {
          points.add(new Point(i,j,r,g,b));
        }
      }
      pixels[loc] = color(250, 250, 250);
    }
  }
  updatePixels();

  for (int i = 0; i < points.size(); i++) {
    for (int z = 0; z < i; z++) {
        color c = points.get(i).getColor();
        stroke(c);
        strokeWeight(.5);
        line(points.get(i).getX(), points.get(i).getY(), points.get(z).getX(), points.get(z).getY());
    }
  }
}

Поскольку в оригинальном художественном произведении нет непрерывного рисования, нет необходимости использовать функцию рисования. И вот результат:

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

for (int i = 0; i < points.size(); i++) {
    for (int z = 0; z < i; z++) {
      if (dist(points.get(i).getX(), points.get(i).getY(), points.get(z).getX(), points.get(z).getY()) < 90) {
        color c = points.get(i).getColor();
        stroke(c);
        strokeWeight(.5);
        line(points.get(i).getX(), points.get(i).getY(), points.get(z).getX(), points.get(z).getY());
      }
    }
  }

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

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

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

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

for (int i = 0; i < points.size(); i++) {
    for (int z = 0; z < i; z++) {
      if (dist(points.get(i).getX(), points.get(i).getY(), points.get(z).getX(), points.get(z).getY()) < 90) {
        color a = points.get(z).getColor();
        color b = points.get(i).getColor();
        stroke(b);
        strokeWeight(.85);
        line(points.get(i).getX(), points.get(i).getY(), points.get(z).getX(), points.get(z).getY());
      }
    }
  }

Это дает

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

for (int i = 0; i < points.size(); i++) {
    for (int z = 0; z < i; z++) {
      if (dist(points.get(i).getX(), points.get(i).getY(), points.get(z).getX(), points.get(z).getY()) < 90) {
        color a = points.get(z).getColor();
        color b = points.get(i).getColor();
        stroke(a);
        strokeWeight(.85);
        line(points.get(i).getX(), points.get(i).getY(), points.get(z).getX(), points.get(z).getY());
      }
    }
  }

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

Я думаю, что основа работы Клюга здесь, поскольку цвета в “Альтернативах”, похоже, связаны с его эталонными изображениями, а не с самим кодом. Моя имитация его работы отличается тем, что диапазон цветов ограничен только коричневыми и телесными тонами, а не насыщенными зелеными и красными.

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

И эскиз обработки делает это из этого:

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

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

Вот репозиторий github, если вы тоже хотите его клонировать.

Оригинал: “https://dev.to/christiankastner/recreating-digital-art-part-2-4f29”