У меня проблема с преобразованием кода MATLAB в Python

#python #arrays #matlab #image-processing

#python #массивы #matlab #обработка изображений

Вопрос:

Мне нужно преобразовать приведенный ниже блок кода в Python. Я создал два массива с именами u и v отдельно и поместил их в цикл for в диапазоне от 0 до M-1, и я знаю find , что работает аналогично условию if. У меня проблема, поскольку оба idx и u являются массивами.

Код MATLAB — это:

 u = 0:(M-1); 
v = 0:(N-1); 
idx = find(u > M/2); 
u(idx) = u(idx) - M; #I have a problem here
idy = find(v > N/2); 
v(idy) = v(idy) - N;
 

В основном, что я делал в Python, пока не добрался до этой проблемной строки:

 input_image = Image.open('./....image....')
input_image=np.array(input_image)
M,N = input_image.shape[0],input_image.shape[1]

FT_img = fftpack.fftshift(fftpack.fft2(input_image))

# Assign the order value 
n = 2; # one can change this value accordingly 
  
# Assign Cut-off Frequency 
D0 = 60; # one can change this value accordingly 
  
# Designing filter 
u=[]
v=[]
for i in range(M-1):
  u.append(i)

for i in range(N-1):
  v.append(i)
 

Комментарии:

1. Вы ищете Numpy. Я думаю, вам следует прочитать несколько руководств по Python. 1 , 2 . В последнем есть глава, посвященная Numpy.

2. Спасибо @Cris, я только что отредактировал свой пост.

3. Очевидно, что сценарий Matlab — это ваш ввод, а сценарий Python — ваш вывод. Пожалуйста, разместите скрипты Matlab и Python в виде двух отдельных блоков кода. В настоящее время у вас есть *** Matlab *** и Python , объединенные в один блок кода. Разделите два блока кода внутри вашего сообщения stack overflow знаками pound. ### Original Matlab (input) ### и ### Attempted Python (output) ###

4. @Samuel, просто отредактировал мой пост так, как вы упомянули.

5. По-видимому, имеющийся у вас код MATLAB вычисляет нечто, известное как частоты дискретизации » Дискретного преобразования Фурье «. Дискретные преобразования Фурье хорошо изучены. Вам не нужно писать свой собственный код для вычисления частот дискретизации дискретного преобразования Фурье. Если человек, написавший код MATLAB, не смог написать комментарий, объясняющий, что они вычисляли, то этот человек был очень плохим программистом. Почти невозможно сказать, что должен делать код без комментариев. Почему бы просто не иметь функцию с именем что-то вроде get_fft_frequencies() ?

Ответ №1:

Что u = 0:(M-1) делает Matlab и как мы можем сделать то же самое в Python?

Ниже приведен один отрывок из вашего исходного кода Matlab:

     % BEGIN MATLAB %

    u = 0:(M-1); 

    % END MATLAB %
 

Что делает код?

Предположим, что M = 7 . Тогда код Matlab упрощает:

     u = 0:6; 
 

Результатом является массив u , начинающийся 0 и заканчивающийся 6 :

 u = [0   1   2   3   4   5   6]
 

По сути, вы инициализируете массив последовательных целых чисел.

Существуют различные способы выполнить что-то подобное в Python:

     # Begin Python   

    M = 7
    u = list(range(0, M))

    # End python
 

Обратите внимание, что это range(0, 7) выглядит как [0, ..., 5, 6] , не [0, ..., 6, 7]
range Функция Python автоматически вычитается 1 из верхнего предела

Если вы действительно занимаетесь материалами типа Matlab, то numpy какую библиотеку вы хотите использовать в Python:

 import numpy as np
u = np.array(range(0, 7))
 

Индексация, начинающаяся с 0, по сравнению с индексацией, начинающейся с 1

Обратите внимание, что индексация Matlab начинается с 1 .
Индексация Python начинается с 0 .
ARRAY = ["red", "blue", "white", "green"]

  -------------- ------- -------- --------- --------- 
|    ARRAY     | "red" | "blue" | "white" | "green" |
 -------------- ------- -------- --------- --------- 
| PYTHON INDEX |     0 |      1 |       2 |       3 |
| MATLAB INDEX |     1 |      2 |       3 |       4 |
 -------------- ------- -------- --------- --------- 
 

Понимание find функции

Перевод find с Matlab на английский

Рассмотрим find функцию из Matlab:

 idx = find(u > M/2);    % this is matlab-code
 

Вызов функции find(u) будет искать по всему массиву u что-либо строго большее, чем M/2 . find(u) затем вернет список всех индексов для объектов, превышающих M/2

Рассмотрим следующий пример find функции:

 u  = [98 00 00 87 49 50 51 00 85];
%      1  2  3  4  5  6  7  8  9 .....ARRAY INDICIES
idx = find(u > 50);
disp(idx)
% displays .... 1   4   7   9
 

find(u > 50) найдет индексы каждого элемента u , превышающие или равные 51

Рассмотрим код u(idx) = 22;
У нас есть следующие результаты:

  --------------------- ------ ----- ----- ------ ----- ----- ------ ----- ------ 
|   MATLAB INDICIES   |  1   |  2  |  3  |  4   |  5  |  6  |  7   |  8  |  9   |
 --------------------- ------ ----- ----- ------ ----- ----- ------ ----- ------ 
| print(u)            | 99   | 00  | 00  | 99   | 49  | 50  | 51   | 00  | 99   |
 --------------------- ------ ----- ----- ------ ----- ----- ------ ----- ------ 
| % u > 50?           | %yes | %no | %no | %yes | %no | %no | %yes | %no | %yes |
 --------------------- ------ ----- ----- ------ ----- ----- ------ ----- ------ 
| idx = find(u > 50); |      |     |     |      |     |     |      |     |      |
| u(idx) = 22;        |      |     |     |      |     |     |      |     |      |
 --------------------- ------ ----- ----- ------ ----- ----- ------ ----- ------ 
| print(u)            | 22   | 0   | 0   | 22   | 49  | 50  | 22   | 0   | 22   |
 --------------------- ------ ----- ----- ------ ----- ----- ------ ----- ------ 
 

Все, что внутри массива u больше или равно 51 , было заменено на 22

Перевод find с английского на Python

Предположим, что у вас есть массив u в Python.
Вы хотите заменить каждое целое число, большее или равное на 51 22
Вы можете сделать это на Python, используя numpy библиотеку:

 # This is Python (not matlab)
import numpy as np

u = [98 00 00 87 49 50 51 00 85];
u = np.array(u)
u[u > 50] = 22

# THIS IS PYTHON CODE (not matlab)   
 

Обратите внимание, что u[u > 50] = 22 это то же самое, что и следующее:

 # THIS IS PYTHON CODE (not matlab)   

indicies = type(u).__gt__(u, 50)
u.__setitem__(indicies, 22)  

# THIS IS PYTHON CODE (not matlab)    
 

Перевод find с Matlab на Python

Если вы переведете часть своего исходного кода из Matlab в Python, это будет выглядеть следующим образом:

ВВОД MATLAB:

 M = 7      
u = 0:(M-1);     
idx = find(u > M/2); 
u(idx) = u(idx) - M;
 

ВЫВОД PYTHON:

 # THIS IS PYTHON CODE (not matlab)   
 
import numpy as np
M = 7    
u = np.array(range(0, M))   
idx = u > M/2
u[idx] = u[idx] - M  

# THIS IS PYTHON CODE (not matlab)    
 

Перевод всего ВСЕГО кода Matlab на английский и математический языки

В начале поста я объяснил, что делают несколько отдельных фрагментов вашего кода Matlab.

Теперь давайте переведем весь скрипт Matlab на английский и математический языки.

*** ЧТО-ТО ПОХОЖЕЕ НА ВАШ ОРИГИНАЛЬНЫЙ / СТАРЫЙ MATLAB НИЖЕ ***

 function u = GenerateArray(M)
    u = 0:(M-1); 
    idx = find(u > M/2); 
    u(idx) = u(idx) - M; 
end

M = 7;
u = GenerateArray(M);

N = 9;
v = GenerateArray(N);
 

*** ПОВЕДЕНИЕ В ВИДЕ ТАБЛИЦЫ***

Я думаю, что код Matlab легче понять как таблицу, чем как код:

  -------------- --------------------------- 
| WHOLE NUMBER |           ARRAY           |
| `M`          |  `u`                      |
 -------------- --------------------------- 
| 4            | 0   1   2  -1             |
| 5            | 0   1   2  -2  -1         |
| 6            | 0   1   2   3  -2  -1     |
| 7            | 0   1   2   3  -3  -2  -1 |
 -------------- --------------------------- 
 

Для M > 7 :

  • левая половина массива: [0, 1 , 2, 3, [...], floor(M/2)]
  • правая половина массива: lang-none [(-1)*(x-0), (-1)*(x-1), (-1)*(x-2), [...], -3, -2, -1] где x равно floor((M-1)/2)

Перевод всего кода Matlab в Python

Следующий скрипт Python имеет тот же результат, что и скрипт Matlab:

 import numpy as np
import itertools as itts

def generate_data(array_size : int) -> type(np.array(range(0, 1))):
    """
     -------------- --------------------------- 
    | INPUT        |           OUTPUT          |
     -------------- --------------------------- 
    | 4            | 0   1   2  -1             |
    | 5            | 0   1   2  -2  -1         |
    | 6            | 0   1   2   3  -2  -1     |
    | 7            | 0   1   2   3  -3  -2  -1 |
     -------------- --------------------------- 

     * the left side of the array:
         starts at:
             zero

         ends at:
             floor(M/2)

         counts by:
              1

         looks like:
             [0, 1 , 2,  3,  [...],  floor(M/2)]

     * the right side of the array...
         starts at
            (-1) * floor((M-1)/2)

         ends at:
             -1

         counts by:
             -1

         looks like:
             [
                 (-1) * floor((M-1)/2),
                 (-1) * (floor((M-1)/2) - 1),
                 (-1) * (floor((M-1)/2) - 2),
                 [...],
                 -3,
                 -2,
                 -1
            ]

    """
    # clean_input = int(dirty_input)
    n = int(array_size)

    # make the first element of the left side of the array be zero.
    # left_side_first = 0
    lsf = 0

    # left_side_last = clean_input // 2
    lsl = n // 2

    # left_side_iterator =  range(left_side_first, 1   left_side_last)
    lsit = range(lsf, 1   lsl)
    # `list` stands for "left side iterator"

    right_side_first = (-1) * ((n - 1) // 2)
    right_side_last = -1
    right_side_iterator = range(right_side_first, 1   right_side_last)

    # merged_iterator = chain(left_side_iterator, right_side_iterator)
    merged_iterator = itts.chain(lsit, right_side_iterator)

    output = np.array(list(merged_iterator))

    # We convert the iterator to a `list` because the following
    # direct use of the iterator does not work:
    #
    #    output = np.array(merged_iterator)

    return output
 

Мы можем вызвать функцию Python следующим образом:

 arr = generate_data(14)
print(arr)
 

Вывод для ввода 14 показан ниже:

 [ 0  1  2  3  4  5  6  7 -6 -5 -4 -3 -2 -1]
 

Ответ №2:

Ваш код MATLAB

 u = 0:(M-1);
idx = find(u > M/2);
u(idx) = u(idx) - M;
 

может быть более эффективно реализовано путем исключения find :

 u = 0:(M-1);
idx = u > M/2;
u(idx) = u(idx) - M;
 

Эта форма тривиально переводится на Python с помощью NumPy:

 u = np.arange(0, M)
idx = u > M/2
u[idx] = u[idx] - M
 

Комментарии:

1. Предположим на мгновение, что M/2 это число 34 . Обратите внимание, что у > оператора есть специальное определение для массивов numpy . Когда u массив numpy u > 34 , массив поиска кода u для каждого отдельного элемента больше 34 . Мы заранее знаем, что u это массив [0, 1, 2, 3, 4, 5, ...] Элементы u уже отсортированы и пронумерованы последовательно. Искать по всему массиву u элементы больше, чем пустая трата времени 34 . Для повышения эффективности во время выполнения вы могли бы написать idx = range(1 M/2, M) или idx = range(1 len(u)/2, len(u))

2. @SamuelMuldoon: Я согласен. Вы также можете объединить два половинных массива и избежать вычитания. И еще проще просто позвонить fftfreq .