【问题标题】:Multiprocessing of image processing (EDITED)图像处理的多处理(已编辑)
【发布时间】:2021-02-07 14:41:25
【问题描述】:

我有以下程序:

daytime_images = os.listdir("D:/TR/Daytime/")
number_of_day_images = len(daytime_images)
day_value = 27

def find_RGB_day(clouds, red, green, blue):
    img = Image.open(clouds)
    img = img.convert('RGB')
    pixels_single_photo = []
    for x in range(img.size[0]):
        for y in range(img.size[1]):
            h, s, v, = img.getpixel((x, y))
            if h <= red and s <= green and v <= blue:
                pixels_single_photo.append((x,y))
    return pixels_single_photo

number = 0

for _ in range(number_of_day_images):
    world_image = ("D:/TR/Daytime/" + daytime_images[number])
    pixels_found = find_RGB_day(world_image, day_value, day_value, day_value)
    coordinates.append(pixels_found)
    number = number+1

已编辑 我想使用多处理器执行该功能,所以我尝试了:

for number in range(number_of_day_images):
    p = multiprocessing.Process(
        target=find_RGB_day,
        args=("D:/TR/IR_Photos/Daytime/" + daytime_images[number],27, 27, 27))
    p.start()
    p.join()
    number = number+1
    coordinates.append(p)

执行的时候出现了AttributeError,不知道怎么解决:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\ProgramData\Anaconda3\lib\multiprocessing\spawn.py", line 116, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "C:\ProgramData\Anaconda3\lib\multiprocessing\spawn.py", line 126, in _main
    self = reduction.pickle.load(from_parent)
AttributeError: Can't get attribute 'find_RGB_day' on <module '__main__' (built-in)>

我认为这个错误可能与我将图像引入程序的方式有关,我从一个文件夹中获取所有名称,然后选择每个元素的元素,其中 number= number+1

【问题讨论】:

    标签: python python-3.x image multiprocessing runtime-error


    【解决方案1】:

    我正在与wagnifico 并行工作并尝试了 Pool(不错的猜测)。 我没有图像文件,所以我使用namedtuple构造了类似的函数以尽可能接近。

    from multiprocessing import Pool, TimeoutError
    import os, time
    import random
    from collections import namedtuple
    
    
    def find_RGB_day(red, green, blue):
        img = Image((256, 256))  # loading your image goes here eg. 256 x 256
        pixels_single_photo = []
        for x in range(img.size[0]):
            for y in range(img.size[1]):
                h, s, v, = random.randrange(255), random.randrange(255), random.randrange(255)
                if h <= red and s <= green and v <= blue:
                    pixels_single_photo.append((x,y))
        time.sleep(5)  # del this line, it imitates loading a big file
        return pixels_single_photo
    
    
    if __name__ == '__main__':
        number_of_day_images = 5
        day_value = 27
        Image = namedtuple('Image',['size'])
    
        with Pool(processes=4) as pool:  # You can play with processes number
            multiple_results = [pool.apply_async(find_RGB_day, args=(27, 27, 27)) for i in range(number_of_day_images)]
            try:
                [print(res.get()) for res in multiple_results]
            except TimeoutError:
                print("We lacked patience and got a multiprocessing.TimeoutError")
    

    我使用了有关“使用工人池”的 python 文档,您可以找到 HERE。

    因此,池不是创建这个进程循环,而是负责所有计算。

    for _ in range(number_of_day_images):
        p = multiprocessing.Process(target=find_RGB_day, args=("D:/TR/IR_Photos/Daytime/" + daytime_images[number], 27, 27, 27))
        p.start()
        p.join()
    

    你可以有这样的东西:

    multiple_results = [pool.apply_async(find_RGB_day, args=("D:/TR/IR_Photos/Daytime/" + daytime_images[number], 27, 27, 27)]
        try:
            [print(res.get()) for res in multiple_results]
    

    在我的代码示例中,4 个文件在大约 5 秒内加载并构建了一个 multiple_results 数组(因为我们有 4 个工人),最后一个在 5 秒后触发。

    [编辑] 我已经下载了图像并使用此代码来获取所需像素的所有坐标。 (27, 27, 27) 对我来说太低了,所以我使用了不同的比例 (31, 90, 170)。

    享受吧。

    from multiprocessing import Pool, TimeoutError
    import time, os
    import random
    from PIL import Image
    
    
    def find_RGB_day(clouds, red, green, blue):
        img = Image.open(clouds)
        img = img.convert()
        pixels_single_photo = []
        for x in range(img.size[0]):
            for y in range(img.size[1]):
                # print(img.getpixel((x, y)))
                h, s, v, = img.getpixel((x, y))
                if h <= red and s <= green and v <= blue:
                    pixels_single_photo.append((x,y))
        return pixels_single_photo
    
    
    def create_pool():
        coordinates = []
        with Pool(processes=4) as pool:
            files_to_precess = [pool.apply_async(find_RGB_day,
                                                 args=("D/TR/Daytime/" + daytime_images[number], 31, 90, 170))
                                for number in range(number_of_day_images)]
            try:
                coordinates = [res.get() for res in files_to_precess]  # processes get your data in here
            except TimeoutError:
                print("We lacked patience and got a multiprocessing.TimeoutError")
        return coordinates
    
    if __name__ == '__main__':
        daytime_images = os.listdir("D/TR/Daytime/")
        number_of_day_images = len(daytime_images)
        print(number_of_day_images)
        day_value = 27
        coordinates = create_pool()
        [print(res) for res in coordinates]
    

    【讨论】:

    • 感谢您的回答。在我的程序中,我正在寻找添加到pixels_single_photo 的某些像素,然后,在每个循环结束时,这些像素被保存在一个称为坐标的列表中(列表列表)我该如何实现这个这个程序?跨度>
    • 您已经获得了 multiple_results 列表中的所有像素。与其像我一样将它们打印出来,您可以随心所欲地使用它。试试我的代码,你就会看到所有的代码:)
    • 很抱歉给您带来不便,如何将所有坐标存储在一个名为坐标的列表中?尝试使用 [coordinates.append(res.get()) 获取坐标中的 res] 我遇到了 AttributeError:'list' 对象没有属性 'get'。谢谢
    • 没问题。我在最后一次编辑中更正了几行,所以在“享受”之后粘贴所有内容。它应该是坐标 = [res.get() for res in files_to_precess] 其中 files_to_process 列表仅存储所有所需的进程,因此您循环遍历它并 res.get() 将它们一一列出。
    • 感谢您的帮助,非常感谢。
    【解决方案2】:

    您应该按照错误消息的说明进行操作并添加一个主模块:

    def fun(inputs):
        # your function
        return outputs
    
    if __name__ == '__main__':
       # your main code
       p = multiprocessing.Process(target=fun, args=(inputs,))
       p.start()
       p.join()
    

    更多详情请访问answers for this question。

    另外,您的代码中存在错误。调用进程时必须拆分函数和参数:target=fun, args=(inputs,),就像我在上面的示例中所做的那样。当您发送带有参数的函数时 - target=fun(inputs) - 您实际上并没有调用任何进程,因为您只是将函数 fun 的输出作为目标发送,而不是函数本身。它将引发错误,因为您的函数的输出不可调用(本身不是函数)。

    为了适应您的调用,使用多个参数,您可以使用:

    for number in range(number_of_days_images):
        p = multiprocessing.Process(
            target=find_RGB_day,
            args=("D:/TR/IR_Photos/Daytime/" + daytime_images[number],
                  27, 27, 27)
        )
        # rest of your code ...
    

    此外,我建议您使用pool.Pool.map,它将在所需数量的工作人员之间拆分参数列表并阻止结果。 here 提供了有关如何为具有多个参数的函数实现它的很好的描述。

    【讨论】:

    • 谢谢。哪里可以将pixel_single_photo的保存引入到列表坐标中?
    • 我经常收到页面顶部描述的属性错误。你知道这是什么原因吗?
    • 你好像没有定义函数。确保在调用之前已经定义了它。此外,在您的编辑中,您应该删除 number = number + 1,因为它已经被 for 循环处理了。
    猜你喜欢
    • 2012-12-13
    • 2019-02-27
    • 1970-01-01
    • 1970-01-01
    • 2020-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多