Python 3.7: многопроцессорная обработка цикла for с общими переменными - PullRequest
0 голосов
/ 22 февраля 2019

сначала немного контекста:

Я пытаюсь записать скрипт на python для преобразования изображения в оттенках серого (.tif) в формат .jpeg с так называемой цветовой картой «jet».Мне удалось сделать это с помощью цикла 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')

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

Таким образом, кажется, что вычислительная нагрузка недостаточно велика для многопроцессорной обработки, чтобы быть полезной.

Тем не менее, для тех, кто сталкивается с этой темой и интересуется частью моего вопроса, касающейся обработки изображений, я нашел другой, гораздо более быстрый способ (от 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)
0 голосов
/ 23 февраля 2019

Ваш fun метод зацикливается на некотором списке, но в этом случае он получит "часть", элемент из вашего списка, поэтому он должен возвращать только результат своей обработки.

Iизменили рабочий код для работы с многопроцессорной обработкой.

Поскольку метод 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')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...