生成适度有趣的图像

时间:2010-03-08 21:39:30

标签: c

摘要:你能否在一个像素平面上提出一个数学-theh算法,这个算法会生成一个中等有趣的图像,最好是一个总体上类似的图像?

到目前为止的故事:

曾几何时,我决定努力减少我(无可否认的)众多计算机上的周期浪费,并着手以适度的方式生成图像。使用PRNG和一些聪明的数学来创建整体上类似于的图像。

或者至少,那是计划。事实证明,聪明的数学需要成为一个聪明的数学家;我不是。

在某种程度上,我找到了一种偏好直线的方法(因为这些通常是我们世界的组成部分),可能过于强烈。结果是温和地有趣;或许像城市网格一样:

City grids, maybe? http://totlandweb.info/imggen.out.png

现在问题是正确的:给出这个小程序的源代码;你可以改进它并提出一种方法,给出更有趣的结果吗? (例如,不是城市网格,但也许是面孔,动物,地理,你有什么)

这也是一种挑战;我想,因此我已经制定了一些完全随意且同样可选的规则:

  1. 代码中的注释说明了这一切。建议和“解决方案”应该  编辑算法本身,而不是周围的框架,除了修复  阻止样本编译的错误。

  2. 代码应该使用标准问题C编译器干净地编译。 (如果  提供的示例没有,哎呀!告诉我,我会解决的。 :)

  3. 该方法应该是可选的,不需要从中获取帮助  您友好的邻居数学图书馆,并且整体上使用(P)RNG作为其  主要数据输入渠道。

  4. 解决方案应该可以通过简单地解决之间的任何问题来实现  剪辑线(表示你不应分别在上方和下方编辑的那些),  声明你需要特别添加到序言中的内容。

  5. 编辑:有时很容易忘记互联网上的人无法阅读我的内容  心神;但你去了。该计划应该至少需要人为干预  生成图像,除了评估结果并选择最佳  的。

  6. 代码需要C编译器和libpng来构建;我不完全相信MinGW编译器提供了必需品,但如果没有,我会感到惊讶。对于Debian,你需要libpng-dev软件包,对于Mac OS X,你需要XCode工具..

    源代码可以是downloaded here

    警告:大量代码挥霍传入!

    // 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;
    }
    

    注意:虽然严格来说这个问题似乎并不是“可回答的”;我仍然认为它可以产生一些“正确”的答案。也许

    快乐狩猎。

    编辑(再次):我的答案(读下)中使用的简单bezier路径的源代码可以找到herehere

6 个答案:

答案 0 :(得分:10)

Fractals?它们不再仅仅用于股票市场分析(Mandelbrot joke,对不起)。

有些Fractal images往往让人联想到现实世界的地理位置。特别是IFS分形可用于相当逼真的plantstrees以及terrain

fractal.c是一个简单的单色Mandelbrot集,默认为缩放。


添加了:

Context-free语法可用于表达能够绘制出美学上令人愉悦的图像的方程式。 Jared Tarbell有一个由程序生成的一些精彩图像的相关图库。 AzaAlgorithm Ink

第二次补充:

代数或计算艺术的另一种主要形式来自Cellular automaton(CA),例如(John)Conway's Game of Life,由Martin Gardner撰写的1970 Scientific American文章着称。 2002年,斯蒂芬·沃尔夫勒姆(Stephen Wolfram)自我出版A New Kind of Science(NKS),将CA重新引入公众。这些系统往往是封闭的动态系统,基于一套简单的规则“活”或“死”。

与分形相关的是chaotic systems,或非线性动态系统,如果你想听起来很聪明。它们可以在物理系统上建模,例如weather forecasting,并且可以提供非真实随机但难以预测的数字输出,可以将其显示为strange attractor(和SA) 。

答案 1 :(得分:2)

嗯。我记得很久以前在徽标中制作了一个国家发电机。基本的策略是用每种颜色的画家播种它,并有规则,“颜色画家,随机移动,但可能不会在任何被绘制的区域移动,除非它是用自己的颜色绘制的。”结果是几个连续绘制的区域。画家在4个方向上随机移动,网格大小为50x50左右。

一旦完成,我拍摄了我的50x50图像,将它(与最近邻居)扩展为更大的图像,并使用一些标准图形滤镜(模糊等)使其看起来不错。如果你想要一个单色图像,只需将任何边框变成黑色,其他所有边框都变白。

这种策略根本不支持直线。

答案 2 :(得分:2)

你问的问题是审美。一个人认为“好”或“美丽”或“适度有趣”的事物因人而异,我认为不能找到最佳答案。

我知道很多人会发现你在问题中发布的图片令人作呕而且毫无根据,充斥着城市规划的社会政治束缚的想法。但是,认为它看起来很有趣。

答案 3 :(得分:1)

这可能是解决问题的必然结果,而不是解决问题的方法,但我从不同角度看待同样的想法后看到了有趣的结果:

取一个网格(从正方形,六边形或有你的东西构建它)并在其上生成一个随机的点域。现在,检查使用网格后面的行连接固定点集的所有可能方法。拍摄具有相似主题的图片(例如,树叶)的片段,并将它们转换为“线条艺术”样式以将它们缩小为轮廓。对于每组几个点,查看您的大纲片段库并尝试找到一个可以连接点(或至少靠近,这可能需要旋转,镜像等)。您会发现有无数可能的输出,但如果正确完成,您最终可能会看到许多看似叶子的东西(即使它们是以前从未见过的'新'叶子类型)!

答案 4 :(得分:1)

您可以为行为添加一些琐碎的状态,而不是直接随机性。例如,您可以根据条件方程式选择它们,而不是根据x y基本上P来选择Prand % 2做什么。举个简单的例子:

two-state http://img121.imageshack.us/img121/9018/twostate.png

如果您允许状态1表示“保持当前路径”并且0为“更改方向”,则通过调整Q阈值来控制更改方向的频率。添加状态会增加复杂性,但通过为PQ精心选择的值,您可能会得到适度有趣的结果。

答案 5 :(得分:0)

本着彻底粉碎自己的精神(公认的任意规则,我已经走在前面,自己创造了一个答案!

代码使用了一些非常简单的bezier曲线代码,我昨晚把它拼凑在一起,虽然答案不那么引人注目,但它仍然有点有趣。可以在herehere找到贝塞尔码的代码。

除了编辑剪辑字段外,我当然还添加了

#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