Python:将二维数组切割成小块

0 投票
2 回答
1916 浏览
提问于 2025-04-16 02:57

我有一个原始数据文件,我把它读进了一个字节缓冲区(就是一个Python字符串)。每个数据值代表一个8位的像素,这些像素组成了一个二维数组,表示一张图片。我知道这张图片的宽度和高度。

我想把这张图片分成几个小块,每个小块的面积必须大于一个最小值(比如1024字节),但又要小于一个最大值(比如2048字节)。这些小块的高度和宽度可以随意,只要满足面积的要求,而且这些小块的大小不需要都一样。此外,输入数据的大小也不一定是2的幂。

在Python中,怎么做这个比较好呢?

祝好

2 个回答

1

如果你在处理图片,建议使用 PIL(Python图像库)。首先,你需要加载图片:

import Image
i = Image.open(imagefile)

然后你可以轻松地裁剪出任意大小的区域:

box = (FirstCornerX, FirstCornerY, SecondCornerX, SecondCornerY)
region = im.crop(box)

这样你就可以对裁剪后的部分进行操作了。你还可以在图像对象和二维数组之间转换,不过我不太记得具体怎么做了。我之前有几个函数可以在图片和 numpy 数组之间转换,我会看看能不能找到它们。

另外,你可能还想看看 PIL手册,里面有关于处理图片的文档和示例。

2

因为你没有说明“最好”的意思,我就假设它是指“代码更简洁”。

假设你有以下数据:

from collections import Sequence
import operator

assert(type(MIN_AREA) is int)
assert(type(MAX_AREA) is int)
assert(type(width) is int)
assert(type(height) is int)
assert(instanceof(data, Sequence))
assert(len(data) == width * height)
assert(MAX_AREA >= 2 * MIN_AREA)

(在MIN和MAX区域的条件是这个方法能工作的必要条件)

有些情况下,这种分割是无法用任何算法实现的,比如把一个3x3的图像分成4到8块的瓷砖。

假设这些数据是按行存储的(就像PNM规范中那样)。

def split_(seq, size):
    return [seq[i:i+size] for i in range(0,len(seq),size)]

tiles = list()
if width >= MIN_AREA:
    # each row is subdivided into multiple tiles
    tile_width = width / (width / MIN_AREA) # integral division
    rows = split_(data, width)
    row_tiles = [split_(row, tile_width) for row in rows]
    tiles = reduce(operator.add, row_tiles)
elif width < MIN_AREA:
    # each tile is composed of rows
    min_tile_height = int(MIN_AREA / width) + 1
    tile_height = height / (height / min_tile_height)
    tile_size = tile_height * width
    tiles = split_(data, tile_size)
    if len(tiles[-1]) < MIN_AREA:
        if (tile_height > 2):
            tiles[-2] += tiles[-1]
            del tiles[-1]
        else: # tile_height == 2, the case 1 don't pass here
            # special case, we need to split vertically the last three rows
            # if the width was 3 too we have a problem but then if we are here
            # then MIN_AREA was 4, and MAX_AREA was 8, and the rows are >= 5
            if width > 3:
                last_three_rows = split_(tiles[-2] + tiles[-1], width)
                tiles[-2] = reduce(operator.add,[row[:width/2] for row in last_three_rows])
                tiles[-1] = reduce(operator.add,[row[width/2:] for row in last_three_rows])
            else: # width = 3 and MIN_AREA = 4
                last_five_rows = reduce(operator.add, tiles[-3:])
                three_columns = [last_five_rows[i::3] for i in range(3)]
                tiles[-3:] = three_columns

只要记住,在最后的情况下,你会得到两个或三个瓷砖并排放置,其他的瓷砖则堆叠在它们的上面(或下面,具体取决于第‘0’行的位置)。

如果你需要存储比原始像素数据更多的信息,只需调整瓷砖的创建过程即可。

撰写回答