Более быстрое изменение размера изображения - PullRequest
1 голос
/ 11 апреля 2020

У меня есть стопка изображений (3D-массив), и я хочу улучшить их разрешение (повышающая дискретизация). Я запускаю следующий фрагмент кода, который я нахожу немного медленным ...

Есть ли способ улучшить скорость этого фрагмента кода? (без использования многопроцессорной обработки)

using BenchmarkTools
using Interpolations

function doInterpol(arr::Array{Int, 2}, h, w)
   A = interpolate(arr, BSpline(Linear()))
   return A[1:2/(h-1)/2:2, 1:2/(w-1)/2:2]
end

function applyResize!(arr3D_hd::Array, arr3D_ld::Array, t::Int, h::Int, w::Int)
    for i = 1:1:t
         @inbounds arr3D_hd[i, :, :] = doInterpol(arr3D_ld[i, :, :], h, w)
    end
end

t, h, w = 502, 65, 47
h_target, w_target = 518, 412

arr3D_ld = reshape(collect(1:t*h*w), (t, h, w))
arr3D_hd = Array{Float32}(undef, t, h_target, w_target)
applyResize!(arr3D_hd, arr3D_ld, t, h_target, w_target)

Когда я тестирую следующее:

@btime applyResize!(arr3D_hd, arr3D_ld, t, h_target, w_target)

Я получил:

2.334 s (68774 allocations: 858.01 MiB)

Я запускал его несколько раз, и результаты в [1,8 с - 2,8 с] интервал.

Ответы [ 2 ]

7 голосов
/ 11 апреля 2020

Юлия хранит массивы в главном порядке столбцов . Это означает, что срезы, такие как arr[i, : ,:], работают намного хуже, чем arr[:,:,i] (который непрерывен в памяти). Поэтому способ получить некоторую скорость - индексировать массивы, используя (h,w,t), а не (t, w, h).

Вторая проблема заключается в том, что при взятии фрагментов, подобных arr[i,:,:], копируются данные. Кажется, что это имеет незначительное влияние, но было бы неплохо привыкнуть к , используя представления массива вместо срезов , когда это возможно. Представление - это небольшой объект-обертка, который ведет себя так же, как и фрагмент большего массива, но не содержит копию данных: он напрямую обращается к данным родительского массива (см. Пример ниже, чтобы лучше понять, что представление есть).

Обратите внимание, что обе эти проблемы упоминаются в советах по производительности Julia ; может быть полезно прочитать оставшиеся советы на этой странице.

Соединив это, ваш пример можно переписать так:

function applyResize2!(arr3D_hd::Array, arr3D_ld::Array, h::Int, w::Int, t)
    @inbounds for i = 1:1:t
        A = interpolate(@view(arr3D_ld[:, :, i]), BSpline(Linear()))
        arr3D_hd[:, :, i] .= A(1:2/(h-1)/2:2, 1:2/(w-1)/2:2)
    end
end

, который используется с массивами, хранящимися немного по-другому от вашего случая:

       # Note the order of indices
julia> arr3D_ld = reshape(collect(1:t*h*w), (h, w, t));
julia> arr3D_hd = Array{Float32}(undef, h_target, w_target, t);

       # Don't forget to escape arguments with a $ when using btime
       # (not really an issue here, but could have been one)
julia> @btime applyResize2!($arr3D_hd, $arr3D_ld, h_target, w_target, t)
  506.449 ms (6024 allocations: 840.11 MiB)

Это примерно в 3,4 раза быстрее, чем ваш исходный код, что соответствует тестам на моей машине:

julia> arr3D_ld = reshape(collect(1:t*h*w), (t, h, w));
julia> arr3D_hd = Array{Float32}(undef, t, h_target, w_target);
julia> @btime applyResize!($arr3D_hd, $arr3D_ld, t, h_target, w_target)
  1.733 s (50200 allocations: 857.30 MiB)

NB: Ваш исходный код использует синтаксис, такой как A[x, y], для получения интерполированных значений. Похоже, это не рекомендуется в пользу A(x, y). Возможно, у меня не такая же версия Interpolations, как у вас, хотя ...



Пример, иллюстрирующий поведение представлений

julia> a = rand(3,3)
3×3 Array{Float64,2}:
 0.042097  0.767261  0.0433798
 0.791878  0.764044  0.605218
 0.332268  0.197196  0.722173

julia> v = @view(a[:,2]) # creates a view instead of a slice
3-element view(::Array{Float64,2}, :, 2) with eltype Float64:
 0.7672610491393876
 0.7640443797187411
 0.19719581867637093

julia> v[3] = 42  # equivalent to a[3,2] = 42
42
4 голосов
/ 12 апреля 2020

Использование

itp = interpolate(arr3D_ld, (NoInterp(), BSpline(Linear()), BSpline(Linear())));
A = itp(1:size(itp,1), 1:2/517:2, 1:2/411:2);

Это должно дать ~ 7-кратное улучшение производительности по сравнению с вашей версией.

Как отметил Франсуа Февот, также важно обращать внимание на предупреждения об устаревании, поскольку они замедляются Пуховое исполнение.

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