使用 OpenCV 或 Pillow 等库来优化 Python 中的图像裁剪代码的最佳实践和有效方法是什么?

问题描述 投票:0回答:2

我在 Pillow 中有这段代码可以完美裁剪图像。例如,我有相同背景下不同颜色的内容,此代码将其裁剪为尽可能最小的尺寸,边距为 32 像素。

但是,速度很慢!在运行它的计算机(具有 4 GiB RAM 的 Cloud Run 4 vCPU)上需要近 12 秒,而启动完整浏览器并解释 HTML 和 CSS 的 Chromium 进程只需要 3 秒。

所以,我想知道我可以做些什么来优化这个过程。

我知道它是像素完美的,并且鉴于其性质,需要更多时间,但 12 秒似乎太长了。

或者,我可以使用 OpenCV,或者我可以采用一些涉及 JavaScript 和 Python 的技术来确定裁剪的理想大小,但我不知道如何去做。

未裁剪的完整图像:https://delduca-to25gludpq-uc.a.run.app/get

def trim(buffer, margin=32, trim_color="#92b88a"):
    with PIL.Image.open(io.BytesIO(buffer)).convert("RGB") as image:
        width, height = image.size

        left, top, right, bottom = 0, 0, width - 1, height - 1

        trim_color_rgb = tuple(int(trim_color[i : i + 2], 16) for i in (1, 3, 5))

        while left < width:
            column = [image.getpixel((left, y)) for y in range(height)]
            if all(pix == trim_color_rgb for pix in column):
                left += 1
            else:
                break

        while top < height:
            row = [image.getpixel((x, top)) for x in range(width)]
            if all(pix == trim_color_rgb for pix in row):
                top += 1
            else:
                break

        while right > left:
            column = [image.getpixel((right, y)) for y in range(height)]
            if all(pix == trim_color_rgb for pix in column):
                right -= 1
            else:
                break

        while bottom > top:
            row = [image.getpixel((x, bottom)) for x in range(width)]
            if all(pix == trim_color_rgb for pix in row):
                bottom -= 1
            else:
                break

        left = max(left - margin, 0)
        top = max(top - margin, 0)
        right = min(right + margin, width - 1)
        bottom = min(bottom + margin, height - 1)

        return image.crop((left, top, right, bottom))
python opencv python-imaging-library playback
2个回答
0
投票

一只在这里无法说出名字的小鸟给了我这个解决方案,并且它在不到一秒的时间内执行!

def trim(buffer, margin=32, trim_color="#92b88a"):
    with PIL.Image.open(io.BytesIO(buffer)).convert("RGB") as image:
        data = np.array(image)
        trim_color_rgb = tuple(int(trim_color[i : i + 2], 16) for i in (1, 3, 5))

        non_trim_rows = np.where(np.any(data != trim_color_rgb, axis=(1, 2)))[0]
        non_trim_cols = np.where(np.any(data != trim_color_rgb, axis=(0, 2)))[0]

        left = max(0, non_trim_cols[0] - margin)
        top = max(0, non_trim_rows[0] - margin)
        right = min(data.shape[1] - 1, non_trim_cols[-1] + margin)
        bottom = min(data.shape[0] - 1, non_trim_rows[-1] + margin)

        return PIL.Image.fromarray(data[top:bottom, left:right])


0
投票

据我所知,

get_pixel()
可能会非常慢。您应该将图像转换为
numpy.array

numpy_array = np.array(image)   #  convert to `numpy array`

并在不使用

for
-loops

的情况下运行一些代码
column = array[0:y, right]
if (column == trim_color_rgb).all():

我必须编写

minimal working
代码来检查它并且

  • 你的版本有时会带我
    25 to 0 seconds
  • 使用
    numpy
    大约需要
    1 second

我用于测试的完整工作代码:

import time
import numpy as np
from PIL import Image

def trim_1(buffer, margin=32, trim_color="#92b88a"):

    with Image.open('logo.png').convert("RGB") as image:
    #with Image.open(io.BytesIO(buffer)).convert("RGB") as image:
        width, height = image.size

        left, top, right, bottom = 0, 0, width - 1, height - 1

        trim_color_rgb = tuple(int(trim_color[i : i + 2], 16) for i in (1, 3, 5))

        while left < width:
            column = [image.getpixel((left, y)) for y in range(height)]
            if all(pix == trim_color_rgb for pix in column):
                left += 1
            else:
                break

        while top < height:
            row = [image.getpixel((x, top)) for x in range(width)]
            if all(pix == trim_color_rgb for pix in row):
                top += 1
            else:
                break

        while right > left:
            column = [image.getpixel((right, y)) for y in range(height)]
            if all(pix == trim_color_rgb for pix in column):
                right -= 1
            else:
                break

        while bottom > top:
            row = [image.getpixel((x, bottom)) for x in range(width)]
            if all(pix == trim_color_rgb for pix in row):
                bottom -= 1
            else:
                break

        left = max(left - margin, 0)
        top = max(top - margin, 0)
        right = min(right + margin, width - 1)
        bottom = min(bottom + margin, height - 1)

        print(left, top, right, bottom)
        return image.crop((left, top, right, bottom))

def trim_2(buffer, margin=32, trim_color="#92b88a"):

    with Image.open('logo.png').convert("RGB") as image:
    #with Image.open(io.BytesIO(buffer)).convert("RGB") as image:
        width, height = image.size

        numpy_array = np.array(image)   #  convert to `numpy array`
        #height, width, _ = numpy_array.shape 

        left, top, right, bottom = 0, 0, width - 1, height - 1

        trim_color_rgb = tuple(int(trim_color[i : i + 2], 16) for i in (1, 3, 5))

        while left < width:
            column = numpy_array[:,left]
            if (column == trim_color_rgb).all():
                left += 1
            else:
                break

        while top < height:
            row = numpy_array[top,:]
            if (row == trim_color_rgb).all():
                top += 1
            else:
                break

        while right > left:
            column = numpy_array[:,right]
            if (column == trim_color_rgb).all():
                right -= 1
            else:
                break

        while bottom > top:
            row = numpy_array[bottom,:]
            if (row == trim_color_rgb).all():
                bottom -= 1
            else:
                break

        left = max(left - margin, 0)
        top = max(top - margin, 0)
        right = min(right + margin, width - 1)
        bottom = min(bottom + margin, height - 1)

        print(left, top, right, bottom)
        
        return image.crop((left, top, right, bottom))

start = time.time()
print('running ...')
result = trim_1(None)
end = time.time()
print('trim_1 time:', end - start)
result.save('trim_1.png')

start = time.time()
print('running ...')
result = trim_2(None)
end = time.time()
print('trim_2 time:', end - start)
result.save('trim_2.png')

结果:

running ...
668 48 1227 551
trim_1 time: 25.654032468795776

running ...
668 48 1227 551
trim_2 time: 0.8261435031890869
© www.soinside.com 2019 - 2024. All rights reserved.