【问题标题】:Randomness of Python's randomPython的随机性的随机性
【发布时间】:2019-09-19 21:18:25
【问题描述】:

我正在使用 Python 生成图像,并使用虚线进行点画。划线的周期是恒定的,改变的是划线/空间比。这会产生这样的结果:

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

想知道这是从哪里来的,我做了一个非常简单的测试用例,上面有堆叠的虚直线:

  • 冲刺比:50%
  • 短划线周期 20px
  • 使用random.uniform(-10.,+10.)(*) 将原点从-10px 转移到+10px(在初始random.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()

【问题讨论】:

  • 这并不能完全回答您的问题,但很有趣且相关:stackoverflow.com/questions/7029993/…
  • 也许您可以创建一个minimal reproducible example,它允许其他人重现您的简单测试用例。仅根据您的描述,我不确定图像是如何生成的。
  • @JohnColeman 添加了代码。一条线是在 orign 0 处的线的随机移动。我不会将线从一条移动到下一条(但可能我应该这样做)
  • @JohnColeman 破折号从每行的起点开始。上一行没有结转(使用不分割图像宽度的破折号很容易检查)
  • 这个话题在这个 Youtube 视频“Randomness is Random - Numberphile”中被谈论。基本上,您希望 0 和 1 的随机序列为 010101 ...,即 (01)+,但事实并非如此。

标签: python random


【解决方案1】:

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

编辑:我看到我有点误解了,所有的破折号都是 20px 的随机偏移量。因此,我认为查看任何一组垂直破折号都会显得随机,但相同的随机组会在整个页面中重复出现,从而给出模式。

【讨论】:

  • 如果您显示一个图表来展示掷多个骰子时的总数概率,这个答案将非常强大。
  • 称为中心极限定理。你可以阅读它here,或者自己谷歌它。所以是的,随着您逐步对一组随机数求和,该总和将越来越多normal
  • “当您将随机元素添加在一起时,随机性会减少”:不,但是随着您平均越来越多的随机元素,均值的方差会减小。总和的方差增加。
【解决方案2】:

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

换个角度看——如果您打印出图像,确实有较长的白色通道,您可以通过这些通道轻松地用钢笔画一条线。为什么你的大脑不应该感知它们?

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

【讨论】:

  • 确实如此。即便如此,大脑还是很擅长忽略完全不同相的一条线。
  • 按照你的推理,最终最好的方法是完全没有随机性。
  • @xenoid 我在编写光线追踪器时对此进行了研究。有一些算法专门设计用于产生“良好的视觉噪音”,模仿我们眼睛的设计方式。您可以搜索Poisson-Disc sampling 之类的内容。结果远远优于正常的随机抽样。
  • @pipe 不确定我可以在这里使用它,但对我的另一个宠物实验很感兴趣。
【解决方案3】:

我们在“随机”图片中看到一种模式至少有一个明显的原因:400x400 像素就是重复 20 次的同一个 20x400 像素。

所以每一个明显的动作都会并行重复 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))

【讨论】:

  • 在我的最终解决方案中,我仍然有一个规则的垂直图案,而且不那么明显。有一个可变周期不是一个坏主意,但如果不严重增加处理时间,这对于我使用的 API 是不可行的。
  • @xenoid:感谢您的评论。可能有一些聪明的方法可以一次性为整个表生成可变周期。顺便说一句,有趣的问题!
【解决方案4】:

发布我的最终解决方案作为答案,但请为其他人投票。

John Coleman 说得有道理:

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

所以,最后,避免排水沟的最佳方法是放弃随机性并有一个非常固定的班次方案,效果很好的是 4 阶段 0,25%,75%,50% 循环:

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

【讨论】:

  • 除了循环之外,您还可以通过在每行添加少量随机性来改善这一点。对于您的 4 个周期,它可能约为 0-12.5%
  • 这是比 OP 中的图像分辨率更低的图像,对吧?它如何看待更高的分辨率/字符密度?
  • @Baldrickk 不,相同大小,只需单击它即可获得全尺寸 (970x545)
  • 啊好吧,只是看起来更稀疏了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多