Как я могу увеличить вычислительную эффективность для работы с numpy массивами, используя циклы в python? - PullRequest
0 голосов
/ 26 марта 2020

Я пытаюсь выполнить некоторые задачи преобразования изображений с помощью numpy в python. Идея состоит в том, что, предположим, я загрузил файл изображения в массив numpy img, затем я создал новый массив new_img, а также определил отображение между координатами пикселя: [x,y] в новом изображении соответствует до [old_x,old_y]. А затем я использую new_img[x,y] = img[old_x,old_y] для вычисления преобразования. L oop для фактического вычисления этого преобразования выглядит примерно так: (на самом деле не работает, потому что я опустил много деталей, касающихся правила преобразования, ширины и длины изображений, проверки границ и т. Д. c., Но вы получите представление) .

def get_old_coord(y,x):
  # this is the function to compute the corresponding pixel coordinates
  # some computation here yields old_x and old_y
  # ...
  return old_x,old_y

for x in range(height_of_new_img):
  for y in range(width_of_new_img):
    new_img[y,x] = img[get_old_coord(x,y)]

# new_img is then as desired.

Проблема, с которой я столкнулся, заключается в том, что двойной l oop чрезвычайно трудоемкий. Для изображений размером 1000x1000 требуется одна или две минуты. С другой стороны, поскольку правило преобразования get_old_coord может быть многим, я не думаю, что смогу улучшить это, используя некоторую встроенную функцию для арифметики массива. Как я могу сделать этот процесс более эффективным?


Обновление: для тех, кто хочет получить полный пример, вот один

import math
import torch
import torch.nn
import torchvision
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

def get_old_coord(x,y,old_h,old_w,new_h,new_w):
    cent_x, cent_y = new_h/2, new_w/2
    if ((x+1)%200==0 and (y+1)%new_w==0) or (x+1==new_h and (y+1)%new_w==0):
        print('Progress = %.2f %%'%((x+1)/new_h*100))
    rel_x, rel_y = x-cent_x, y-cent_y
    #print('Doint %d,%d, center = %d,%d, rel_x, rel_y = %d,%d'%(x,y,cent_x,cent_y,rel_x,rel_y))
    rho = math.sqrt(rel_x**2+rel_y**2)
    rho /= (min(new_h,new_w)/2)
    if rel_x==0 and rel_y>=0:
        theta = math.pi/2
    if rel_x==0 and rel_y<0:
        theta = -1*math.pi/2
    if rel_x>0:
        theta = math.atan(rel_y/rel_x)
    if rel_x<0:
        theta = math.atan(rel_y/rel_x)+math.pi
    theta = 2*math.pi-theta
    rho = 1-rho
    old_x = (int)(rho*old_h)
    old_y = (int)(theta*old_w/(2*math.pi))%old_w
    old_x = min(old_h-1,max(0,old_x))
    #old_y = min(old_w-1,max(0,old_y))
    #print('rho = %f, theta = %f, old_x, old_y = %d,%d'%(rho,theta,old_x,old_y))
    return old_x, old_y

def transform(new_h,new_w,old_im):
    old_h, old_w, _ = old_im.size()
    new_im = torch.zeros(new_h,new_w,3).int()

    for i in range(new_h):
        for j in range(new_w):
            new_im[i,j] = old_im[get_old_coord(i,j,old_h,old_w,new_h,new_w)]

    return new_im

input_file_name = 'in.jpg'
output_file_name = 'out.jpg'

new_h = 800
new_w = 800

old_im = torch.tensor(plt.imread(input_file_name))
new_im = transform_radial(new_h,new_w,old_im)

new_im = Image.fromarray(np.uint8(new_im))
new_im.save(output_file_name)

По сути, это реализует преобразование полярной координаты. Извините за то, что не успел добавить комментарии в мой код. Но пробовать это на любом из ваших изображений должно быть весело. Кроме того, я на самом деле использую тензоры факелов в этом примере, но они мало чем отличаются от numpy массивов.

1 Ответ

0 голосов
/ 26 марта 2020

В основном вам нужна векторизация, но с доступом к индексу массива, над которым выполняется поэлементная операция.

для массива NxM, я нашел способ сделать это как

N,M = 4,6 # random number of dimensions

foo_mat = np.random.rand(N,M) #<-- random array representing data

def bar_func(elem, i, j): # <-- i,j are the indices of the matrix 
    return pass #<- Do whatever you want here

bar_func = np.vectorize(bar_func, signature="(n,m),(n,m),(n,m)->(n,m)")

baz_solved_mat = bar_func(foo_mat, *np.mgrid[:N,:M])

Как это работает?

bar_func = np.vectorize(bar_func, signature="(n,m),(n,m),(n,m)->(n,m)")

Здесь, подпись говорит, для (n, m) -образной матрицы значений elem, (n, m) -образных значений i и (n, m) ) значения j в форме (3 параметра bar_func соответственно) возвращают значение (n,m) в форме. Это отображает каждую i, j координату 3 матрицы вместе.

np.mgrid - это быстрый способ получить эти массивы индекса строки и столбца. см. До c

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...