Python的随机性


71

我正在使用Python使用虚线为点画生成图像。破折号的周期是恒定的,改变的是破折号/空间比。这将产生如下内容:

在此处输入图片说明

但是,在该图像中,虚线具有统一的原点,这会产生难看的垂直装订线。因此,我尝试将原点随机化以去除排水沟。这种工作,但有一个明显的模式:

在此处输入图片说明

我想知道这是从哪里来的,所以我制作了一个非常简单的测试用例,用堆叠的虚线表示:

  • 冲刺率:50%
  • 破折号20px
  • 使用random.uniform(-10.,+10.)(*)(初始值后,原点从-10px变为+ 10pxrandom.seed()

在此处输入图片说明

并增加了随机性:

在此处输入图片说明

因此仍然存在模式。我不明白的是,要获得可见的装订线,您需要使6个或7个连续值落入同一范围内(例如,总范围的一半),这应该是1/64的概率,但是似乎发生了很多通常会在200行中生成。

我误会了吗?只是我们的人类大脑正在看到没有模式的模式吗?是否有更好的方法来生成更“视觉上随机的”东西(python 2.7,最好不安装任何东西)?

(*)部分像素在这种情况下有效

附件:我使用的代码(这是一个Gimp脚本):

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

# Python script for Gimp (requires Gimp 2.10)
# Run on a 400x400 image to see something without having to wait too much
# Menu entry is in "Test" submenu of image menubar

import random,traceback
from gimpfu import *

def constant(minShift,maxShift):
    return 0

def triangle(minShift,maxShift):
    return random.triangular(minShift,maxShift)

def uniform(minShift,maxShift):
    return random.uniform(minShift,maxShift)

def gauss(minShift,maxShift):
    return random.gauss((minShift+maxShift)/2,(maxShift-minShift)/2)

variants=[('Constant',constant),('Triangle',triangle),('Uniform',uniform),('Gauss',gauss)]

def generate(image,name,generator):
    random.seed()
    layer=gimp.Layer(image, name, image.width, image.height, RGB_IMAGE,100, LAYER_MODE_NORMAL)
    image.add_layer(layer,0)
    layer.fill(FILL_WHITE)
    path=pdb.gimp_vectors_new(image,name)

    # Generate path, horizontal lines are 2px apart, 
    # Start on left has a random offset, end is on the right edge right edge
    for i in range(1,image.height, 2):
        shift=generator(-10.,10.)
        points=[shift,i]*3+[image.width,i]*3
        pdb.gimp_vectors_stroke_new_from_points(path,0, len(points),points,False)
    pdb.gimp_image_add_vectors(image, path, 0)

    # Stroke the path
    pdb.gimp_context_set_foreground(gimpcolor.RGB(0, 0, 0, 255))
    pdb.gimp_context_set_stroke_method(STROKE_LINE)
    pdb.gimp_context_set_line_cap_style(0)
    pdb.gimp_context_set_line_join_style(0)
    pdb.gimp_context_set_line_miter_limit(0.)
    pdb.gimp_context_set_line_width(2)
    pdb.gimp_context_set_line_dash_pattern(2,[5,5])
    pdb.gimp_drawable_edit_stroke_item(layer,path)

def randomTest(image):
    image.undo_group_start()
    gimp.context_push()

    try:
        for name,generator in variants:
            generate(image,name,generator)
    except Exception as e:
        print e.args[0]
        pdb.gimp_message(e.args[0])
        traceback.print_exc()

    gimp.context_pop()
    image.undo_group_end()
    return;

### Registration
desc="Python random test"

register(
    "randomize-test",desc,'','','','',desc,"*",
    [(PF_IMAGE, "image", "Input image", None),],[],
    randomTest,menu="<Image>/Test",
)

main()

1
这不能完全回答您的问题,但很有趣且相关:stackoverflow.com/questions/7029993/…
SuperShoot,

也许你可以做一个 最小的可重现示例,使其他人可以重现您的简单测试用例。仅根据您的描述,我不确定如何生成图像。
约翰·科尔曼

@JohnColeman添加了代码。一条线是在原始点0处的线的随机移位。我不会将线从一条线移到另一条线(但我应该是)
xenoid

1
@JohnColeman虚线从每行的起点开始。前一行没有
残留

1
这个主题在YouTube视频“随机性是随机的-嗜好者”中谈论的。基本上,您希望0和1的随机序列为010101 ...,即(01)+,但不是。
alecail

Answers:


47

这样想:直到排水沟被阻塞(或几乎被阻塞)之前,它是可以感知的。仅当两条连续的线几乎完全异相时才发生这种情况(第一行中的黑色部分几乎位于下一条白色部分的上方)。这样的极端情况每10排中只有大约1排发生,因此可见的水槽在被阻塞之前似乎延伸了10排。

换一种方式来看-如果您打印出图像,则确实存在长长的白色通道,通过这些通道您可以轻松地用笔画一条线。为什么您的大脑不应该感知它们?

为了获得更好的视觉随机性,请找到一种使连续线条相互依赖的方法而不是相互独立,这样几乎会出现异相行为。


7
确实。即使那样,大脑也很擅长忽略完全异相的一条线。
艾里克·杜米尼尔

3
按照您的推理,最终最好的方法就是完全没有随机性。
xenoid

1
@xenoid我在编写光线追踪器时对此进行了研究。有专门设计用于生成“良好视觉噪声”的算法,该算法模仿了我们眼睛的设计方式。您可以搜索类似Poisson-Disc采样的东西。结果远远好于正常的随机抽样。

@pipe不确定我可以在这里使用它,但是对我的另一个宠物实验很有趣。
xenoid

27

我们在“随机”图片中看到图案的原因至少有一个显而易见的原因:400x400像素与20x400像素重复20次相同。

在此处输入图片说明

因此,每个明显的动作都平行重复20次,这确实有助于大脑分析图像。

实际上,相同的10px宽的图案会重复40次,黑白交替:

在此处输入图片说明

您可以为每行分别随机设置破折号周期(例如12和28之间):

在此处输入图片说明

这是相应的代码:

import numpy as np
import random

from matplotlib import pyplot as plt
%matplotlib inline
plt.rcParams['figure.figsize'] = [13, 13]

N = 400

def random_pixels(width, height):
    return np.random.rand(height, width) < 0.5

def display(table):
    plt.imshow(table, cmap='Greys', interpolation='none')
    plt.show()

display(random_pixels(N, N))

def stripes(width, height, stripe_width):
    table = np.zeros((height, width))
    cycles = width // (stripe_width * 2) + 1
    pattern = np.concatenate([np.zeros(stripe_width), np.ones(stripe_width)])
    for i in range(height):
        table[i] = np.tile(pattern, cycles)[:width]
    return table

display(stripes(N, N, 10))

def shifted_stripes(width, height, stripe_width):
    table = np.zeros((height, width))
    period = stripe_width * 2
    cycles = width // period + 1
    pattern = np.concatenate([np.zeros(stripe_width), np.ones(stripe_width)])
    for i in range(height):
        table[i] = np.roll(np.tile(pattern, cycles), random.randrange(0, period))[:width]
    return table

display(shifted_stripes(N, N, 10))

def flexible_stripes(width, height, average_width, delta):
    table = np.zeros((height, width))
    for i in range(height):
        stripe_width = random.randint(average_width - delta, average_width + delta)
        period = stripe_width * 2
        cycles = width // period + 1
        pattern = np.concatenate([np.zeros(stripe_width), np.ones(stripe_width)])
        table[i] = np.roll(np.tile(pattern, cycles), random.randrange(0, period))[:width]
    return table

display(flexible_stripes(N, N, 10, 4))

1
在我的最终解决方案中,我仍然具有规则的垂直图案,并且看不见得多。具有可变的时间段不是一个坏主意,但这对于我使用的API来说是不可行的,而不会严重增加处理时间。
xenoid

@xenoid:感谢您的评论。可能有一些聪明的方法可以在整个过程中单次生成可变周期。有趣的问题顺便说一句!
埃里克·杜米尼尔

9

将我的最终解决方案发布为答案,但是请支持其他人。

约翰·科尔曼(John Coleman)有话要说:

为了获得更好的视觉随机性,请找到一种方法,使连续的行相互依存,而不是相互独立,这样几乎会出现异相行为。

因此,最后,避免发生混乱的最佳方法是放弃随机性,并采用非常固定的移位方案,而效果很好的方案是4相0.25%,75%,50%周期:

在此处输入图片说明

好的,仍然有轻微的菱形图案,但是它比我尝试的随机方案引入的图案要少得多。


1
您可以通过在周期之外为每行添加少量随机性来改善这一点。对于您的4个周期,可能约为0-12.5%
迈克尔·安德森

这是比OP中的分辨率低的图像,对不对?如何看待更高的分辨率/字符密度?
鲍德里克

@Baldrickk不,相同大小,只需点击以查看完整大小(970x545)
Xenoid

嗯,看起来比较稀疏。
鲍德里克

7

这有点违反直觉,但是当您将随机元素加在一起时,随机性就会变小。如果我正确遵循,则每个元素的范围是10px-30px。因此,10个元素的总大小为100像素到300像素,但是分布甚至不在该范围内。极端情况不太可能发生,平均而言,它将接近200像素,因此将出现基本的20像素模式。您的随机分布需要避免这种情况。

编辑:我看到我有点误解了,所有的破折号都是20px具有随机偏移量。因此,我认为查看任意1个垂直破折号看起来都是随机的,但是在页面上重复相同的随机破折号,得到了图案。


如果您显示一个图表,该图表演示投掷多个骰子时总计的概率,则此答案将非常有用。
亚当·巴恩斯

3
这称为中央极限定理。您可以在此处阅读或自己搜索。所以是的,随着您不断地对一组随机数求和,该和将变得越来越正常
David Culbreth

3
“当你添加随机元素结合在一起的随机性变得少”:没有,但你平均越来越多的随机因素,平均跌幅的差异。总和的方差增加。
悬崖AB
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.