Python 3.7:使用共享变量多处理for循环

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

首先是一些背景:

我正在尝试写下一个python脚本,将灰度(.tif)中的Image转换为带有所谓''jet''色彩映射的.jpeg。我设法用for循环做了,但是对于一个图像来说有点长(数百万像素要处理!),所以我想使用多处理。

我的问题是,要将每个灰色像素转换为彩色像素,我必须使用两个变量(光强度''min_img''的最小值和矢量''dx_cm''从初始灰度级变为256比例,对应于喷射色图)。

所以要将''min_img''和''dx_cm''的信息传递给我尝试使用multiprocessing.Value()的进程,但作为回报我得到错误:

RuntimeError: Synchronized objects should only be shared between processes through inheritance

我尝试了不同来源的许多不同的东西,无论我的代码版本如何,我都在努力解决这个错误。所以,如果我的代码不干净,我很抱歉,如果有人可以帮助我,我将非常感激。

我的非工作代码:

import multiprocessing
from PIL import Image
from matplotlib import cm


def fun(gr_list,dx,minp):

    dx_cmp = dx.value
    min_imgp = minp.value

    rgb_res=list()

    for i in range(len(gr_list)):
        rgb_res.extend(cm.jet(round(((gr_list[i]-min_imgp)/dx_cmp)-1))[0:-1])

    return rgb_res


if __name__ == '__main__':

    RGB_list=list()

    n = multiprocessing.cpu_count()

    img = Image.open(r'some_path_to_a.tif')

    Img_grey=list(img.getdata())

    dx_cm = multiprocessing.Value('d',(max(Img_grey)-min(Img_grey))/256)

    min_img = multiprocessing.Value('d',min(Img_grey))

    with multiprocessing.Pool(n) as p:

        RGB_list = list(p.map(fun, (Img_grey,dx_cm,min_img)))

    res = Image.frombytes("RGB", (img.size[0], img.size[1]), bytes([int(0.5 + 255*i) for i in RGB_list]))    

    res.save('rgb_file.jpg')

PS:这是我想要并行化的初始for循环的示例:

from PIL import Image
from matplotlib import cm


if __name__ == '__main__':

    img = Image.open(r'some_path_to_a.tif')

    Img_grey = list(img.getdata())

    dx_cm = (max(Img_grey)-min(Img_grey))/256

    min_img = min(Img_grey)

    Img_rgb = list()

    for i in range(len(Img_grey)):
        Img_rgb.extend(cm.jet(round(((Img_grey[i]-min_img)/dx_cm)-1))[0:-1])

    res = Image.frombytes("RGB", (img.size[0], img.size[1]), bytes([int(0.5 + 255*i) for i in Img_rgb]))    

    res.save('rgb_file.jpg')
python shared-memory python-multiprocessing
2个回答
0
投票

你的fun方法循环遍历某些列表,但在这种情况下,它将从列表中接收“part”,一个项目,因此它应该只返回其处理的结果。

我已将工作代码更改为使用多处理运行。

fun方法返回一个列表时,p.map将返回一个列表列表(结果列表)并且需要展平,之前使用list extends方法完成。

尝试使用进程池和线程池多处理,在我的方案中没有任何性能提升。

  • 流程多处理:
from PIL import Image
from matplotlib import cm
import multiprocessing


def fun(d):
    part, dx_cm, min_img = d
    return cm.jet(round(((part-min_img)/dx_cm)-1))[0:-1]

if __name__ == '__main__':
    img = Image.open(r'a.tif')
    Img_grey = list(img.getdata())

    def Gen(img_data):
        dx_cm = (max(img_data)-min(img_data))/256
        min_img = min(img_data)
        for part in img_data:
            yield part, dx_cm, min_img

    n = multiprocessing.cpu_count()
    with multiprocessing.Pool(n) as p:
        Img_rgb = [item for sublist in p.map(fun, Gen(Img_grey)) for item in sublist]

    res = Image.frombytes("RGB", (img.size[0], img.size[1]), bytes([int(0.5 + 255*i) for i in Img_rgb]))    
    res.save('b.jpg')
  • 线程多处理:
from PIL import Image
from matplotlib import cm
import multiprocessing
from multiprocessing.pool import ThreadPool

if __name__ == '__main__':
    img = Image.open(r'a.tif')
    Img_grey = list(img.getdata())
    dx_cm = (max(Img_grey)-min(Img_grey))/256
    min_img = min(Img_grey)

    def fun(part):
        return cm.jet(round(((part-min_img)/dx_cm)-1))[0:-1]

    n = multiprocessing.cpu_count()
    with ThreadPool(n) as p:
        Img_rgb = [item for sublist in p.map(fun, Img_grey) for item in sublist]

    res = Image.frombytes("RGB", (img.size[0], img.size[1]), bytes([int(0.5 + 255*i) for i in Img_rgb]))    
    res.save('b.jpg')

0
投票

因此,似乎计算负担不足以使多处理有用。

然而,对于那些对我的问题的图像处理部分感兴趣的主题,我发现了另一种更快的方法(比之前的方法低15到20倍)来做同样的事情而没有for循环:

from matplotlib import cm
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
from PIL import Image

cm_jet = cm.get_cmap('jet')
img_src = Image.open(r'path to your grey image')
img_src.mode='I'

Img_grey = list(img_src.getdata())
max_img = max(Img_grey)
min_img = min(Img_grey)

rgb_array=np.uint8(cm_jet(((np.array(img_src)-min_img)/(max_img-min_img)))*255)

ax = plt.subplot(111)
im = ax.imshow(rgb_array, cmap='jet')

divider = make_axes_locatable(ax)
cax_plot = divider.append_axes("right", size="5%", pad=0.05)

cbar=plt.colorbar(im, cax=cax_plot, ticks=[0,63.75,127.5,191.25,255])
dx_plot=(max_img-min_img)/255
cbar.ax.set_yticklabels([str(min_img),str(round(min_img+63.75*dx_plot)),str(round(min_img+127.5*dx_plot)),str(round(min_img+191.25*dx_plot)), str(max_img)])

ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)

plt.savefig('test_jet.jpg', quality=95, dpi=1000)
© www.soinside.com 2019 - 2024. All rights reserved.