Python 3.7:多处理具有共享变量的 for 循环

首先是一些上下文:


我正在尝试写下一个 python 脚本,将灰度 (.tif) 中的图像转换为具有所谓“jet”颜色图的 .jpeg。我设法用 for 循环来做到这一点,但对于一张图像(处理数百万像素!)来说有点长,所以我想使用多处理。


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


因此,为了将“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')


RISEBY
浏览 152回答 2
2回答

梵蒂冈之花

您的fun方法正在遍历某个列表,但在这种情况下,它将接收一个“部分”,即您列表中的一个项目,因此它应该只返回其处理结果。我已将工作代码更改为与多处理一起运行。由于该fun方法返回一个列表,因此p.map将返回一个列表列表(结果列表)并且需要展平,extends之前使用 list方法完成。尝试使用进程池和线程池多处理,在我的场景中没有任何性能提升。进程多处理:from PIL import Imagefrom matplotlib import cmimport multiprocessingdef 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 Imagefrom matplotlib import cmimport multiprocessingfrom multiprocessing.pool import ThreadPoolif __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')

心有法竹

因此,对于多处理而言,计算负担似乎还不够大。尽管如此,对于那些对我的问题的图像处理部分感兴趣的主题的人,我发现了另一种更快的方法(比以前的方法快 15 到 20 倍)在没有 for 循环的情况下做同样的事情:from matplotlib import cmimport matplotlib.pyplot as pltfrom mpl_toolkits.axes_grid1 import make_axes_locatableimport numpy as npfrom PIL import Imagecm_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)/255cbar.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)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python