python 如何基于图像之间的白色边框将图像拆分为多个图像

bmvo0sr5  于 2022-12-28  发布在  Python
关注(0)|答案(2)|浏览(213)

我需要将一个图像分割成多个图像,基于它们之间的白色边框。
例如:

输出:

我不知道如何开始这个任务。

ajsxfq5m

ajsxfq5m1#

下面是一个解决方案,适用于我们知道网格配置的“简单”情况。我提供了这个解决方案,尽管我怀疑这是要求您做的事情。
在猫的示例图像中,如果给定网格配置2x2,我们可以:

from PIL import Image

def subdivide(file, nx, ny):
    im = Image.open(file)
    wid, hgt = im.size # Size of input image
    w = int(wid/nx) # Width of each subimage
    h = int(hgt/ny) # Height of each subimage
    for i in range(nx):
        x1 = i*w  # Horicontal extent...
        x2 = x1+w # of subimate
        for j in range(ny):
            y1 = j*h # Certical extent...
            y2 = y1+h # of subimate
            subim = im.crop((x1, y1, x2, y2))
            subim.save(f'{i}x{j}.png')

subdivide("cat.png", 2, 2)

以上操作将创建这些图像:

tpgth1q7

tpgth1q72#

我之前的答案依赖于知道输入图像的网格配置,而这个解决方案不知道。
主要的挑战是检测边界在哪里,因此,包含图像的矩形位于哪里。
为了检测边界,我们将寻找(垂直和水平)所有像素都是“白色”的图像线。由于图像中的边界并不是真正的纯白,我们将使用一个小于255的值作为白度阈值(代码中的WHITE_THRESH)。
算法的要点在以下代码行中:

whitespace = [np.all(gray[:,i] > WHITE_THRESH) for i in range(gray.shape[1])]

这里的“whitespace”是一个布尔值列表,看起来像

TTTTTFFFFF...FFFFFFFFTTTTTTTFFFFFFFF...FFFFTTTTT

其中“T”表示相应的水平位置是边界的一部分(白色)。
我们感兴趣的是T和F之间存在转换的x位置。对函数***slices(whitespace)***的调用返回索引元组的列表

[(x1, x2), (x1, x2), ...]

其中每个(x1,x2)对指示图像在x轴方向上的xmin和xmax位置。
slices函数使用异或运算符找到在True和False之间存在转换的“边”,然后以元组列表(索引对)的形式返回转换的位置。
类似的代码用于检测边界和图像的垂直位置。
以下完整的可运行代码将OP的图像“cat.png”作为输入,并且:
1.将子图像提取到4个PNG文件“片段-0-0.png”、“片段-0-1.png”、“片段-1-0.png”和“片段-1-1.png”中。
1.通过将上述片段粘贴在一起创建原始图像的(无边框)版本。
接下来是可运行的代码和生成的图像。程序运行大约0. 25秒。

from PIL import Image
import numpy as np

def slices(lst):
    """ Finds the indices where lst changes value and returns them in pairs
        lst is a list of booleans
    """
    edges = [lst[i-1] ^ lst[i] for i in range(len(lst))]
    indices = [i for i,v in enumerate(edges) if v]
    pairs = [(indices[i], indices[i+1]) for i in range(0, len(indices), 2)]
    return pairs

def extract(xx_locs, yy_locs, image, prefix="image"):
    """ Locate and save the subimages """
    data = np.asarray(image)
    for i in range(len(xx_locs)):
        x1,x2  = xx_locs[i]
        for j in range(len(yy_locs)):
            y1,y2  = yy_locs[j]
            arr = data[y1:y2, x1:x2, :]
            Image.fromarray(arr).save(f'{prefix}-{i}-{j}.png')
                                        
def assemble(xx_locs, yy_locs, prefix="image", result='composite'):
    """ Paste the subimages into a single image and save """
    wid = sum([p[1]-p[0] for p in xx_locs])
    hgt = sum([p[1]-p[0] for p in yy_locs])
    dst = Image.new('RGB', (wid, hgt))
    x = y = 0
    for i in range(len(xx_locs)):
        for j in range(len(yy_locs)):
            img = Image.open(f'{prefix}-{i}-{j}.png')
            dst.paste(img, (x,y))
            y += img.height
        x += img.width
        y = 0
    dst.save(f'{result}.png')

WHITE_THRESH = 110  # The original image borders are not actually white
image_file = 'cat.png'

image = Image.open(image_file)

# To detect the (almost) white borders, we make a grayscale version of the image
gray = np.asarray(image.convert('L'))

# Detect location of images along the x axis
whitespace = [np.all(gray[:,i] > WHITE_THRESH) for i in range(gray.shape[1])]
xx_locs = slices(whitespace)

# Detect location of images along the y axis
whitespace = [np.all(gray[i,:] > WHITE_THRESH) for i in range(gray.shape[0])]
yy_locs = slices(whitespace)

extract(xx_locs, yy_locs, image, prefix='fragment')

assemble(xx_locs, yy_locs, prefix='fragment', result='composite')

单个片段:

合成图像:

相关问题