Генерация умеренно интересных изображений - PullRequest
22 голосов
/ 09 марта 2010

Аннотация: Можете ли вы предложить математический алгоритм на плоскости пикселей, который будет генерировать умеренно интересное изображение, предпочтительно такое, которое в целом напоминает что-то?

История до сих пор:

Однажды я решил попытаться сократить количество циклов на моих (по общему признанию) многочисленных компьютерах и решил генерировать изображения в умеренно интересной манере; используя PRNG и некоторую умную математику для создания изображений, которые в целом будут напоминать что-то.

Или, по крайней мере, это был план. Как оказалось, умная математика требует умного математика; это не я.

В какой-то степени я пришел к методу, который предпочитал прямые линии (поскольку это, как правило, компоненты, из которых состоит наш мир), возможно, слишком сильно. Результат слегка интересно; напоминающие, возможно, городские сетки как таковые:

Городские сетки, может быть? http://totlandweb.info/imggen.out.png

Теперь к собственно вопросу: приведен исходный код этой маленькой программы; Можете ли вы улучшить его и предложить метод, который дает несколько более интересные результаты? (например, не городские сетки, а, возможно, лица, животные, география, что у вас)

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

  1. Комментарии в коде говорят все на самом деле. Предложения и «решения» должны редактировать сам алгоритм, а не окружающий фреймворк, кроме как для исправления ошибки, препятствующие компиляции образца.

  2. Код должен быть аккуратно скомпилирован с помощью стандартного компилятора языка C. (Если пример, приведенный не, упс! Скажи мне, и я исправлю. :)

  3. Метод должен, хотя, опять же, это не является обязательным, не нужно вызывать помощь от вашей дружественной математической библиотеке соседства, и в целом используйте (P) RNG в качестве его первичный канал ввода данных.

  4. Решения, вероятно, должны быть доставлены простым извлечением всего, что находится между отрывочные строки (те, которые говорят, что вы не должны редактировать выше и ниже соответственно), с заявлением о том, что вам нужно добавить к преамбуле, в частности.

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

Код требует компилятора C и libpng для сборки; Я не совсем уверен, что компилятор MinGW обеспечивает все необходимое, но я был бы удивлен, если бы этого не произошло. Для Debian вам понадобится пакет libpng-dev, а для Mac OS X - инструменты XCode.

Исходный код можно скачать здесь .

Предупреждение: Массивная ошибка кода!

// compile with gcc -o imggen -lpng imggen.c
// optionally with -DITERATIONS=x, where x is an appropriate integer
// If you're on a Mac or using MinGW, you may have to fiddle with the linker flags to find the library and includes.

#include <stdio.h>
#include <stdlib.h>
#include <png.h>

#ifdef ITERATIONS
#define REPEAT
#endif // ITERATIONS

// YOU MAY CHANGE THE FOLLOWING DEFINES
#define WIDTH 320
#define HEIGHT 240

// YOU MAY REPLACE THE FOLLOWING DEFINES AS APPROPRIATE
#define INK 16384

void writePNG (png_bytepp imageBuffer, png_uint_32 width, png_uint_32 height, int iteration) {
  char *fname;
  asprintf(&fname, "out.%d.png", iteration);

  FILE *fp = fopen(fname, "wb");
  if (!fp) return;
  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  png_infop  info_ptr = png_create_info_struct(png_ptr);
  png_init_io(png_ptr, fp);
  png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, PNG_FILTER_NONE);
  png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
  png_set_IHDR(png_ptr, info_ptr, width, height, 8,
               PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  png_set_rows(png_ptr, info_ptr, imageBuffer);
  png_set_invert_mono(png_ptr); /// YOU MAY COMMENT OUT THIS LINE
  png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
  png_destroy_write_struct(&png_ptr, &info_ptr);
  fclose(fp);
  free(fname);
}

int main (int argc, const char * argv[]) {
  png_uint_32 height = HEIGHT, width = WIDTH;


  int iteration = 1;
#ifdef REPEAT
  for (iteration = 1; iteration <= ITERATIONS; iteration++) {
#endif // REPEAT  

    png_bytepp imageBuffer = malloc(sizeof(png_bytep) * height);
    for (png_uint_32 i = 0; i < height; i++) {
      imageBuffer[i] = malloc(sizeof(png_byte) * width);
      for (png_uint_32 j = 0; j < width; j++) {
        imageBuffer[i][j] = 0;
      }
    }    

    /// CUT ACROSS THE DASHED LINES
    /// -------------------------------------------
    /// NO EDITING ABOVE THIS LINE; EXCEPT AS NOTED

    int ink = INK;
    int x = rand() % width, y = rand() % height;

    int xdir = (rand() % 2)?1:-1;
    int ydir = (rand() % 2)?1:-1;

    while (ink) {
      imageBuffer[y][x] = 255;
      --ink;
      xdir += (rand() % 2)?(1):(-1);
      ydir += (rand() % 2)?(1):(-1);
      if (ydir > 0) {
        ++y;
      } else if (ydir < 0) {
        --y;
      }
      if (xdir > 0) {
        ++x;
      } else if (xdir < 0) {
        --x;
      }
      if (x == -1 || y == -1 || x == width || y == height || x == y && x == 0) {
        x = rand() % width; y = rand() % height;
        xdir = (rand() % 2)?1:-1;
        ydir = (rand() % 2)?1:-1;
      }
    }

    /// NO EDITING BELOW THIS LINE
    /// -------------------------------------------

    writePNG(imageBuffer, width, height, iteration);

    for (png_uint_32 i = 0; i < height; i++) {
      free(imageBuffer[i]);
    }    
    free(imageBuffer);
#ifdef REPEAT
  }
#endif // REPEAT
  return 0;
}

Примечание: Хотя этот вопрос, строго говоря, не кажется "ответственным" как таковой; Я все еще верю, что это может привести к какому-то «правильному» ответу. Может быть.

Счастливой охоты.

Редактировать (снова): Исходный код для упрощенных путей Безье, использованных в моем ответе (читать), можно найти здесь и здесь .

Ответы [ 6 ]

10 голосов
/ 09 марта 2010

Фракталы ? Они больше не только для анализа фондовых рынков ( шутка Мандельброта , извините).

Некоторые Фрактальные изображения , как правило, напоминают географию реального мира. В частности, IFS фракталы можно использовать для довольно реалистичных растений и деревьев и рельефа .

fractal.c - это простой монохромный набор Мандельброта с масштабом по умолчанию.


Добавлено:

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

2-е дополнение:

Другая основная форма алгебраического или вычислительного искусства принадлежит Сотовому автомату (CA), такому как (Джон) Игра жизни Конвея , прославившемуся 1970 Scientific American статья, написанная Мартином Гарднером. CA был вновь представлен публике после публикации Стивеном Вольфрамом A New Kind of Science (NKS) в 2002 году. Это, как правило, закрытые динамические системы, которые «живут» или «умирают» на основе простой набор правил.

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

2 голосов
/ 12 марта 2010

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

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

2 голосов
/ 09 марта 2010

Хммм. Я помню, как создавал генератор страны в логотипе давным-давно. Основная стратегия заключалась в том, чтобы закрасить его художником для каждого цвета и установить правило: «Художники по цвету перемещаются случайным образом, но не могут перемещаться по любой области, которая окрашена, если она не окрашена в свой собственный цвет». Результатом было несколько смежно окрашенных участков. Художники перемещались случайным образом в 4 направлениях, и размер сетки составлял примерно 50х50.

Когда я закончил, я взял свое изображение 50x50, расширил его (с ближайшим соседом) до чего-то намного большего и использовал некоторые стандартные графические фильтры (размытие и тому подобное), чтобы оно выглядело прилично. Если вам нужно монохромное изображение, просто сделайте все границы черными, а все остальное белым.

Эта стратегия вообще не поддерживает прямые линии.

1 голос
/ 09 марта 2010

Вместо прямой случайности вы можете добавить к поведению какое-то тривиальное состояние. Например, вместо выбора того, что x и y делают на основе P, где P по существу rand % 2, вы можете выбрать их на основе условного уравнения. В качестве простого примера:

двухстороннее http://img121.imageshack.us/img121/9018/twostate.png

Если вы позволите состоянию 1 представлять «поддерживать текущий путь», а 0 - «изменить направление», то, регулируя порог Q, вы контролируете частоту, с которой вы меняете направление. Добавление состояний добавляет сложности, но вы, вероятно, получите умеренно интересные результаты с тщательно подобранными значениями для P и Q.

1 голос
/ 09 марта 2010

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

Возьмите сетку (постройте ее из квадратов, шестиугольников или чего-то еще) и сгенерируйте случайное поле точек на ней. Теперь рассмотрим все возможные способы соединения этого фиксированного набора точек, используя линии, которые следуют за сеткой. Возьмите фрагменты картинок с похожей темой (например, листья) и преобразуйте их в стиль «штриховой рисунок», чтобы уменьшить их до контура. Для каждого набора из нескольких точек просмотрите свою библиотеку частей контура и попытайтесь найти ту, которая может соединить точки (или, по крайней мере, приблизиться, это может потребовать поворота, зеркального отображения и т. Д.). Вы найдете множество возможных выходов, но если все сделано правильно, у вас может получиться множество листьев, которые выглядят как листья (даже если это «новые» типы листьев, которых раньше никогда не видели)!

0 голосов
/ 12 марта 2010

В духе полного разрушения моих собственных (по общему признанию произвольных правил, я пошел прямо вперед и сам создал ответ!

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

В дополнение к редактированию поля отсечения я также добавил, конечно,

#include "bezier.h"

Без этой строки работать не очень хорошо. ;)

/// NO EDITING ABOVE THIS LINE; EXCEPT AS NOTED

Bezier *path = newBezier(newPoint(rand() % width,rand() % height), newPoint(rand() % width,rand() % height), newPoint(rand() % width,rand() % height), newPoint(rand() % width,rand() % height));

float t;
Point *point = NULL;

for (t = 0.0; t <= 1.0; t += 0.00000006) {
  point = bezierPoint(path, t, point);

  int32_t x = point->x, y = point->y;

  if (x >= 0 && x < width && y >= 0 && y < height)
    imageBuffer[y][x] = 255;
}

destroyPoint(point);

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