首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在numpy数组上迭代的更快方法

在numpy数组上迭代的更快方法
EN

Stack Overflow用户
提问于 2022-01-17 07:06:04
回答 1查看 102关注 0票数 0

我有一个非常大的数组,需要迭代。数组是一个大的tiff图像,而不是一个颜色值,我想添加一个4-4位的2d模式。我的代码现在看起来是这样的。它需要很长时间才能完成。tiff是一个数组(x,y,4)。X和y很大。value是一个包含与我正在搜索的值相匹配的模式的列表,并提供给我索引。模式是由4-4个模式组成的数组。谢谢

代码语言:javascript
复制
for iy, ix in np.ndindex(tiff[:, :, 0].shape):
    tiff[iy, ix, 0] = np.random.choice(np.argwhere(Values == tiff[iy, ix, 0])[:, 0], 1, replace=False)
    tiff[iy, ix, 1] = np.random.choice(np.argwhere(Values == tiff[iy, ix, 1])[:, 0], 1, replace=False)
    tiff[iy, ix, 2] = np.random.choice(np.argwhere(Values == tiff[iy, ix, 2])[:, 0], 1, replace=False)
    tiff[iy, ix, 3] = np.random.choice(np.argwhere(Values == tiff[iy, ix, 3])[:, 0], 1, replace=False)
    Rippedimage[iy * 8 : (iy + 1) * 8 - 4, ix * 8 : (ix + 1) * 8 - 4] = Array_Pattern_4_4[tiff[iy, ix, 0]]
    Rippedimage[iy * 8 : (iy + 1) * 8 - 4, ix * 8 + 4 : (ix + 1) * 8] = Array_Pattern_4_4[tiff[iy, ix, 1]]
    Rippedimage[iy * 8 + 4 : (iy + 1) * 8, ix * 8 : (ix + 1) * 8 - 4] = Array_Pattern_4_4[tiff[iy, ix, 2]]
    Rippedimage[iy * 8 + 4 : (iy + 1) * 8, ix * 8 + 4 : (ix + 1) * 8] = Array_Pattern_4_4[tiff[iy, ix, 3]]

左是前面,右边是后面的样子。

EN

回答 1

Stack Overflow用户

发布于 2022-01-17 08:57:59

老实说,要知道您真正想要的是什么有点困难,但是下面是一些代码:

  • 为每个灰度阴影生成各种NxN随机抖动模式(假设8位图像)
  • 选择原始图像中每个NxN像素的随机模式以生成抖动版本

在我的Macbook上,抖动920x920图像大约需要17毫秒:

代码语言:javascript
复制
image generation 4.377
pattern generation 6.06
dither generation 16.915
代码语言:javascript
复制
import time
from contextlib import contextmanager

import numpy as np
from PIL import Image


def generate_patterns(
    *,
    pattern_size: int = 8,
    pattern_options_per_shade: int = 8,
    shades: int = 256,
):
    patterns = []
    for shade in range(shades):
        shade_patterns = [
            np.random.random((pattern_size, pattern_size)) < (shade / shades)
            for i in range(pattern_options_per_shade)
        ]
        patterns.append(shade_patterns)
    return np.array(patterns)


def dither(image, patterns):
    (
        shades,
        pattern_options_per_shade,
        pattern_width,
        pattern_height,
    ) = patterns.shape
    assert shades == 256  # TODO

    # image sampled at pattern_sizes
    resampled = (
        image[::pattern_width, ::pattern_height].round().astype(np.uint8)
    )
    # mask of pattern option per pattern_size block
    pat_mask = np.random.randint(
        0, pattern_options_per_shade, size=resampled.shape
    )

    dithered = np.zeros_like(image)
    for (iy, ix), c in np.ndenumerate(resampled):
        pattern = patterns[c, pat_mask[iy, ix]]
        dithered[
            iy * pattern_height : (iy + 1) * pattern_height,
            ix * pattern_width : (ix + 1) * pattern_width,
        ] = pattern

    return dithered * 255


@contextmanager
def stopwatch(title):
    t0 = time.perf_counter()
    yield
    t1 = time.perf_counter()
    print(title, round((t1 - t0) * 1000, 3))


def main():
    with stopwatch("image generation"):
        img_size = 920
        image = (
            np.linspace(0, 255, img_size)
            .repeat(img_size)
            .reshape((img_size, img_size))
        )
        image[200:280, 200:280] = 0

    with stopwatch("pattern generation"):
        patterns = generate_patterns()

    with stopwatch("dither generation"):
        dithered = dither(image, patterns)

    import matplotlib.pyplot as plt

    plt.figure(dpi=450)
    plt.imshow(dithered, interpolation="none")
    plt.show()


if __name__ == "__main__":
    main()

输出图像看起来像(例如)

编辑

将源图像向上缩放到抖动版本的版本:

代码语言:javascript
复制
image generation 3.886
pattern generation 5.581
dither generation 1361.194
代码语言:javascript
复制
def dither_embiggen(image, patterns):
    shades, pattern_options_per_shade, pattern_width, pattern_height = patterns.shape
    assert shades == 256  # TODO

    # mask of pattern option per source pixel
    pat_mask = np.random.randint(0, pattern_options_per_shade, size=image.shape)

    dithered = np.zeros((image.shape[0] * pattern_height, image.shape[1] * pattern_width))
    for (iy, ix), c in np.ndenumerate(image.round().astype(np.uint8)):
        pattern = patterns[c, pat_mask[iy, ix]]
        dithered[iy * pattern_height:(iy + 1) * pattern_height, ix * pattern_width:(ix + 1) * pattern_width] = pattern

    return (dithered * 255)

编辑2

此版本将抖动行直接作为原始二进制文件写入磁盘。读者应该知道每一行有多少像素。基于一个小的经验测试,这看起来很管用.

代码语言:javascript
复制
import time
from contextlib import contextmanager

import numpy as np


def generate_patterns(
    *,
    pattern_size: int = 8,
    pattern_options_per_shade: int = 16,
    shades: int = 256,
):
    patterns = []
    for shade in range(shades):
        shade_patterns = [
            np.packbits(
                np.random.random((pattern_size, pattern_size))
                < (shade / shades),
                axis=0,
            )[0]
            for i in range(pattern_options_per_shade)
        ]
        patterns.append(shade_patterns)
    return np.array(patterns)


def dither_to_disk(bio, image, patterns):
    assert image.dtype == np.uint8
    shades, pattern_options_per_shade, pattern_height = patterns.shape
    pat_mask = np.random.randint(0, pattern_options_per_shade, size=image.shape)
    for y in range(image.shape[0]):
        patterns[image[y, :], pat_mask[y, :]].tofile(bio)


@contextmanager
def stopwatch(title):
    t0 = time.perf_counter()
    yield
    t1 = time.perf_counter()
    print(title, round((t1 - t0) * 1000, 3))


def main():
    with stopwatch("image generation"):
        img_width = 25_000
        img_height = 5_000
        image = (
            np.linspace(0, 255, img_height)
            .repeat(img_width)
            .reshape((img_height, img_width))
        )
        image[200:280, 200:280] = 0
        image = image.round().astype(np.uint8)

    with stopwatch("pattern generation"):
        patterns = generate_patterns()

    with stopwatch(f"dither_to_disk {image.shape}"):
        with open("x.bin", "wb") as f:
            dither_to_disk(f, image, patterns)


if __name__ == "__main__":
    main()
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70737620

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档