更快的图像大小调整
Faster image resizing
我有一堆图像(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.8s - 2.8s]间隔内。
Julia 在 column-major order 中存储数组。这意味着像 arr[i, : ,:]
这样的切片比 arr[:,:,i]
(在内存中是连续的)性能差得多。因此,获得一些速度的方法是使用 (h,w,t)
而不是 (t, w, h)
.
来索引你的数组
第二个问题是像arr[i,:,:]
这样的切片会复制数据。它在这里的影响似乎可以忽略不计,但如果可以,养成 using array views instead of slices 的习惯可能会很好。视图是一个小型包装器对象,其行为方式与较大数组的切片相同,但不保存数据副本:它直接访问父数组的数据(请参见下面的示例以更好地理解什么一个观点是)。
请注意,Julia performance tips 中提到了这两个问题;阅读本页中的其余建议可能会有用。
将这些放在一起,您的示例可以重写为:
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 倍的加速 w.r.t 你的原始代码,它在我的机器上像这样进行基准测试:
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)
注意: 您的原始代码使用 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
使用
itp = interpolate(arr3D_ld, (NoInterp(), BSpline(Linear()), BSpline(Linear())));
A = itp(1:size(itp,1), 1:2/517:2, 1:2/411:2);
与您的版本相比,它的性能应该提高了约 7 倍。
正如 François Févotte 指出的那样,注意弃用警告也很重要,因为它们会减慢执行速度。
我有一堆图像(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.8s - 2.8s]间隔内。
Julia 在 column-major order 中存储数组。这意味着像 arr[i, : ,:]
这样的切片比 arr[:,:,i]
(在内存中是连续的)性能差得多。因此,获得一些速度的方法是使用 (h,w,t)
而不是 (t, w, h)
.
第二个问题是像arr[i,:,:]
这样的切片会复制数据。它在这里的影响似乎可以忽略不计,但如果可以,养成 using array views instead of slices 的习惯可能会很好。视图是一个小型包装器对象,其行为方式与较大数组的切片相同,但不保存数据副本:它直接访问父数组的数据(请参见下面的示例以更好地理解什么一个观点是)。
请注意,Julia performance tips 中提到了这两个问题;阅读本页中的其余建议可能会有用。
将这些放在一起,您的示例可以重写为:
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 倍的加速 w.r.t 你的原始代码,它在我的机器上像这样进行基准测试:
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)
注意: 您的原始代码使用 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
使用
itp = interpolate(arr3D_ld, (NoInterp(), BSpline(Linear()), BSpline(Linear())));
A = itp(1:size(itp,1), 1:2/517:2, 1:2/411:2);
与您的版本相比,它的性能应该提高了约 7 倍。
正如 François Févotte 指出的那样,注意弃用警告也很重要,因为它们会减慢执行速度。