问题 在640 x 360维度生成所有可能的黑白像素图像的算法?


我的编程经验非常少。

我想编写一个程序,生成并保存为gif图像的每个可能的图像,只能使用640 x 360像素尺寸的黑白像素。

换句话说,每个像素可以是黑色或白色。 640 x 360 = 230,400像素。所以我相信总共可以生成460,800张图像(黑色/白色为230,400 x 2)。

我想要一个程序自动执行此操作。

请帮忙!


5094
2017-12-10 00:46


起源

你实际上正在生成2 ^ 230,400个图像,因为你只计算了可能打开的像素数量,并将其加倍,这只是两个图像(一个全黑,一个全白),或实际上是一个排列和它的逆 - damienc88
您是否正在尝试创建一种新类型的条形码,它将对我们星球上的每个原子进行编目? - RustyToms
它是2 ^ 230400,而不是230500 ^ 2 - justhalf
是的,每个像素可以是黑色或白色。如果只有3个像素,则有8个组合(000,001,010,011,100,101,110,111),即2x2x2。如果你有230400像素,你有2 ^ 230400,根据 WolframAlpha的 它长69,358位 - justhalf
有人为此设定了赏金。 - RustyToms


答案:


首先回答你的问题。是的,会有关于“一些”图片的文章。实际上,人类写的适合640x360像素的文字会出现。还有其他所有文本(尚未写入的文本或永远不会被写入的文本)。你也会看到每个人的照片,现在或将要活着。看到 无限猴子定理 了解更多信息。

创建你想要的gif的代码相当容易。我为此使用了Java。请注意,您需要额外的课程: AnimatedGifEncoder。代码不受内存限制,因为 AanimatedGifEncoder 将在计算后立即将每个映像写入磁盘。但请确保您有足够的可用磁盘空间。

import java.awt.Color;
import java.awt.image.BufferedImage;

public class BigPicture {
    private final int width;
    private final int height;

    private final int WHITE = Color.WHITE.getRGB();
    private final int BLACK = Color.BLACK.getRGB();

    public BigPicture(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public void process(String outFile) {
        AnimatedGifEncoder gif = new AnimatedGifEncoder();
        gif.setSize(width, height);
        gif.setTransparent(null); // no transparency
        gif.setRepeat(-1); // play only once
        gif.setDelay(0); // 0 ms delay between images,
                         // 'cause ain't nobody got time for that!
        gif.start(outFile);
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);

        // set the image to all white
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                bufferedImage.setRGB(x, y, WHITE);
            }
        }

        // add white image
        gif.addFrame(bufferedImage);

        // add all other combinations
        while (increase(bufferedImage)) {
            gif.addFrame(bufferedImage);
        }

        gif.finish();
    }

    /**
     * @param bufferedImage
     *            the image to increase
     * @return false if last pixel set to black => image is complete black
     */
    private boolean increase(BufferedImage bufferedImage) {
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                if (bufferedImage.getRGB(x, y) == WHITE) {
                    bufferedImage.setRGB(x, y, BLACK);
                    return true;
                }
                bufferedImage.setRGB(x, y, WHITE);
            }
        }
        return false;
    }

    public static void main(String[] args) {
        new BigPicture(640, 360).process("C:\\temp\\bigpicture.gif");
        System.out.println("finished.");
    }
}

请注意,这需要一些时间。所以不要打扰等待,享受你的生活! ;)

编辑:由于我的解决方案有点不清楚,我会解释算法。

  1. 我已经定义了一个名为的方法 increase。此方法采用BufferedImage并更改图像的位模式,以便显示下一个位模式。该方法只是一点点补充。该方法将返回 false 如果图像遇到最后一位模式(所有像素都设置为黑色)。
  2. 只要有可能增加位模式(即 increase() 返回true)我们将图像保存为新帧并再次增加图像。
  3. 怎么了 increase() 方法有效:该方法首先在x方向上运行,然后在y方向上运行。我假设白色像素是 0 和黑色像素 1。所以,我们想要采用图像的位模式并添加 1。我们检查第一个像素:如果它是白色的(0)我们可以添加 1 没有溢出所以我们把像素变成黑色(0 + 1 = 1 =>黑色像素)。之后我们从方法返回,因为我们只想增加一个位置。它回来了 true 因为增加是可能的。如果我们遇到黑色像素,我们会溢出(1 + 1 = 2 或二进制 10)。所以我们必须将当前像素设置为白色并添加 1 到下一个像素。这将持续到我们找到第一个白色像素。

: 首先我们创建一个print方法:此方法将图像打印为二进制数。注意数字是相反的,最重要的位是右侧的位。

public void print(BufferedImage bufferedImage) {
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            if (bufferedImage.getRGB(x, y) == WHITE) {
                System.out.print(0); // white pixel
            } else {
                System.out.print(1); // black pixel
            }
        }
    }
    System.out.println();
}

现在我们修改main-while循环:

print(bufferedImage); // this one prints the empty image
while (increase(bufferedImage)) {
    print(bufferedImage);
}

现在设置一些简短的例子来测试:

new BigPicture(1, 5).process("C:\\temp\\bigpicture.gif");

最后输出:

00000 // 0 this is the first print before the loop -> "white image"
10000 // 1 the first white pixel is set to black
01000 // 2 the first overflow, so the second pixel is set to black "2"
11000 // 3
00100 // 4
10100 // 5
01100
11100
00010 // 8
10010
01010
11010
00110
10110
01110
11110
00001 // 16
10001
01001
11001
00101
10101
01101
11101
00011
10011
01011
11011
00111
10111
01111
11111 // 31 == 2^5 - 1
finished.

8
2018-04-01 13:14



what-if.xkcd.com/34 - Christian Landgren
这不会呈现所有可能的像素组合。这只会一次打开一个像素!所以你的动画gif基本上会从左到右依次移动一个点...... - Adrian Salazar
@AdrianSalazar我测试了它,它按预期工作,但随意指出我的错误。 - Absurd-Mind
@Absurd-记住,你的错误很容易证明。两个嵌套的fors将给出宽度x高度的图像数量。不是2 ^宽度^高度。 - Adrian Salazar
@Absurd-Mind和“我测试过它”几乎不是真的。你不能等待这么多的图像被输出。 - Adrian Salazar


换句话说,每个像素可以是黑色或白色。 640 x 360 =   230,400像素。所以我相信总共有460,800张图片是可能的   生成(黑色/白色230,400 x 2)。

你的信念有一点缺陷。你的像素数是对的:230,400。不幸的是,这意味着没有2 * 230,400,但是2 ^ 230,400张可能的图片,这是一个超过60,000位的数字(恐怕比允许的答案大小更长)。为了比较,具有45位数的特定数字表示可观察宇宙的直径(以厘米为单位)(大致为小指的宽度)。

为了理解为什么你的图片数量计算错误,请考虑这个例子:如果你的图片只包含三个像素,你可以有8个不同的图片(2 ^ 3),而不是6(2 * 3)。以下是所有这些:BBB,BBW,BWB,BWW,WBB,WBW,WWB,WWW。添加另一个像素会使可能的图片大小翻倍,因为所有3像素的情况都可以为白色,而对于所有3像素的情况,可以为黑色。加倍1(这是你可以拥有0像素的图片数量)230,400次给你2 ^ 230,400。

对这个问题有一个赏金很好,但如果它像四月的傻瓜笑话一样,那就相当分散注意力并适得其反。


4
2018-04-04 14:46





我将继续前进并从相关问题中捏一些代码,只是为了好玩。

from itertools import product
for matrix in product([0, 1], repeat=(math,pow(2,230400)):
    # render and save your .gif

正如所有评论已经说明的那样,祝你好运!

更严重的是,如果你不想绝对确定你有所有的排列,你可以生成一个随机的640x360矩阵并将其存储为图像。

执行此操作说100k次,你将至少看到一组有趣的图片,但是获得所有可能的排列是不可行的。

然后,您可以删除所有相同的文件,以将设置简化为唯一的图像。


2
2017-12-10 01:17



大声笑会炸毁我的电脑吗? - user3084984